C语言有参函数调用时参数间数据传递问题
C语言中在发生有参函数调用时,实参变量与形参变量之间的数据都是单向的“值传递”方式。包括指针变量和数组名作参数的情况。
C语言要求函数的实参要有确定的值,在函数调用时给形参分配相应的内存单元,同时将实参的“值”赋(复制)给形参,实现数据从实参到形参的传递(‘值传递’方式)。因为是复制,所以在操作副本(形参)过程中不会影响到原本(实参)内容。
首先,作为函数实参的量包括常量、变量和表达式。其中变量又包括简单变量、数组元素、数组名、指针变量等。不同类型变量作参数实现的数据传递方式相同,效果不同。所谓方式相同即都是参数间数据单向的“值传递”,效果不同是指被调函数能否改变主调函数中变量的值。
情况一:简单变量或数组元素作为函数参数
数组元素本身属于简单变量,在向形参传递数据时,根据前述规则只需将变量中的“值”复制一份放到形参变量中去操作,此时在被调用函数中操作的对象(形参)与实参并不在同一内存单元,并且在调用结束后形参所占内存单元被释放,因此调用函数不会影响到实参变量的值。同时被调函数也不会影响到主调函数中其他变量的值。
例:1
#include<stdio.h>
void main()
{int a=1,f(int a);
printf("%d%d",a,f(a));
}
f(int a)
{return(++a);}
例2
#include<stdio.h>
void main()
{int a[3]={1,2,3},f(int a);
printf("%d%d",a[0],f(a[0]));
}
f(int a)
{return(++a);}
情况二:指针变量或数组名作为函数参数
1.指针变量作函数参数
指针变量作实参在调用时仍然符合前述“值传递”规则,将其“值”赋给形参,相当于复制。此时数据在实参与形参间传递仍是单向的,调用函数不会影响实参的“值”(即指针变量中所存地址)。而与简单变量不同的是指针变量复制给形参的“值”本身是一个地址,这个地址为形参访问其所指变量创造了可靠条件。我的理解是,实参是一个抽屉的钥匙,在传参时,实参复制了一把钥匙传给形参。而被调函数拿到钥匙副本后,进行的操作可以分为两类:1、对钥匙本身做了一些操作(对指针本身进行操作);2、通过钥匙对抽屉里的内容进行了一些操作(对指针所指的变量进行操作);两种操作都不可能影响实参的值(即钥匙原本),却有可能改变实参所指向变量的值(即抽屉里的内容)。
例1
#include<stdio,h>
void main()
{void swap(int*p1,int*p2);
int a,b;
int *pointer1,int*pointer2;
scanf("%d,%d",&a,&b);
pointer1=&a; pointer2=&b;
if(a<b) swap(pointer1,pointer2);
printf("%d,%d",a,b);
}
void swap(int*p1,int*p2)
{int temp;
temp=*p1;
*p1=*p2;
*p2=temp;}
例2
#include<stdio,h>
void main()
{void swap(int*p1,int*p2);
int a,b;
int *pointer1,int*pointer2;
scanf("%d,%d",&a,&b);
pointer1=&a; pointer2=&b;
if(a<b)
swap(pointer1,pointer2);
printf("%d,%d",a,b);
}
void swap(int*p1,int*p2)
{int temp;
temp=p1;
p1=p2;
p2=temp;}
2.数组名作函数参数
数组名本身是一个特殊的指针变量,其值是数组的首地址,因此作实参时其传给形参的是内存中某指定单元的地址,调用过程中形参数组与实参数组占用同一段内存单元,因此对形参数组的操作也就是对实参数组的操作,对实参数组与形参数组来说数据传递表现为“双向”的,而对实参变量与形参变量而言数据的传递仍然是单向的。
例
#include<stdio,h>
void main()
{int a[3]={1,2,3};
void f(int a[]);
f(a);
for(i=0;i<3;i++)
printf("%d",a[i]);
}
void f(int a[])
{for(i=0;i<3;i++)
a[i]++;
}
情况三:引用作为函数参数:
首先申明引用和指针最大的不同是:应用本身不是变量,不存在自己的变量空间,引用只是一个作为变量别名的标志。
引用必须依托于一个已实际存在的变量,正如一个人的如果连正名都没有,就无所谓小名了。正因为引用只是为了方便为同一个变量所取的小名,所以在任何地方通过引用对变量的操作和通过变量名进行操作的结果是一样的。
综上,当引用作为函数参数时,对形参的操作既是对原变量的操作,可以改变实参的值。效果上虽然和通过指针改变实参一样,但两种机制完全不同,引用并没有另开辟其它空间,直接对“原本”进行了操作,节省了时间和空间。
(拓)结构体数组作函数参数
用结构体数组作函数参数包含两类情况:结构体数组元素作实参和结构体数组名作实参。两类情况仍然服从数据的单向传递原则只不过前者传给形参的是某些变量的值,后者传给形参的是结构体数组的首地址。
1.结构体数组元素作实参
符合结构体变量作实参规则,采取单向“值传递”方式将结构体变量所占的内存单元的内容全部顺序复制给形参(函数调用期间形参也要占用内存单元)。注意当实参的成员中包含数组时形参相应的成员接受到的是一个地址。
2.结构体数组名实参
同整形数组数组名作实参一样传递给形参的是内存中已指定单元的地址,调用过程中形参数组与实参数组占用同一段内存单元,因此对形参数组的操作也就是对实参数组的操作。对数组的操作表现为双向性。
综上所述,对于有参函数调用时,实参变量与形参变量之间的数据都是单向的“值传递”方式。至于调用过程中是否会改变主调函数中变量的值,则只需根据具体算法看被调函数是否会找到主调函数中变量所在内存单元并对其原本进行操作。