深入理解你最爱的指针
- const修饰指针
- 野指针
- assert断言
- 指针的使用(传值调用和传址调用)
——const修饰指针
我有话说:在前面我们已经对const关键字有了一个初步的了解,接下来我们就它及进行挖掘,方便我们进行更加全面的了解。
int main()
{
const int n = 10;//这里的n被称为常变量,本质上是变量,但具有常量的属性(无法被修改)
n = 100;//n已经被const修饰,无法对其值进行修改,运行的话系统会报错
printf("%d",n);
return 0;
}
这里如果运行起来,程序是会报错的,这就暗示了**const具有“锁定”的功能。**把n锁定在了10。
——接下来,我们看看const对指针变量有什么影响
`c
int main()
{
int n = 0;
int m = 1;
int * const p = &n;//可以看到,const放在了*右边,相当于锁定了p这个指针变量
p =&m;//!!!!!!!!!!!!!!!!!上面的代码中const锁定了p,p里面只能存放n变量的地址,无法修改p让其存放的m地址。***!!这行代码会报错!!***
*p = 10;//可以正常运行
int main()
{
int n = 10;
int m = 5
int const * p = &n;//const放在了*的左边,相当于锁定了*p,意味者无法通过*p改变p的大小
p = &m;//可以正常运行
*p = 100//!!!!!!!!!!!!!!!!!
}
————综上,const放在的左边和右边有着不一样的作用效果
(1)const放在✳的左边,锁定了p,p指向的那个变量无法被解引用修改
(2)const放在✳的右边,锁定了p,p只能指向n,不能指向其他变量
——野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)这种指针会对内存空间造成损害,所以要避免出现野指针。下面是避免出现野指针的一些措施。
- 指针初始化
int main()
{
int a = 10;
int * p = &a;
}
tip.如果不知道指针变量里面存的是谁的地址(上述代码里面指针变量p存的是a的地址),可用NULL 代替,NULL(指向0的地址),即,如下图
int main()
{
int a = 0;
int * p = NULL;
}
指针变量不再使用时,及时将其指向NULL,避免返回局部变量的地址
——assert断言
assert.h 头文件定义了宏assert() , assert关键字是来判断语句是否为真,如果为真那就继续进行操作,如果为假,系统就会报错,并且还会提供错误信息的位置!!就类似于宫殿的大门,只有相关人员才能通过,语法为assert(),条件放在括号里边
eg.我们就这个assert断言举一个简单的例子(使用assert需包含头文件assert.h)
#include<assert.h>
int main()
{
int * p = NULL;
assert(p!=NULL)
printf("%d",5);//!!!!!!!!!!系统不会打印5,因为打印5的前提条件是p!=NULL(p不等于NULL),但是p就是NULL
}
相当于assert后面的代码都不会运行,assert像一道墙一样卡住了
——传值调用和传址调用
传值调用
咱们先来讲一讲传值调用,这是浅层含义的函数传参,先来看一段代码
void Swap(int x, int y)//x接收a的值,具体为3;y接收b的值,具体为4
{
int z = 0;//定义z变量,实现两个数据的交换
z = x;
y = z;
x = y;//对x和y的值进行了交换,得到的结果为x = 4,y = 3
}
int main()
{
int a = 3;
int b = 4;
printf("交换前a=%d b=%d",a,b);
Swap(a,b);
printf("交换后a=%d b=%d",a,b);
}
这段代码最后的的结果为
交换前a=3,b=4 交换后a=3,b=4
————>不难看出,Swap函数对于a和b的改变没有起到作用,这是因为Swap只是把a和b的值传了过去,那边开辟了两个新的空间内存来给变量(x和y)使用,只是单纯的把a和b的值传给了相应的x和y。x和y都是单独的空间,改变他们两个的值不会对a和b有影响,这点慢慢理解。也就是说,x和y除了Swap函数的传值操作后,没有与a和b建立联系
|
| a | 0x0012ff40 |
|---|---|
| b | 0x0012ff41 |
| x | 0x0012aa40 |
| y | 0x0012aa41 |
可以看出x和y是单独的空间,只是Swap函数把3和4传给了x和y而已。无法通过Swap函数对a和b进行交换。
传址调用
同样的,上代码
void Swap(int * p1,int * p2)//p1用来存放a的地址,p2用来存放b的地址
{
int z = 0;
z = *p1;//((*p1)解引用得到a的值,也就是把a的值放到z里面去,当前z为520)
*p1 = *p2;//刚交换完的*p1里面没有值,将b的值传给*p1,***p1得到1314**
*p2 = z;//自此完成了交换
}
int main()
{
int a = 520;
int b = 1314;
printf("交换前a=%d b=%d",a,b);
Swap(&a,&b);//将a和b的地址传过去,后面对它们的指针(地址)进行解引用就可以交换二者的值
printf("交换后a=%d b=%d",a,b);
}
上述代码把a和b的地址传了过去,直接对*p1,p2进行修改,就可以修改主函数里面的a和b了
综上所述:
(1)如果只是想把主函数的值传给别的变量,那么使用的是传值调用
(2)如果想通过函数修改主函数的值,就得把主函数变量的地址传过去,那么使用的是传址调用
954

被折叠的 条评论
为什么被折叠?



