虽然通过指针型参数传递可以达到让被调函数内的操作作用于主调函数内数据的效果,但从实参和形参的角度来看,这种参数传递并没有和一般的传递方法有什么本质的区别,也是值传递方式。
当参数传递方式是值传递时,形参和实参都存储在各自的内存空间中,相互独立互不影响,它们之间唯一的联系便是在形参初始化时会使用实参的值。
数组参数
在C语言中,数组名可以看作一个指向数组首元素的指针常量,那么当数组作为参数是又是如何传递呢?实际上,当函数形参是数组类型时,作为形参的数组名便不再代表数组,而是被编译器解析成一个指针。通过下面的例子可以看出,数组类型的形参只是在函数签名中看上去是一个数组,但在函数体内,它已经彻底沦为一个指针。
#include <stdio.h>
void arrArg(int arr[]){
printf("形参arr的值:%#x,地址:%#xn", arr, &arr);
printf("sizeof(arr):%d, sizeof(int *):%dn",sizeof(arr), sizeof(int *));
printf("sizeof(arr[0]):%d,sizeof(int):%dn", sizeof(arr[0]), sizeof(int));
printf("*arr:%d,arr[0]:%dn", *arr, arr[0]);
printf("*(arr+1):%d,arr[1]:%dn", *(arr+1), arr[1]);
printf("arr+1:%#x,&arr[1]:%#xn",arr+1, &arr[1]);
arr++;
printf("自增操作后形参arr的值:%#x,地址:%#xn",arr, &arr);
printf("自增操作后,*arr:%d, arr[0]:%dn",*arr, arr[0]);
}
int main(){
int a[] = {1,2,3};
printf("实参a的值:%#x,地址:%#xn",a,&a);
printf("sizeof(a):%d,sizeof(a[0]):%dn",sizeof(a),sizeof(a[0]));
arrArg(a);
return 0;
}
编译后执行结果如下:
实参a的值:0x5fcb00,地址:0x5fcb00
sizeof(a):12,sizeof(a[0]):4
形参arr的值:0x5fcb00,地址:0x5fcae0
sizeof(arr):8, sizeof(int *):8
sizeof(arr[0]):4,sizeof(int):4
*arr:1,arr[0]:1
*(arr+1):2,arr[1]:2
arr+1:0x5fcb04,&arr[1]:0x5fcb04
自增操作后形参arr的值:0x5fcb04,地址:0x5fcae0
自增操作后,*arr:2, arr[0]:2
可以看出,虽然形参arr被声明为int型数组,但在函数内部,arr已不再拥有数组的性质,而拥有了指向int型的指针的性质:
arr的大小是指针的大小(8),而非数组的大小(数组的大小是所有元素大小的总和,上例中:4×3=12)
arr可以被修改,而数组名不可以被修改
arr与a的内存地址不同但值相同(都是数组首元素地址),所以,在函数被调用时,真正被传递的值是数组首元素的地址,并以此地址初始化了一个指向实参数组首元素的指针作为形参。因为实际的形参是一个指针,所以这种情况也是属于值传递。同时,与指针参数效果一样,在函数内对“数组”的修改会直接作用于外部。










