C语言基础——指针(2)

一.    野指针
1.    野指针的成因:
野指针的成因有三种,我们对它们一一进行介绍:
(1)    指针未初始化:
倘若我们要创建一个指针变量p来存放a的地址,当出现这样的情况,指针未初始化:
int *p;
这个指针变量未初始化,默认为随机值。
(2)    指针越界访问,例如:

b8133820c282496aae34c80b48e80b5c.png

 我们可以看到,当指针指向的范围超过数组的范围(11)时,p就是野指针。
(3)    指针指向的空间释放:
我们通过一个例子来说明:f55bf1073c6440b1afb50b1bedcf931e.png

这个代码存在严重的逻辑错误,我们对它来进行分析:
首先,我们创建了一个指针变量p,并用它来接收test传来的函数地址。
其次,我们跳到test中,创建了一个变量n,并将其赋值为100,再返回这个值所在的地址。
最后,我们本来想做的是,通过解引用p找到test函数中存放的地址的内容,并将其打印。
🙅‍♂️但是,n是一个局部变量,在出test函数之后,创建的n的地址在内存中就会被销毁,这时候虽然指针变量p中还存放着n的地址,但是再解引用p来找内存中的地址,就会找不到了。



2.避免野指针
对于野指针的成因,我们分别给出了相应的解决办法:
(1)    注意指针初始化:
倘若我们明确一个指针指向哪里,就直接赋值地址,当不知道指针指向哪里时,可以给指针赋值为NULL,具体的格式是这样的:
Int *p=NULL;
(2)    仔细检查以避免指针越界。
(3)    避免返回局部变量的地址。




二.    assert断言
在使用这个函数的时候,我们需要加入头文件assert.h
以下是它的使用方法:
assert(p!=NULL)
当代码运行到这里时,如果变量p是NULL,程序就会报错,就像这样:

ea76ba6cdb154726b737339932fa0cf7.png



三.    指针的传址调用
假设我们需要写一个函数,来完成两个数的交换,正常来写是这样的:
void change(int a, int b)
{
    int c = 0;
    c = a;
    a = b;
    b = c;
}
int main()
{
    int a = 10;
    int b = 20;
    change(a, b);
    printf("a=%d b=%d", a, b);
    return 0;
}

eeb51dbd85f04e9b87bd04cedd085bdf.png

 从打印结果来看,两个数并没有进行交换,原因如下:
我们的函数change(a,b)里的a,b是实参,而void change(int a, int b)里的a,b为形参,当实参给形参传递内容的时候,形参会临时单独创建一份空间来接收实参,这也就意味着,在形参中的a,b两个变量发生了交换,但是在出函数的瞬间,a,b变量所在的临时空间与其地址会被销毁,这时候实参中的a,b并不会发生变化。



但是,当我们用指针来写的时候,就可以彻底完成两个变量的交换:
void change(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}
int main()
{
    int a = 10;
    int b = 20;
    change(&a, &b);
    printf("a=%d b=%d", a, b);
    return 0;
}

我们通过change函数,把a和b的地址传给void change(int* a, int* b),而在void change(int* a, int* b)中,我们用a和b两个指针变量来接收其传来的地址,而这个时候,给指针变量a和指针变量b解引用,它们所找到的地址的内容就是实参a,b的地址所对应的内容。我们通过函数远程操控地址,从而实现了两个变量的交换。这种将变量的地址传递给函数的方法,叫做传址调用。



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值