关于C语言中数组作为参数传递的疑惑~~

int array[]={1,2,3}
void a(int array[2]){}
void b(int array[]){}
void c(int (&array)[2]){}
以上都是以数组作为参数传递给函数a,b,c的。想了解以上三者的区别,希望各位老大详细解释,谢谢~~~

凑凑热闹,同意terry_tang的观点,另做些补充:

先看代码:

#include <stdio.h>

void foo(int array[2]){printf("int array[2]:\t\t%x %d\n", &array, sizeof(array));}
void bar(int array[]){printf("int array[]:\t\t%x %d\n", &array, sizeof(array));}
void baz(int (&array)[2]){printf("int (&array)[2]:\t%x %d\n", &array, sizeof(array));}

int main()
{
int a[2] = {1, 2};
printf("main::a[2]:\t\t%x %d\n", a, sizeof(a));
foo(a);
bar(a);
baz(a);

return 0;
}

解说:

foo和bar的传值方式是相同的,都是一个int*, 即一个整型指针,这可以从foo和bar里打印出的array地址和main中的不同和sizeof(array)仅为sizeof(int*)看出,只不过是外型有点儿区别。

编译器是不知道你要传递的是一个数组或是单一一个整型的地址的,这是因为C中数组的内存模型是连续存储(它并不知道传递的(首)地址之后的空间可否访问)。

所以写为foo或bar的样式仅仅是对人的一种暗示,暗示传递的是一个数组,括号里的2编译器是不会把他当回事儿的①。

采用foo中的样式,代码编写者在函数中获知传递的数组的大小,但这种暗示功能很弱,而且易使人产生误解。

比如以上的函数foo,传递大小为1个元素的数组(即单一一个整型的地址):

int x[1];
foo(x);

或传递一个大小为100的数组:

int x[100];
foo(x);

编译器都不会有任何抱怨,所以在代码工程量很大的时候,你无法保证数组传值的安全性,另外一个问题是如果你写的是商业性质的库,你无法保证客户(二次开发者)能安全地使用你的代码。

采用bar中样式,实质和foo相同,空括号给人的暗示就是它能接受的参数是一个数组,而且是一个长度不确定的一维整型数组,这相对于foo来说更为实际和真实一些(因为foo可能造成欺骗性的代码,原因见上)。

所以这种传数组的方式被多数人所采用,但一般还需多加一个参数来指定数组的大小,如:

void bar(int array[], int size);

或效仿STL的做法,传递数组的首地址和超尾指针(在遍历数组元素时很方便,且更快速、安全):

void bar(int* beg, int* end);

至于baz,它不同于foo和bar。前面已经说过,foo和bar实质是相同的,传的都是一个int*,且传值方式都是按值传递(C中只有按值传递)。

而baz却是按引用传递,传递的是一个"编译器认可的,大小为2"②的数组的引用。

foo和bar都可以改写为:

void theFact(int* array);

void theFact(int* array, int size);

按照此逻辑是不是baz可改写为这样呢?

void baz2(int* const& array); // a其实是一个int* const型指针,所以要加上const作为修饰

答案是否定的,注意上面的②,只有在C++中,函数"按引用"传递数组并"指定其大小时",[]中的数字才有意义(对编译器而言)。所以baz2 != baz:

int x[100];

baz(x); // 编译错误
baz2(x); // 可以通过

要理解这和foo, bar的不同首先要理解C++中对引用的定义: 引用就是对象本身,不存在没有引用对象的引用。所以在baz中,形参array就是实参main中的a,一切a所有的特性都是array的特性,所以sizeof(array) == sizeof(a),而且&baz::array == main::a(地址相同)。

①: C99中允许使用static数组参数修饰词,如:

void foo(int x[static 10]); // x数组至少含有10个连续元素

上句中的10此时并不是可有可无的,它是编译器优化数组访问的一种暗示。
温馨提示:内容为网友见解,仅供参考
第1个回答  推荐于2018-02-24
C语言数组调用是传送地址调用。
为便于弄清函数原型和数组调用,把程序补充写成:
#include<stdio.h>
#include<stdlib.h>

void a(int x[2]){ x[0] = 11; x[1] = 12; };

void b(int x[], int n){
int i;
for (i=0;i<n;i++) x[i] = 2.0 * x[i];
}

void c(int x) { printf("%d\n",x); }

void main()
{
int array[]={1,2,3} ;
int k;

(void) a(array);
printf("%d %d %d\n",array[0],array[1],array[2]);

(void) b(array, 3);
printf("%d %d %d\n",array[0],array[1],array[2]);

k = (int) (&array)[2];
(void) c( k);
printf("%d %d %d\n",array[0],array[1],array[2]);

}

a(array); 调用,函数a 对调用数组前2个单元做了加工,第3个单元不做加工。所以输出结果 11,12,3

b(array,3); 调用,对array 3个单元做了加工,各乘2,
所以输出结果 22,24,6

c的调用是把array 的指针值拿来派用场,所以输出结果不变 22,24,6

如果a函数原型是 void a(int x),
调用(void) a(array[2]), 则是把数组第3个元素拿来加工。

因问题说得不清楚,只好猜测。本回答被提问者和网友采纳
第2个回答  2016-01-16
1、数组做参数,完全无法按值传递。这是由C/C++函数的实现机制决定的。
2、传数组给一个函数,数组类型自动转换为指针类型,因而传的实际是地址。
下面三种函数声明完全等同:
void func(int array[10])
void func(int array[])
void func(int *array)
第3个回答  2007-08-17
第一个函数是把数组array的第三个元素作为参数传递过去的,是传值;
第二个函数是把数组array的地址,也就是第一个元素的内存地址传递过去,是传址;
第三个,呃,不太明白了,如果没有那个圆括号,我会认为是传递的数组第三个元素的地址,但是加了这个括号代表什么呢,有点疑惑。
第4个回答  2007-08-17
三个都是定义了没有返回值的函数
但是第一个是定义了一个有两元素就是说数组中的元素不能大于二而溢出的整形数组,将这个数组作为函数的参数
第二个没有定义元素的个数,同样将数组作为函数的参数
第三个则是定义了一个具有两个元素的指针型数组,传递的是数组的首地址

C语言数组作为形参实参的一些疑惑?
void fun(int arr[], int n);在函数定义的时候,形参int arr[]不是表示某个元素的值,而是告诉编译器第一个参数是一个数组指针,可以接收实参传过来的数组地址。实际上以上定义等价于下面的定义。1.数组里面带元素个数:void fun(int arr[常数], int n);这里的常数可以是任意正整数,实际上编译...

关于c语言中的结构体数组作为函数参数传递的
1、结构体数组传给指针,实质上是不可能的,本质上传的是数组首地址,根据偏移来操作数组,这样看起来好像是真在操作数组一样。就和普通指针一样使用,只不过它是结构体数组。2、例程:typedef struct Student{ char name[10] ; int age ;}Student;#define LEN 10 \/\/print all Student infoma...

C语言中,数组名作为函数参数,属于什么传递,为什么?
属于地址传递,在函数里修改的话,将直接影响调用方的数值。这是因为数组名代表这个数组的首地址,不过是静态不可更改的而已。在函数里用引用[i]下标时,就是找到这个数组第i号元素的地址进行修改的。所以是第于是地址传递。

C语言中函数定义形参为数组时的问题
1.数组为参数传递的是数组首地址,而不是元素的值,而你说的a[size]仅仅是值,况且事实上也没有a[size]这个元素 2.既然是数组名的传递,当然需要由一个数组的参数来接收,int v[]”的问题是因为他是形式参数,是为了接收数组的 n的问题是因为,如果只传递了数组,但是函数并找不到数组的个数,所以需要...

C语言中,数组做函数参数如何才能按值传递?
传数组给一个函数,数组类型自动转换为指针类型,因而传的实际是地址。void func(int array[10])void func(int array[])void func(int *array)所以以上三种函数声明完全等同。实际情况是,数组做参数,完全无法按值传递。这是由C\/C++函数的实现机制决定的。下一个问题是:为什么偏要按值传递呢?当要...

关于c语言数组的一些疑惑?
而数组做形参时,只是把实参的首地址传给形参,后面对形参的元素的赋值和改写,直接对实参的数组元素进行了赋值和改写。在C语言中,array[10]有两种含义:①它指含有10个元素的数组array,如:int array[10];②它指数组array的第10号元素,如:array[10] =5;因此,对于使用数组array[10](这里,你...

c语言中数组名为函数实参的问题?
代码在编译时会出现 error C2664: 'InsertSort' : cannot convert parameter 1 from 'int' to 'int []'这是因为用数组名做函数实参时,向形参(数组名或指针变量)传递的是数组首元素地址,因此对参数的类型做一下改变,如下图所示:

关于C语言的二维数组作为函数参数的问题?
int arr[n][m];实际上相当于:int n=2,m=3;int (*arr)[m];所以,传递二维数组作为参数,实际上就是传递了一个指针。将形参的类型定义成int*,再在函数内部转换回指向数组的指针就行了,比如:void f(int *p,int row,int column){ int (*arr)[column]=(int (*)[column])p;\/\/使用...

C语言中,数组名作为函数参数,属于什么传递,为什么?
C语言中,数组名作为函数参数,属于数组参数传递。在VB6.0中,允许使用数组作为实参传递到子过程的形参中,数组传递必须采用地址传递的方式来传递参数。数组型变量名本身只是该数组所占存储空间的首地址,函数调用时,系统不会为形参分配数组存储空间,而是仅仅分配一个存放数组地址(第一个元素地址)的存储...

关于c语言中数组作为函数参数的函数之间调用问题
1、新建一个数组作为参数项目,如图所示:2、添加一个array.c文件,如图所示:3、包含stdio.h和stdlib.h头文件,如图所示:4、输入main函数主体及返回值,如图所示:5、定义一个数组arr,如图所示:6、定义一个function函数,如图所示:7、将数组作为参数传递给function函数,如图所示:8、运行程序,输出...

相似回答