将整个数组传递给函数

时间:2010-10-22 14:06:59

标签: c

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

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

8 个答案:

答案 0 :(得分:17)

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

如果我写:

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方法有效。

答案 1 :(得分:8)

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

答案 2 :(得分:5)

通常,制作整个阵列的副本是昂贵的。回到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));
}

答案 3 :(得分:3)

“按引用传递”是C中的红色鲱鱼。函数的所有参数都只是“按值传递”。对于数组,您以指针的形式传递第一个元素的地址。然后,您可以使用此指针指向所需的存储位置&读或写值。

答案 4 :(得分:3)

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

给出以下代码:

int a[5];

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

为什么foo可以在bar只收到传入的值的副本时操纵原始值?

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

所以

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

不同于:

int* a;
bar(a);

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

bar(&a[5]);

答案 5 :(得分:2)

来自online C standard

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

假设以下代码段:

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

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

因此,&a[0]收到的是指向foo的指针,而不是数组。取消引用或下标此指针允许您更改数组的值。

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

我一直强调单词 expression 来区分实际的数组对象(永远是一个数组类型)和任何引用代码中的那个对象,可以转换为指针类型。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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