在前面的章节介绍过普通变量作函数参数的方法,它其实是一种按值调用(Call by Value)的方法,即程序将函数调用语句中的实参的一份副本传给函数的形参。
例题:演示程序按值调用的例子。
#include <stdio.h>
void Fun(int par)
{
printf("PAR = %d\n",par);
par=2;
}
int main(void)
{
int arg=1;
printf("arg = %d\n",arg);
Fun(arg);
printf("arg = %d\n",arg);
return 0;
}
程序在函数Fun()中的第二行(bar=2)改变了形参的值,并在main中调用了Fun()函数后再次输出实参的值,由程序的运行结果可以看出,函数形参值得改变并未影响实参得改变。这是因为传给函数形参的值只是函数调用语句中实参值的副本,因此,按值调用的方法不能再被调函数中改变其调用语句的实参值。
那么如何再函数中改变实参的值呢?这就要用到指针这个武器了。
指针变量的一个重要应用就是用作函数参数,指针作函数参数时,虽然实际上也是传值给被调函数(C语言中的所有函数调用都是按值调用),但是传给被调函数的这个值不是变量的值,而是变量的地址,通过向被调函数地址传递某个变量的地址值可以再被调函数中改变主调函数中的这个变量的值,相当于模拟了C++语言中的按引用调用,因此称为模拟按引用调用(Simulating Call by Reference)
例题:演示程序模拟按引用调用的例子。
#include <stdio.h>
void Fun(int *par);
int main()
{
int arg=1;
printf("arg = %d\n",arg);
Fun(&arg);
printf("arg = %d\n",arg);
return 0;
}
void Fun(int *par)
{
printf("par = %d\n",*par);
*par=2;
}
程序将Fun中的形参改为指针类型,使用指针变量作为函数形参,这就意味着形参接收到的数据指针是一个地址值。因此main中使用取地址符&获取变量arg的地址值,并将其传给函数Fun(),从而使形参par指向了变量arg。
思考:下列程序是否能将随意输入的两个整数进行交换后在输出?
#include <stdio.h>
void swap(int x,int y);
int main(void)
{
int a,b;
printf("Please enter a,b:");
scanf("%d%d",&a,&b);
printf("Before swap :a = %d,b = %d\n",a,b);
swap(a,b);
printf("After swap :a = %d,b = %d\n",a,b);
}
void swap(int x,int y)
{
int temp=0;
temp=x;
x=y;
y=temp;
}
从结果可以看出无法实现数据的调换。结合上一个程序的分析,再函数swap中只是对形参进行了改变,但不会对实参进行操作。
修改:
#include <stdio.h>
void swap(int *x,int *y);
int main(void)
{
int a,b;
printf("Please enter a,b:");
scanf("%d%d",&a,&b);
printf("Before swap :a = %d,b = %d\n",a,b);
swap(&a,&b);
printf("After swap :a = %d,b = %d\n",a,b);
}
void swap(int *x,int *y)
{
int temp=0;
temp=*x;
*x=*y;
*y=temp;
}
上述程序中,若将swap中的取地址符&去掉,则会出向错误:
27 11 D:\exercise\Simulating Call by Reference\main.cpp [Error] invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
可以看出大致意思使类型不同。但是在scanf是不会给出错误或警告,但是在运行程序的时候会出现问题,导致死机等情况。
在其他的一些编译器中,则会出现如非法内存访问的错误
主要原因是,去掉取地址符后,会将整形参数赋值给指针,指针知道的地址不是我们所需要的。