当前位置:网站首页>C语言-7月21日-指针的深入
C语言-7月21日-指针的深入
2022-08-11 05:30:00 【曾铎000811】
目录
const放在一级指针前面进行修饰(限制指针变量指向的数据):
const对一级指针的前面和后面均进行修饰(限制指针变量和指针变量指向的数据的值):
今天对指针进行了更加深入地学习,回顾一下今天所讲的知识点。
指针的强转问题:
#include<stdio.h>
int main()
{
int ar[] = {1,2,13,14};
int *p = ar;//p指针现在是整形类型大小为4字节的指针变量
long long *l = (long long*)p; //在这里我通过long long将p指针的大小强转位8字节
printf("%lld",*l);
return 0;
}在这段代码中,我定义了一个元素个数为4的数组,定义了一个整形类型的指针变量,在下面我又通过long long对整形类型的指针变量进行强转,强制将指针的大小从原来的4字节变为8字节。我的计算机是以小端存储的方式来进行存储的,即是最低地址存放最低字节,所以数据地址的填充如下图所示:

当我执行p++语句时,语句蕴含的意思应该是:p+sizeof(p),也就是p指针每向后偏移一个单元格,所对应的字节大小应该是4,那当我执行l++语句时(l+sizeof(l)),即应该是l指针每向后偏移一个单元格,所对应的字节大小应该是8字节。
在这里先提前说明,对于栈来说,开辟内存的方式是和数组不一样的:
栈的内存开辟:从高地址向低地址进行内存开辟
数组内存开辟:从低地址向高地址进行内存开辟
在这段代码中,定义的均为局部变量,所以操作系统会在栈区进行开辟,数组包含4个整形值,栈顶指针向上偏移16个字节,与栈底指针相差16字节,这也就是ar所使用的内存区间。此时ar所指向首元素地址,位于栈顶指针所在处。

栈的分派方式
const问题:
先来了解const:const是一个C语言的关键字,const限定一个变量不允许被改变,产生静态的作用。很多时候使用const可以提高程序的安全性和可靠性。
const和一级指针的结合问题:
如果在这里我定义一个使用const修饰的值,并试图对这个值进行修改。

编译器出现了报错,因为这时max已经被const所修饰,不能被改变.
const放在一级指针前面进行修饰(限制指针变量指向的数据):
在这里我将const放在指针前面修饰,但在执行第6行代码的时候现世报错,编译器提示变量必须是可修改的左值。

下面来分析报错的原因,在const语句中,const限制了指针变量指向的数据,也就是修饰了解引用的过程。在之前的文章:指针的学习 中提到,“*”属指针的操作符,作用是引用指针指向的变量值,引用该变量的地址,然后再通过*解开,此过程称之为解引用。那么现在使用const对*p进行了修饰,也就意味着这个解引用的过程不能再变,指针p和a产生关联,p存放了a的地址,此时*p就是a本身,所以通过解引用的方式试图对a值修改的语句是会报错的。
所以可以得出结论:const修饰p的指向内容,内容不能做修改。
const放在一级指针后面进行修饰(限制指针变量本身):
现在将const放在指针后面修饰,在执行第七行代码的时候报错,编译器依旧显示变量必须是可修改的左值。

分析报错的原因:在第5行代码中:const直接修饰了指针本身,也就是p存放a的地址的过程,此时p本身代表的就是a的地址,那么当我们试图更改p中所存放的地址时,自然就会报错了。
所以可以得出结论:当const修饰指针p本身时,指针p的值(也就是p所存放的地址)不能被修改。
const对一级指针的前面和后面均进行修饰(限制指针变量和指针变量指向的数据的值):
现在将const分别放在指针的前面和后面,执行第六行和第七行的时候编译器报错,报错原因:变量必须是可修改的左值。

分析报错的原因: 在第五行代码const对p变量本身和p变量所指向的内容均进行了修饰,也就是对解引用的过程和p存放a地址的过程均进行了修饰,所以p和*p都是不可被修改的,我们试图更改这两个值,编译器就会报错。
总结:区分const是限制指针变量本身还是指针变量所指向的值:如果const位于*号的左侧,则const用来限制指针变量所指向的值,如果const位于*号的右侧,则const用来限制指针变量本身。
const与二级指针结合的问题:
这里同样有三种结合方式:
const放在二级指针之前:
const int **q;在这种方式下,const修饰的是int类型的,所以解引用**q等价的值是不能被赋值的,但是可以*q可以被修改地址,在这里二级指针q本身也可以被修改赋值。
const放在二级指针之后:
int **const q;在这种方式i下,const修饰的是q二级指针本身,也就是const修饰int**类型,所以q指针是不能被修改赋值的,但是*q和**q均可以被修改赋值。
const放在二级指针之间:
int *const *q;在这种方式下,const修饰的是*q,也就是int *类型,所以*q是不能被赋值的,但是q指针本身和**q均可以被修改赋值。
作业:
作业一:利用指针实现strcpy(拷贝函数):
#include<stdio.h>
#include<iostream>
#include<assert.h>
void my_strcpy(int *ar,int *br,int begin_index,int m)//形参分别为:被复制的数组ar,新数组br,元素下标,数组元素个数
{
assert(ar != nullptr && br != nullptr && begin_index >= 0);
int *p = ar + begin_index;//p指针的初始位置是被复制数组ar的起始元素;
int *q = br + begin_index;//q指针的位置也是br数组的起始元素;
assert(p != nullptr && q != nullptr);
for(int i = 0;i < m;i++){
*q = *p;//将p指针对应的地址解引用后的元素赋值给q指针对应地址解引用的元素,循环;
q++;
p++;//每次赋值完之后,p指针和q指针的位置向后偏移一位,直到全部复制完成;
}
}
int main()
{
int m = 0;//定义整型值m用来存放被复制的数组中一共有几个元素
printf("Please input the number of array:\n");//输入元素的个数
scanf("%d",&m);
int ar[m];
printf("Please input these numbers.\n");//填充上面个数个元素
for(int i = 0;i < m;i++){
scanf("%d",&ar[i]);
}
int br[m];
my_strcpy(ar,br,0,m);//调用函数
printf("The array you copied br[] is:");
for(int i = 0;i < m;i++){
printf("%2d",br[i]);//输出
}
return 0;
}例如在这里我输入元素的个数为5,填充的元素分别为:1,2,3,4,5,运行结果为:

复制完成
作业二:利用指针实现strlen(计算字符串长度)函数:
#include<stdio.h>
#include<iostream>
#include<assert.h>
int my_strlen(char *ar)
{
assert(ar != nullptr);
char *p = ar;
int m = 0;//定义整型值m来对字符串的长度进行存储
while(*p != '\0'){//循环条件:p指针解引用后的元素不是字符串的末尾'\0'
m++;
p++;//每次循环记录字符串长度的m加1,p指针的位置向后迁移一位
}
return m;
}
int main()
{
char message[] ="";
printf("Please input the string.\n");
scanf("%s",message);
printf("The lenth of the string you put is %d",my_strlen(message));
return 0;
}如图我输入fuckyou!带上感叹号一共是8个字符,我们来看一下运行结果:

结果正确,字符串长度输出成功 !
作业三:里用指针实现strcat(链接字符串)函数:
#include<stdio.h>
#include<iostream>
#include<assert.h>
void my_strcat(char *message1,char *message2)
{
assert(message1 != nullptr && message2 != nullptr);
char *p = message1;
char *q = message2;
assert(p != nullptr && q !=nullptr);
while(*p){//此循环存在的原因:当p指针还停留在第一个字符串时,一直向后迁移,直到到达第一个字符串的末尾
p++;
}
while(*q != '\0'){//跳出第一个循环之后,当指针没有到达第二个字符串的末尾时
*p++ = *q++;//将第二个字符串的字符添加在第一个字符串的后面,循环。
}
}
int main()
{
char message1[100] = {0};
char message2[100] = {0};
printf("Please input your first string: \n");
scanf("%s",message1);
printf("Please input your second string: \n");
scanf("%s",message2);
my_strcat(message1,message2);
printf("The string you connected is %s\n",message1);
return 0;
}如图为我输入的第一个字符串和第二个字传分别为Hello和world:

如图,字符串连接成功!
字符串连接成功!
作业四:利用指针实现strcmp(字符串比较)函数:
#include<stdio.h>
#include<iostream>
#include<assert.h>
int my_strcmp(char *p1,char *p2)
{
assert(p1 != nullptr && p2 != nullptr);
int i = 0;
while(*(p1 + i) == *(p2 + i)){//循环条件为字符串1和字符串2的存在一个字符相同时
if(*(p1 + i++) == '\0'){
return (0);
}
else{
return(*(p1 + i) - *(p2 + i));//返回值字符串1减去字符串2的ASCII码
}
}
}
int main()
{
char str1[100];
char str2[100];
char *p1 = &str1[0];
char *p2 = &str2[0];
printf("Please input the strings you wanna compare:\n");
scanf("%s%s",str1,str2);
printf("The result of the strings you compared with is :%d ",my_strcmp(p1,p2));
return 0;
}如图我比较boy字符串和bad字符串,运行结果为:

结果正确
边栏推荐
猜你喜欢

虚拟机更改IP地址

JVM学习四:垃圾收集器与内存回收策略

精彩联动 | OpenMLDB Pulsar Connector原理和实操

连接数据库时出现WARN: Establishing SSL connection without server‘s identity verification is not recommended.

js learning advanced (event senior pink teacher teaching notes)

The official website of OpenMLDB is upgraded, and the mysterious contributor map will take you to advance quickly

127.0.0.1 已拒绝连接
![[Meetup]OpenMLDBxDolphinScheduler 链接特征工程与调度环节,打造端到端MLOps工作流](/img/d8/a367c26b51d9dbaf53bf4fe2a13917.png)
[Meetup]OpenMLDBxDolphinScheduler 链接特征工程与调度环节,打造端到端MLOps工作流

Tinker的自我介绍

Asis2016 books null off by one
随机推荐
星盟-pwn-babyheap
js学习进阶BOM部分(pink老师笔记)
Regular expression replacement for batch quick modification code
开发公众号授权遇到的redirect_uri参数错误
He Kaiming's new work ViTDET: target detection field, subverting the concept of layered backbone
Invalid revision: 3.18.1-g262b901-dirty
stack stack
gerrit configure SSH Key and account, email information
Day 72
【Meetup预告】OpenMLDB+OneFlow:链接特征工程到模型训练,加速机器学习模型开发
Visual studio2019 配置使用pthread
ARM assembly instruction ADR and LDR
场景驱动的特征计算方式OpenMLDB,高效实现“现算先用”
使用c语言实现井字棋(有源码,可以直接运行)
OpenMLDB + Jupyter Notebook:快速搭建机器学习应用
Open Source Machine Learning Database OpenMLDB Contributor Program Fully Launched
论文解读:GAN与检测网络多任务/SOD-MTGAN: Small Object Detection via Multi-Task Generative Adversarial Network
经纬度求距离
自己动手写RISC-V的C编译器-00环境配置
第四范式OpenMLDB优化创新论文被国际数据库顶会VLDB录用