本文主要介绍C语言参数的三种传递方式,以及个人遇到的一些问题及解决方法
C语言中,传递参数的主要方式有三种:
1.值传递方式
2.地址传递方式
3.引用传递
一、值传递
值传递,指的是将实参的值复制并赋值给形参。这里需要注意的地方是,实参和形参的存储单元并不相同,实参的存储单元由实参的定义方式决定,而形参的存储单元则是栈,对应的存储单元在函数调用时创建,函数退出时释放。也就是说形参的改变,并不会对实参有任何影响。
#include <stdio.h>
void value(int a, int b); //函数实现功能 将输入的值互换
int main(int argc, const char *argv[])
{
int c = 1;
int d = 2;
value(c, d);
printf("c = %d d = %d \n", c, d);
return 0;
}
void value(int a, int b)
{
int t = 0;
printf("a = %d b = %d \n", a, b);
t = a;
a = b;
b = t;
printf("a = %d b = %d \n", a, b);
}
程序执行结果为:
a = 1 b = 2 //形参得到正确的实参值
a = 2 b = 1 //形参互换成功
c = 1 d = 2 //实参并未改变
由此可见,对于参数使用值传递的方式时,形参怎么变化都不会改变实参的值。
二、地址传递
地址传递方式,指的是将地址变量作为实参传递到函数,常用形式就是实参和形参都为指针变量(指针就是地址)。关于这个具体名称为指针传递方式还是地址传递方式我找了不少资料,没有找到具体那个才是正确的说法,但是使用方式是相同的,这里暂时就说是地址传递,如果有知道这么问题答案的,希望能在评论区点评一下。
#include <stdio.h>
void value(int *a, int *b);
int main(int argc, const char *argv[])
{
int c = 1;
int d = 2;
int *p = &c;
int *q = &d;
value(p, q);
printf("p = %d q = %d \n", *p, *q);
return 0;
}
void value(int *a, int *b)
{
int *t = NULL;
printf("a = %d b = %d \n", *a, *b);
t = a;
a = b;
b = t;
printf("a = %d b = %d \n", *a, *b);
}
程序执行结果是:
a = 1 b = 2
a = 2 b = 1
p = 1 q = 2
由上面的结果,我们发现,地址传递方式的时候,形参的改变并不会改变实参的。然而结论是这样的吗?我们看看下面这个例子:
#include <stdio.h>
void value(int *a, int *b);
int main(int argc, const char *argv[])
{
int c = 1;
int d = 2;
int *p = &c;
int *q = &d;
value(p, q);
printf("p = %d q = %d \n", *p, *q);
return 0;
}
void value(int *a, int *b)
{
int t = 0;
printf("a = %d b = %d \n", *a, *b);
t = *a;
*a = *b;
*b = t;
printf("a = %d b = %d \n", *a, *b);
}
程序执行结果如下:
a = 1 b = 2
a = 2 b = 1
p = 2 q = 1
这里,我们发现两段程序仅在调用函数里面对形参的处理方式不同就导致了不一样的结果。这里简要分析一下,地址传递方式,本质上也是值传递,只是传递的参数是一个地址。所以就有上一段程序的结果,形参改变但是实参不改变的结果。然而不通点在于,地址传递方式会传递进来的是一个地址,我们可以通过地址更改该地址上存储的数据。所以得到了第二种结果,形参的改变导致了实参的改变。
相对于值传递方式,地址传递方式增加了一道形参改变实参的桥梁,利用的就是指针上的取值操作,直接对已知地址上保存的数据进行修改。
三、引用传递
引用传递方式传递过程中,被调函数的形参也作为局部变量在栈中开辟了内存空间,但此时存放的是由主调函数放进来的实参变量的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此特点,被调函数对形参的任何操作都会影响主调函数中的实参变量。
下面举例的程序是在C++上的使用,在C里面并没有,在C中的引用传递,请参考地址传递的第二段程序。
#include <stdio.h>
void value(int &a, int &b);
int main(int argc, const char *argv[])
{
int c = 1;
int d = 2;
value(c, d);
printf("c = %d d = %d \n", c, d);
return 0;
}
void value(int &a, int &b)
{
int t = 0;
printf("a = %d b = %d \n", a, b);
t = a;
a = b;
a = t;
printf("a = %d b = %d \n", a, b);
}
程序执行结果如下:
a = 1 b = 2
a = 2 b = 1
c = 2 d= 1
简单的概述引用传递,int &b = i;这里的b就是一个引用,他是变量i的引用。引用就是指针,两者没区别。我们可以将引用想像成一个不需要“*”就可以访问变量的指针。
还需要再次提醒,这种引用程序只能在支持C++的编译器上使用,该种写法是C++内的引用,所以在C编译器上编译会报错。
四、个别自身遇到问题及问题分析
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char test1(char *p, char *q);
char test2(char **p, char **q);
int main(int argc, const char *argv[])
{
char s1[200] = "test 1";
char s2[200] = "test 2";
char *p = s1;
char *q = s2;
test1(p, q);
printf("p = %s q = %s\n", p, q);
test2(&p, &q);
printf("p = %s q = %s\n", p, q);
return 0;
}
char test1(char *p, char *q)
{
char *t;
t = p;
p = q;
q = t;
return ;
}
char test2(char **p, char **q)
{
char *t;
t = *p;
*p = *q;
*q = t;
return ;
}
程序执行结果是:
p = test 1 q = test 2 //指针变量没交换
p = test 2 q = test 1 //指针变量交换了
该段程序想说明的问题是,指针变量作为实参的时候,怎么能利用形参将其改变。具体的做法是将形参定义为比形参更高一级的指针变量。对其再进行取值操作即可,与地址传递里的取值操作相同。
仓促成文,不当之处,尚祈方家和读者批评指正。联系邮箱[email protected]