C语言传参分为值传传递和地址传递。C语言指针传参时,可以通过指针引用方式改变指针指向的值。改变变量,可以使用指针应用方式,改变地址,使用指针的指针引用方式。

C语言值传递:

形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参)

 #include <stdio.h>void swap(int x, int y);main(){  int a = 5, b = 9;swap(a, b);printf("a=%d\nb=%d\n", a, b);return 0;
}
void swap(int x, int y)
{int t;t = x;x = y;y = t;
}

上述代码运行后a、b的值并未改变

C语言地址传递:

形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

 #include <stdio.h>void swap(int *p1, int *p2);main(){  int a = 5, b = 9;int* pointer_1, *pointer_2;pointer_1 = &a;pointer_2 = &b;swap(pointer_1, pointer_2);printf("a=%d\nb=%d\n", a, b);return 0;
}
void swap(int *p1, int *p2)
{int t;t = *p1;*p1 = *p2;*p2 = t;
}

程序说明:

程序运行时候,先输入a和b的值,然后将a和b的地址赋给指针变量pointer_1和pointer_2,使pointer_1指向a, pointer_2指向b,如图

在swap函数调用时候,将实参的值传给形参,采用的依然是值传递,虚实结合后形参p1的值为&a,p2的值为&b,这时候p1和pointer_1都指向变量a, p2和pointer_2都指向变量b。

接着执行swap函数的函数体,使*p1和*p2的值互换,也就是使a和b的值互换,互换后的情况如下

函数调用结束后,形参p1和p2不复存在(已释放),情况如下

上述代码执行后a和b值交换,a=9、b=5

易错点补充:

 #include <stdio.h>void swap(int *x, int *y);main(){  int a = 5, b = 9;int *pp = &a;int *kk = &b;swap(pp, kk);printf("a=%d\nb=%d\n", *pp, *kk);return 0;
}
void swap(int *x, int *y)
{int *t;t = x;x = y;y = t;
}

请读者想一下,上述代码执行后a和b的值是否交换,为什么?

上述代码看起来像交换了指针pp和kk的指向,实际上并没有

代码的运行结果a=5、b=9,运行结果是a和b的值并没有改变,因为这时使用的实参pp,kk是值传递,传递的是指针的值,以指针pp来说,指针的值是变量a的地址,

指针的值传入后用形参int *x和int *y接收,这里x和pp虽然都指向变量a的地址,但指针变量x和pp自己的地址(地址的地址值)是不相同(意思是x拷贝了一份pp的值),意味着你能改变变量a的值,但是不能改变pp的值(这里与值传递相似)

为了更加直观,清晰的看出值的交换,这里添加一些代码来显示内存和变量的值

 #include <stdio.h>void swap(int *x, int *y);main(){int a = 10, b = 20;int *pp = &a;int *kk = &b;printf("a的地址%p----b的地址%p\n\n", &a, &b);printf("pp的值%p----kk的值%p\n", pp, kk);printf("pp的地址%p----kk的地址%p\n\n", &pp, &kk);swap(pp, kk);printf("a = %d\nb = %d", *pp, *kk);return 0;
}
void swap(int *x, int *y)
{int *t;printf("x的值%p----y的值%p\n", x, y);printf("x的地址%p----y的地址%p\n", &x, &y);t = x;x = y;y = t;
}

结构体指针地址传参

上面的例子只是传递一个int指针类型做参数,看起来比较简单,在实际应用中,结构体指针做函数参数的比较常见,通过结构体指针的引用,可修改结构体成员的数据内容

#include <stdio.h>
#include <string.h>

struct animal
{  
    char name[30];    
    int num;
};

//使用结构体作为参数 浪费内存 需要建立结构体
void change_struct(struct animal cat)
{
    cat.num = 17;
}

//函数内部改变需要地址 所以需要指针保存
void change_point(struct animal *cat)
{
    cat->num   = 13;
}

void main
{
    struct animal cat = {0};
    struct animal *pcat = &cat;
    cat.num = 20;

change_struct(cat);
    printf("%d",cat.num);  //输出20

change_point(pcat);
    printf("%d",cat.num);  //输出13

cat.num = 28;
    change_point(&cat);    //输出13
    printf("%d",cat.num);
}

通过上面的例子可以看到,传递结构体指针(或者取它的地址),可以通过结构体指针的引用修改结构体成员的值。直接传递结构体,不能修改结构体成员的值。

其次,如果传递的是结构体的话,因为C语言的参数传递值调用方式是要求把参数的一份拷贝传递给参数,上面的name这个数组的长度是30,那么这个结构体将占用34个字节的空间,要想把它作为参数传递的,我们必须把34个字节都复制到堆栈中,以后再丢弃,所以传递指针比直接传递结构体变量的效率要高非常多。

一般,将结构体传递给函数的方式有如下3种:

  1.用结构体的单个成员作为函数参数,向函数传递结构体的单个成员(属于传值调用,不会影响相应的实参结构体的值)

  2.用结构体变量做函数参数,向函数传递结构体完整结构(属于传值调用,不会影响相应的实参结构体的值)

  3.用结构体指针或结构体数组作函数参数属于按引用调用,会影响相应的实参结构体的值,向函数传递结构体地址,因为仅复制结构体首地址一个值给被调函数,相对于第二种方式,这种传递效率更高

总结:

1. 指针变量只能存表示地址类型的数据

2. 指针得到谁的地址,就指向谁

3. 几个指针变量指向同一个地址,通过指针引用改变指向的变量值,其他指针指向的变量值同时也会被改变。地址一样,指向的变量值也一样。

C语言指针值传递和地址传递相关推荐

  1. C语言中函数参数传递的方式:值传递,地址传递

    ** C语言中函数参数传递的方式:值传递,地址传递 ** 值传递:将实参的值复制至形参的相应存储单元中,实参与形参占用不同存储单元,单向传递 地址传递:使用数组名或者指针作为函数参数,传递的是该数组的 ...

  2. 【❗划重点!C语言函数参数传递只有两种方式(值传递,地址传递),不支持“引用传递”!❗】

    引子 上篇文章<C语言函数传参の结构体数组篇>提到了C语言的函数参数传递方式,百度了一一一大圈,有说两种的,也有说三种的,简直把我搞晕了,"值传递和地址传递"是毫无疑问 ...

  3. C语言函数传递方式-值传递和地址传递

    C语言函数传递方式 值传递 定义 所谓的值传递,顾名思义就是使用变量.常量.数组等作为函数的参数.实际是将实参的值复制到形参相应的存储单元中,即形参和实参分别占用不同的存储单元. 特点 值传递的特点是 ...

  4. c语言中的值传递和地址传递参数,c语言值传递,地址传递,引用传递

     c语言值传递,地址传递,引用传递 总结:对于函数来说,值传递就是一个人来了,给你一些数 据,你对数据处理.地址传递就是你通过地址找到一个人,然后直接对这个人处理.而引用传递就是你要直接对一个人进行处 ...

  5. 细说值传递、引用传递和地址传递

    细说值传递.引用传递和地址传递 1 实参和形参 形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数. 实际参数:在调用有参函数时,主调函数和被调函数之间有数据传递关 ...

  6. java 引用传递_详解java的值传递、地址传递、引用传递

    详解java的值传递.地址传递.引用传递 一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前 ...

  7. java能传地址吗,详解java的值传递、地址传递、引用传递

    一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前的理解,java中基本数据类型是值传递,对 ...

  8. 对几种传递的理解:值传递,地址传递,引用传递

    对几种传递的理解:值传递,地址传递,引用传递 因为会用到形参和实参的概念,区别一下,形参 即在定义函数时 int add(int a , int b)中a,b,即为形参.而当调用时int(3,4)中3 ...

  9. c/c++ 实参、形参、值传递、地址传递的区别与关系 ---- 授人以鱼不如授人以渔

    函数的传递过程详解: 值传递:将原始对象的值传递给目标.程序会为目标开辟一个完全相同的内存空间,并将原始对象copy到目标中,之后对目标内存进行修改.所以目标的修改并不会影响原始对象,因为原始对象和目 ...

最新文章

  1. Ubuntu中的超级兔子:Tweak安装教程
  2. Python Tensorflow神经网络实现股票预测
  3. SpringBoot 根据传参返回不同的内容
  4. 【深度学习】我用 PyTorch 复现了 LeNet-5 神经网络(CIFAR10 数据集篇)!
  5. Linux NTP服务配置 for Oracle RAC
  6. ubuntu server 14.10 安装 nodejs
  7. QT5开发及实例学习之七布局管理
  8. 十荟团创始人发表内部信,公布下半场业务的全面升级规划
  9. iOS重写和成员变量访问权限
  10. PowerDesigner基础学习
  11. 自然语言处理之TF-IDF
  12. java socket 浏览器_java实现websocket(图文)
  13. OBJECT_ID(Transact-Sql)
  14. vivo X9的usb调试模式在哪里,开启vivo X9usb调试模式的方法
  15. 【深度学习-吴恩达】L1-3 浅层神经网络 作业
  16. no-cache和no-store的区别
  17. 5种高大上的yml文件读取方式,你知道吗?
  18. ArcGIS10.6表统计数据
  19. Ubuntu下U盘只读文件系统,图标上锁,文件无法写入
  20. 004永磁同步电机的工作原理:大白话详细讲解从最简单的直流有刷电机到永磁同步电机是如何转动起来的

热门文章

  1. MapRecuce 词频统计案例
  2. 关于eclispe svn突然不能使用的解决方案SVN资源库报错:Could not create the view: org.tigris.subversion.subclipse.ui.repos
  3. PS中建立选区有哪些方法
  4. ble协议栈从零开始八(security manager 最细致分析上)
  5. 数理统计笔记10:回归分析
  6. 一次典型的练习--Leo与跆拳道(2)
  7. 亚马逊回应乐视收购:否认传闻,对中国市场有长期规划
  8. 简单设置电脑定时关机或者重启
  9. SpringBoot整合邮件服务器
  10. 他们的心声,让无数人温暖一生