为什么会产生分段错误?

时间:2010-03-15 15:21:11

标签: c arrays segmentation-fault

#include<stdio.h>
void foo(int **arr) {
    arr[1][1]++;
}

main() {
    int arr[20][20];
    printf("%d\n",arr[1][1]);
    foo((int**)arr);
    printf("%d\n",arr[1][1]);
}

6 个答案:

答案 0 :(得分:10)

  

假设您声明:       int arr [10] [20];
    什么类型的arr?
  您可能认为它是int **,但这是不正确的。

     

当它衰变时它实际上是int (*)[20]类型(比如当你将它传递给函数时);
  数组衰减仅适用一次。

Details here


现在考虑以下内容,

#include<stdio.h>
#include<stdlib.h>
void foo(int arr[][20]) {
  arr[1][1]++;
}
main() {
  int (*arr)[20];
  arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.

  printf("%d\n",arr[1][1]);
  foo(arr);
  printf("%d\n",arr[1][1]);
}

输出:

  

$ gcc fdsf.c&amp;&amp; ./a.out
  0
  1


  

arr arr + 1 指向20个整数的数组。

     

arr + 0 - &gt; int int int ... int(20 int,con))   [0] [0] [0] [1]
  arr + 1 - &gt; int int int ... int(20 int,con))   [1] [0] [1] [1]

答案 1 :(得分:7)

以下是int[2][2]在内存中的样子:

int[2] int[2]

也就是说,一个数组紧跟另一个数组。

以下是int[2]在内存中的样子:

int int

也就是说,一个int后面跟着另一个int。

所以,这也是int[2][2]在内存中的样子:

int int int int
     ^       ^
     |       |___ this is arr[1][1]
     |
     |____ this is p[1], assuming sizeof(int*) == sizeof(int)

如果您将arr投射到int**,我将调用结果p。然后它指向相同的记忆。当您执行p[1][1]时,您无法获得arr[1][1]。该程序的作用是,它读取p[1]处的值,通过int的大小调整该值,并且取消引用它。如果第二个int包含,例如值“21”,那么您刚刚尝试取消引用指针“25”(如果int是4个字节)。那不对。

数组与指针不同,2-D数组肯定与指针指针不同。

答案 2 :(得分:6)

因为foo期望指向int的指针,并且你正在向它传递一个指向20 int数组的指针。投射它不会改变它不是正确类型的事实。

答案 3 :(得分:5)

如果你这样改变,你会得到预期的结果:

#include<stdio.h>
void foo(int arr[][20]) {
    arr[1][1]++;
}

int
main() {
    int arr[20][20];
    arr[1][1] = 1;
    printf("%d\n",arr[1][1]);
    foo(arr);
    printf("%d\n",arr[1][1]);
}

答案 4 :(得分:4)

foo需要知道数组大小(好吧,至少第二个数组维,首先不需要),否则它不能为[1][1]做必要的指针算法。 / p>

答案 5 :(得分:1)

问题是2d数组的int arr[20][20]意味着该数组存储为1d数组,并且行依次存储。当您对int **arr建立索引时,实际上从数组的第一行获取第二个元素,然后取消引用它并在那里取第一个元素。