传值调用和传址调用
在 C 语言中,传值调用和传址调用都是用来传递参数给函数的方法,它们的区别在于传递参数的方式不同。
传值调用是指将参数的值复制一份传递给函数。在函数内部,对参数值的任何修改都不会影响原始参数值,因为函数只是在其本地副本中修改该值。这种方法的优点是简单、易于实现和理解;缺点是当函数需要修改原始参数值时,必须将该值显示地返回。
传址调用是指将参数的地址传递给函数。在函数内部,可以通过该地址访问原始参数值,并对其进行修改。这个方法的优点是可以直接修改原始参数值,无需将其返回;缺点是这种方法需要更多的内存和一些额外的代码来解引用参数地址。
需要注意的是,传值调用和传址调用只是参数传递的两种方式,并不涉及到数据类型或变量类型的问题。也就是说,可以使用传值调用或传址调用来传递任何类型的参数,包括基本类型和复杂类型。
传值调用:
#include <stdio.h>
void foo(int x) {
x = x * 2;
printf("在函数中,x 的值为 %d\n", x);
}
int main() {
int num = 5;
printf("在调用函数之前,num 的值为 %d\n", num);
foo(num);
printf("在调用函数之后,num 的值为 %d\n", num);
return 0;
}
输出:
在调用函数之前,num 的值为 5
在函数中,x 的值为 10
在调用函数之后,num 的值为 5
可以看到,在函数 foo() 中修改参数 x 的值不会影响 main() 函数中的变量 num。函数的形参和实参分别占用不同的内存空间,对形参的修改不会影响实参 ,对传值调用来说
传址调用:
#include <stdio.h>
void foo(int* x) {
*x = (*x) * 2;
printf("在函数中,*x 的值为 %d\n", *x);
}
int main() {
int num = 5;
printf("在调用函数之前,num 的值为 %d\n", num);
foo(&num);
printf("在调用函数之后,num 的值为 %d\n", num);
return 0;
}
输出:
在调用函数之前,num 的值为 5
在函数中,*x 的值为 10
在调用函数之后,num 的值为 10
可以看到,在函数 foo() 中通过指针访问参数 x 的值并修改后,会影响 main() 函数中的变量 num 的值。在函数内部想改变参数的值,就是用传址调用,如果只想传递参数,则使用传值调用。
总结
传值调用和传址调用的详细解释如下:
1. 传值调用
在函数调用时,需要将实参的值复制一份传递给形参(局部变量),函数使用的是形参的值,而不是实参的值。形参与实参是两份独立的内存空间,互不影响。
当在函数内部对形参的值进行修改时,将不会影响实参的值。因为形参只是实参的一份拷贝,是在函数内部新定义的变量。而函数结束后,形参所占的内存空间就会被回收。下面是一个传值调用的示例,其中 x 是形参,num 是实参:
#include <stdio.h>
void foo(int x) {
x = x + 1;
printf("形参 x 的值为 %d\n", x);
}
int main() {
int num = 5;
printf("实参 num 的值为 %d\n", num);
foo(num);
printf("调用 foo() 函数后,实参 num 的值依旧为 %d\n", num);
return 0;
}
输出:
实参 num 的值为 5
形参 x 的值为 6
调用 foo() 函数后,实参 num 的值依旧为 5
可以看到,foo() 函数对 x 的修改并不会影响实参 num 的值。
2. 传址调用
在函数调用时,需要将实参的地址作为形参传递给函数,这种方式又称为传指针或者传引用。函数在使用形参时,通过指针访问实参。因为形参是实参的地址所指向的值,所以对形参值的修改将会影响实参的值。
下面是一个传址调用的示例,其中 px 是形参,pnum 是实参:
#include <stdio.h>
void foo(int* px) {
(*px)++;
printf("形参 *px 的值为 %d\n", *px); // 输出形参的值
}
int main() {
int num = 5;
int* pnum = #
printf("实参 num 的值为 %d\n", num);
foo(pnum);
printf("调用 foo() 函数后,实参 num 的值变为 %d\n", num);
return 0;
}
输出:
实参 num 的值为 5
形参 *px 的值为 6
调用 foo() 函数后,实参 num 的值变为 6
可以看到,foo() 函数对 px 所指向的地址所储存的值进行了修改,从而也改变了指针所指向的实参 num 的值。
总的来说,传值调用与传址调用的区别可以归纳为:
传值调用 | 传址调用 | |
参数是否变为原变量 | no | yes |
修改形参是否会影响实参 | no | yes |