当我们将一个数组元素传递给一个函数时,它被视为一个普通变量,被调用函数创建一个实际参数的副本并对其进行操作.在形式参数中进行的任何更改都不会影响实际参数.
但是当我们传递一个完整的数组时,情况并非如此.在这种情况下,它(称为函数)可以访问实际参数,并且正式参数中的任何更改都会影响实际参数.为什么会这样?
Alc*_*ive 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]);
}
Run Code Online (Sandbox Code Playgroud)
输出将为"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 */
}
Run Code Online (Sandbox Code Playgroud)
与使用结构不同,如果只在运行时知道nElems,则memcpy方法有效.
数组不能通过C中的值传递.它们被降级为指针.因此被调用函数看到一个指向数组的指针(通过引用传递)并对其进行操作.如果要创建副本,则必须显式地执行此操作,或者将数组放在结构中(可以通过值传递给函数.)
通常,制作整个阵列的副本是昂贵的.回到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));
}
Run Code Online (Sandbox Code Playgroud)