为什么要用指针,什么时候该用指针,什么时候该用指针的指针

很多内容可以参考同专栏的其他文章,像指针&结构体、字符串,函数指针,数组指针,指针基础概念与内存分配等。

几个必须了解的前提概念:
(1)指针是一个保存地址的变量。这个地址是指针所指向的变量的地址而不是指针本身的地址。
(2)C语言的参数传递方式有值传递和地址传递。
(3)C语言中参数传递的本质都是值传递。
(4)形参在调用返回时就会被销毁,它只是拷贝了一份实参,形参的改变对实参没有影响。
(*5)一个实参指针变量传入函数的形参指针变量时,指针指向的内容是可以改变的,但是指针的值和地址本身是不会改变的。
(*6)C语言的变量一但声明赋值后,就会分配一块内存,这块内存的地址是不会改变的。
(7)数组作为形参传递时,形参实参是同一块内存

一、什么时候该用指针

(1)动态数组

指针做动态数组声明用:int *arr;:指针名就是数组名,直接解引*arr就是数组的首项值。

(2)一些功能性声明

函数指针或数组指针。

(3)传参改变变量

当要调用函数改变一个变量的值时,就要用到指针。因为形参不改变实参。
例如:

void swapValue(int num1,int num2)
{
    int temp;
    temp = num1;
    num1 = num2;
    num2 = temp;
    printf("-------swapValue-------\n\r");
    printf("num1=%d\n\r",num1);
    printf("num2=%d\n\r",num2);
}

void swapPoint(int *p1,int *p2)
{
    int temp;
    temp = *p1;     //tmp=a
    *p1 = *p2;      //a=b
    *p2 = temp;     //b=tmp
    printf("-------swapPoint-------\n\r");
    printf("*p1=%d\n\r",*p1);
    printf("*p2=%d\n\r",*p2);
}

void swapPoint2(int *p1,int *p2)
{
    int *temp;
    temp = p1;     //tmp=&a
    p1 = p2;       //&a=&b
    p2 = temp;     //&b=tmp
    printf("-------swapPoint2-------\n\r");
    printf("*p1=%d\n\r",*p1);
    printf("*p2=%d\n\r",*p2);
}

int main()
{
    int a = 5;
    int b = 10;
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    
    swapValue(a,b);
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    
    swapPoint(&a,&b);
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    
    swapPoint2(&a,&b);
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    return 0;
}

可自己先演算一下结果再与下方结果对比。

编译结果:
在这里插入图片描述
逐个分析:
swapValue:传递的是值,形参再怎么变化,函数返回时就会从栈中销毁,因此只会改变形参num1,2的值,不会改变a,b的值,地址就更不用说了。

swapPoint:传递的是指针,这下形参是指针,因此指针便不会改变,但是指针所指向的内容可以改变,因此a,b的值就发生了互换,但是地址不变化。

swapPoint2:传递的是指针,同swapPoint一样,但是内部是直接对形参的指针变量进行交换操作,即互换地址,因此解引形参时相当于将前面调换的值调换回来了。但是函数返回时一切销毁,所以a,b的值和地址都不会变化,而且C语言定义的变量地址是无法改变的。

二、什么时候该用指针的指针

(1)通过传递二级指针改变量

通过传入指向一块内存的地址值的指针(即指针的指针),间接修改指向的值。

例如:

void swap2Pointer(int** p1,int** p2)
{
    int temp;
    printf("-------into swapAddr-------\n\r");
    printf("**p1=%d\n\r",**p1);     //p1=&x,*p1=&a,**p1=a
    printf("**p2=%d\n\r",**p2);
    temp = **p1;
    **p1 = **p2;
    **p2 = temp;
    printf("-------after swapAddr-------\n\r");
    printf("**p1=%d\n\r",**p1);
    printf("**p2=%d\n\r",**p2);
}
int main()
{
    int a = 5;
    int b = 10;
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    int *x = &a;
    int *y = &b;
    swap2Pointer(&x,&y); 
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
}

编译结果:
在这里插入图片描述
拓展:上面说过传入形参的实参是不会改变的(因为函数返回时就销毁),但是指向的内存是可以改变的(现在指向的是a的地址的,那么将上述swap2Pointer修改为如下swapAddr是不是就能改变*p1(&a)*p2(&b)了,从而调换x和y指向的地址值,答案是可以的。
如下:

void swapAddr(int** p1,int** p2)
{
    int temp;
    printf("-------into swapAddr-------\n\r");
    printf("*p1=%x\n\r",*p1);     //p1=&x,*p1=&a,**p1=a
    printf("*p2=%x\n\r",*p2);
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
    printf("-------after swapAddr-------\n\r");
    printf("*p1=%x\n\r",*p1);
    printf("*p2=%x\n\r",*p2);
}
int main()
{
    int a = 5;
    int b = 10;
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    int *x = &a;
    int *y = &b;
    printf("*x=%d\n",*x);
    printf("*y=%d\n",*y);
    swapAddr(&x,&y); 
    printf("a=%d\n",a);
    printf("b=%d\n",b);
    printf("aAdd=%p\n",&a);
    printf("bAdd=%p\n",&b);
    printf("*x=%d\n",*x);
    printf("*y=%d\n",*y);
}

编译如下:
在这里插入图片描述

(2)无法靠传一级指针改变指针时

像如下代码编译时会奔溃,因为num传入p时,num是无法被改变的,因此num没有开辟出空间无法赋值。

void pMalloc(int *p,int size)
{
    p = (int *)malloc(size*sizeof(int));
}

int main()
{
    int *num = NULL;        //如果是全局和static会自动初始化为NULL
    pMalloc(num,5);
    if(num!=NULL)
    {
        *num = 200;
        printf("num=%d",*num);
    }
    else
    {
        printf("Assignment Fail");
    }
    return 0;
}

编译结果:
在这里插入图片描述


而如果将传入的参数变成实参变量的地址的话:

void pMalloc(int **p,int size)
{
    *p = (int *)malloc(size*sizeof(int));
}

int main()
{
    int *num = NULL;        //如果是全局和static会自动初始化为NULL
    pMalloc(&num,5);        //p=#*p=num;**p=*num
    if(num!=NULL)
    {
        *num = 200;
        printf("num=%d",*num);
    }
    else
    {
        printf("Assignment Fail");
    }
    return 0;
}

编译结果:(成功)
在这里插入图片描述
记住前面序中的几点概念,那么玩转指针就很简单了。而多级指针如果很乱的话,就像上面程序中p=#*p=num;**p=*num这样抽丝剥茧即可。

(3)更新ing…

若想通过函数修改变量值,可以通过传递指针以修改目标地址上存储的,而变量的地址是不能改变的。不管是几级指针,最终改变的一定是对应地址上的内存,即以"值"形式存在的数据。

  • 14
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Diode丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值