2011-07-04 241 views
47

我编写了一个函数,其中包含数组作为参数 ,并通过传递数组的值来调用它,如下所示。将数组作为参数传递给函数C

void arraytest(int a[]) 
{ 
    // changed the array a 
    a[0]=a[0]+a[1]; 
    a[1]=a[0]-a[1]; 
    a[0]=a[0]-a[1]; 
} 

void main() 
{ 
    int arr[]={1,2}; 
    printf("%d \t %d",arr[0],arr[1]); 
    arraytest(arr); 
    printf("\n After calling fun arr contains: %d\t %d",arr[0],arr[1]); 
} 

我发现什么,虽然我打电话通过传递值arraytest()功能,int arr[]正本改变。

你能解释一下为什么吗?

+1

您通过引用传递数组,但是您正在修改其内容 - 因此,为什么您看到数据发生更改 –

回答

65

当将数组传递作为参数,这

void arraytest(int a[]) 

意味着完全相同

void arraytest(int *a) 

所以你修改主要的值。

由于历史原因,数组不是一等公民,不能通过值传递。

+2

好了!所以数组根本不会被值传递! –

+1

在哪种情况下哪种表示法更好? –

+7

@Ramon - 我会使用第二个选项,因为它看起来不那么令人困惑,并且更好地表示您没有获得数组的副本。 –

4

您正在传递数组第一个成员的内存位置的值。

因此,当您开始修改函数内部的数组时,您正在修改原始数组。

请记住a[1]*(a+1)

+0

我认为*(a + 1)缺少()应该是*(a + 1) – ShinTakezou

+0

@谢谢,从我和C一起玩过一段时间。 – alex

6

您没有将数组作为副本传递。它只是一个指向第一个元素在内存中的地址的指针。

6

您正在传递数组

6

的第一个元素的地址。在C,除了少数特殊情况下,一个数组引用总是“衰变”的指针数组的第一个元素。因此,“按值”传递数组是不可能的。函数调用中的数组将作为指针传递给函数,这类似于通过引用传递数组。

编辑:有三个这样的特殊情况下,阵列不衰减的指针到它的第一个元素:

  1. sizeof a是不一样的sizeof (&a[0])
  2. &a&(&a[0])不一样(并且与&a[0]不完全相同)。
  3. char b[] = "foo"char b[] = &("foo")不一样。
+0

如果我将一个数组传递给一个函数。举个例子,我创建了一个数组'int a [10]'并分配了每个元素的随机值。现在,如果我使用'int y []'或'int y [10]'或'int * y'将这个数组传递给函数,那么在这个函数中我使用'sizeof(y)'Answer将字节指针已被分配。所以在这种情况下,它会作为一个指针衰减,如果你也包含这个,它将会有帮助。看到这个https://postimg.org/image/prhleuezd/ –

+0

如果我使用'sizeof'操作原来定义的数组中的函数,那么它会像数组一样衰减,但如果我传入其他函数,那么使用' sizeof'运算符会衰减为指针。 –

+0

https://stackoverflow.com/questions/8269048/length-of-array-in-function-argument?noredirect=1&lq=1 –

2

如果你想通过一维数组作为函数参数,你就必须在以下三种方式中的一种来声明一个正式的参数和所有三种申报方式生产,因为每个类似的结果告诉编译器将会收到一个整数指针

int func(int arr[], ...){ 
    . 
    . 
    . 
} 

int func(int arr[SIZE], ...){ 
    . 
    . 
    . 
} 

int func(int* arr, ...){ 
    . 
    . 
    . 
} 

因此,您正在修改原始值。

谢谢!

1

在大多数情况下,C中的数组被转换为指向数组第一个元素的指针。更详细地说,传递给函数的数组总是被转换成指针。

这里报价从K&R2nd

当一个数组名称被传递给函数,什么传递是初始元素的 位置。在被调用的函数中,这个参数是一个局部变量,所以一个数组名称参数是一个指针,即包含地址的一个变量。

写作:

void arraytest(int a[]) 

的含义与写作一样:

void arraytest(int *a) 

因此,尽管你不写它明确它为你传递一个指针,所以你正在修改主值。

更多我真的建议阅读this

此外,你可以找到SO here

0

传递一个多维数组作为参数传递给函数其他的答案。 传递一个暗淡的数组作为参数或多或少是微不足道的。 让我们来看看更有趣的传递2 dim数组的情况。 在C中,你不能使用指针构造指针(int **)而不是2 dim数组。 让我们做一个例子:

void assignZeros(int(*arr)[5], const int rows) { 
    for (int i = 0; i < rows; i++) { 
     for (int j = 0; j < 5; j++) { 
      *(*(arr + i) + j) = 0; 
      // or equivalent assignment 
      arr[i][j] = 0; 
     } 
    } 

在这里,我已指定一个函数,它作为第一个参数的指针5个整数的阵列。 我可以传递的参数有5列的任何2维数组:

int arr1[1][5] 
int arr1[2][5] 
... 
int arr1[20][5] 
... 

您可以来一个想法,以定义可以接受任何2维数组并更改函数签名更一般的功能如下:

void assignZeros(int ** arr, const int rows, const int cols) { 
    for (int i = 0; i < rows; i++) { 
     for (int j = 0; j < cols; j++) { 
      *(*(arr + i) + j) = 0; 
     } 
    } 
} 

这段代码可以编译,但是当试图按照与第一个函数相同的方式赋值时,你会得到一个运行时错误。 因此,在C中,多维数组与指针的指针...指针不同。 int(* arr)[5]是指向5个元素的数组的指针, int(* arr)[6]是一个指向6个元素数组的指针,它们是指向不同类型的指针!

那么,如何定义更高维度的函数参数呢?简单,我们只是按照模式! 海尔北京时间调整,以3维的阵列相同的功能:

void assignZeros2(int(*arr)[4][5], const int dim1, const int dim2, const int dim3) { 
    for (int i = 0; i < dim1; i++) { 
     for (int j = 0; j < dim2; j++) { 
      for (int k = 0; k < dim3; k++) { 
       *(*(*(arr + i) + j) + k) = 0; 
       // or equivalent assignment 
       arr[i][j][k] = 0; 
      } 
     } 
    } 
} 

如何你所期望的,它可以采取作为参数具有在第二维度4个元件和第三维度5中任3个暗淡阵列元素。任何这样的事情都可以:

arr[1][4][5] 
arr[2][4][5] 
... 
arr[10][4][5] 
... 

但是,我们必须指定所有尺寸大小,直到第一个尺寸。