在传值调用(call by value)中,函数参数的值被复制并传递给函数的形式参数。在函数中对形式参数的修改不会影响到原始的实际参数。
在传址调用(call by reference)中,函数参数的地址被传递给函数的形式参数,使得函数可以直接访问和修改原始实际参数的值。
这两种方式在实际的代码编写中,运用广泛,但是这两种情况在运行时间上,却有着很大的差别,下面我们就来深究其原因
1、传值调用
#include <stdio.h>
//创建一个结构体如下
struct ABC
{
int a[10000];
char b[20000];
double c[10000];
};
//传值接收
void pass_by_value(struct ABC ss)
{
;
}
int main()
{
clock_t start_time, end_time;
double execution_time;
struct ABC abc = { {0},{0,{0}} };
// 记录开始时间
start_time = clock();
for (int i = 0; i < 1000000; i++)
pass_by_value(abc);
// 记录结束时间
end_time = clock();
// 计算执行时间,单位为秒
execution_time = (double)(end_time - start_time) / CLOCKS_PER_SEC;
printf("传值调用程序执行时间: %f秒\n", execution_time);
return 0;
}
运行上述代码,我们发现结果如下:
运行时间需要2.5s,这对于一个计算机来说,已经是相当长的时间了,虽然我们一共迭代了一百万次
2、传址调用
#include <stdio.h>
#include <time.h>
//创建一个结构体如下
struct ABC
{
int a[10000];
char b[20000];
double c[10000];
};
//传值接收
void pass_by_value(struct ABC ss)
{
;
}
//传址接收
void pass_by_address(struct ABC* ss)
{
;
}
int main()
{
clock_t start_time, end_time;
double execution_time;
struct ABC abc = { {0},{0,{0}} };
// 记录开始时间
start_time = clock();
for (int i = 0; i < 1000000; i++)
pass_by_value(abc);
// 记录结束时间
end_time = clock();
// 计算执行时间,单位为秒
execution_time = (double)(end_time - start_time) / CLOCKS_PER_SEC;
printf("传值调用程序执行时间: %f秒\n", execution_time);
// 记录开始时间
start_time = clock();
for (int i = 0; i < 1000000; i++)
pass_by_address(&abc);
// 记录结束时间
end_time = clock();
// 计算执行时间,单位为秒
execution_time = (double)(end_time - start_time) / CLOCKS_PER_SEC;
printf("传址调用程序执行时间: %f秒\n", execution_time);
return 0;
}
运行程序,结果如下:
代码的运行速度可以说不是一个数量级,但是为什么会出现这种情况呢,我们调试来看
此处可以看到,在传址调用时,程序会在内存中重新开辟一块新内存来保存传递过来这个结构体,因此,每调用一次这个传址调用的程序,都会新生成一个结构体,而我们写的这个结构体,一共占用140000个字节,所以程序运行速度较慢。
接下来我们来看传址调用
可以看到,传递的仅仅是一个地址,而在64位机器上,一个地址只占用8个字节,因此运行时间较短,哪怕迭代十万次,也仅仅只用了4毫秒,很多机器正是为了保证速度,才使用C语言进行编程,因此这节约的时间非常关键。
讲到这里,或许有人会说,传递地址的话,会不会产生风险,比如我传过去的值被修改了。
其实我们有一种方法可以保护我们的数值不被修改,那就是在函数接收的地方加入const,例如:
//传址接收
void pass_by_address(const struct ABC* ss)
{
;
}
这样,如果强行对数值进行修改,就会出现如下错误
如图,编译将会无法通过。
综上:当我们在使用C语言调用函数时,当涉及一些大的数组或者结构体传参时,尽量使用地址传参,这样可以大幅提升程序运行效率。