将整个数组传递给函数

当我们将一个数组的元素传递给一个函数时,它被视为一个普通变量,被调用的函数创建一个实际参数的副本并对其进行操作。 在forms参数中进行的任何更改都不会影响实际参数。

但是当我们传递整个数组时,情况并非如此。 在这种情况下,它(称为函数)可以访问实际参数,并且正式参数中的任何更改都会影响实际参数。 为什么会这样?

该数组作为指向元素的指针传递。

如果我写:

void doStuff(int *ptr) { ptr[1] = 5; } int main() { int arr[] = {0, 1, 2}; doStuff(arr); printf("%d %d %d\n", arr[0], arr[1], arr[2]); } 

输出将为“0 5 2”。 那是因为C通过值传递任何实际参数。 该参数是指向int的指针。 因此,指向int的指针按值传递。 因此,doStuff在main的堆栈帧中获取指向内存的指针的副本。 当它用ptr[1]取消引用该指针时,它跟随指向main的内存并在那里修改数组。

C只能通过值传递,但它“浅”。 如果要求它传递int *,它将传递一个int *。 它只复制指针的值,而不是它指向的任何值。

如果你想让doStuff获得它自己的数组副本,要么像其他人建议的那样将数组包装在结构中,要么使用memcpy手动深度复制数组,如下所示:

 void doStuff(int *ptr, int nElems) { int myCopyOfTheArray[nElems]; memcpy(myCopyOfTheArray, ptr, sizeof(int) * nElems); /* do stuff with the local copy */ } 

与使用结构不同,如果只在运行时知道nElems,则memcpy方法有效。

数组不能通过C中的值传递。它们被降级为指针。 因此被调用的函数看到一个指向数组的指针(通过引用传递)并对其进行操作。 如果要创建副本,则必须显式执行此操作,或将数组放在结构中(可以通过值传递给函数。)

通常,制作整个arrays的副本是昂贵的。 回到C首次创建的日子,它可能很容易耗尽机器资源(特别是堆栈)。

如果您确实想要传递数组,请将其包装在结构中:

 struct wrap { int array[100]; }; int somefunc(struct wrap large) { ... } void anotherfunc(void) { struct wrap a; ...add data to array... printf("%d\n", somefunc(a)); } 

我还没有看到任何答案,但尚未涵盖整个问题。 从我看到的,看起来问题是这样的:

给出以下代码:

 int a[5]; foo(a); bar(a[0]); 

为什么foo可以操作原始值而bar只接收传入值的副本?

这是因为使用了数组表示法: []运算符取消引用它在数组中引用的项目并传入该位置的值。

所以

 int a[5]; bar(a[0]); 

不同于:

 int* a; bar(a); 

如果要传递对数组中特定项的引用,则需要使用&运算符:

 bar(&a[5]); 

“通过引用传递”是C中的红色鲱鱼。函数的所有参数都只是“按值传递”。 在数组的情况下,您以指针的forms传递第一个元素的地址。 然后,您可以使用此指针指向所需的内存位置以及读取或写入值。

从在线C标准 :

6.3.2.1左值,数组和函数指示符

3除非它是sizeof运算符或一元运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为“array of type”的表达式转换为类型为“指向类型的指针”的表达式指向数组对象的初始元素,而不是左值。 如果数组对象具有寄存器存储类,则行为未定义。

假设以下代码段:

 int a[10]; ... foo(a); 

在对foo的调用中, 表达式 a的类型是“10元素数组的int ”。 但是,由于表达式不是sizeof&运算符的操作数,并且因为它不是用于初始化声明中的另一个数组的字符串文字,所以它的类型从“10-”隐式转换(“衰减”) int “to”指向int “的元素数组,其值将是数组中第一个元素的地址(即&a[0] )。

因此, foo接收的是指向int的指针,而不是数组。 取消引用或下标此指针允许您更改数组的值。

这是C语言的一个特性; 数组不是第一类对象。 实际上,在大多数情况下(包括下标),数组表达式将被转换为指针类型。

我一直在强调单词表达式,以区分实际的数组对象 (永远是永远的数组类型)和代码中对该对象的任何引用 ,可以将其转换为指针类型。

因为当你将整个数组传递给函数时你传递一个指向该数组的指针,这意味着你给函数一个位于这个数组所在的内存中的位置。 因此,当您在函数中更改数组时,您也在更改原始数组。

C中的数组可以被视为指向数组第一个元素的指针。 指针按值传递(您无法修改传入的值),但您可以取消引用它并修改它指向的内存。