在C中,A [i] [j]的含义是否取决于A的声明方式?

sp0*_*00n 13 c arrays pointers multidimensional-array

假设我有一个二维数组grid声明为double grid[5][5].我的理解是,以下陈述是正确的:

  • grid声明时,为5*5双精度分配一个连续的内存块,不多也不少;
  • 当使用表示法访问数组的元素时grid[i][j],这段代码实际上被解释为*(grid+(i*5+j)).

另一方面,我知道我也可以存储与指针数组相同的矩阵,类似于:

double ** grid;
grid = (double**)malloc(sizeof(double*)*5);
for (i=0; i<5; i++)
   grid[i] = (double*)malloc(sizeof(double)*5);
Run Code Online (Sandbox Code Playgroud)

我实际上有一个代码可以做到这一点.问题是,然后它继续grid使用双下标符号来访问前面的元素.这种情况有所不同吗?在这种情况下,grid[i][j]转换为*(*(grid+i)+j),即双重解除?这是我能看到它正确发生的唯一方式.

(这个问题可能源于我(缺乏)对C中指针和数组类型之间关系的理解...)

编辑:

好吧,让我们看看我是否直截了当:

  • grid[i][j]总是被转换成*(*(grid+i)+j);
  • 在这两种情况下,这个表达式确实以不同的方式计算,因为正如Jim在他的回答中所述,指针算法考虑了指向的类型的大小; 然而,在两种情况下都取得了正确的要素;
  • 当且仅当"grid"是2D数组时,此表达式才进一步优化*( (double*)grid + (i*5+j) ),这是可能的,因为编译器知道任何grid[i]实际上是从位置开始的数组grid+i*5.

但这给我留下了一个不可避免的结论:对于2D数组,如果我设置i=j=0,那么我就有了**grid == *((double*)grid).它是否正确?

Jim*_*ter 5

x[i][j]始终完全等同于*(*(x+i)+j)... 但您必须记住,指针运算会考虑指向的类型的大小。在

double ary[NROWS][NCOLS];
Run Code Online (Sandbox Code Playgroud)

ary[i](即*(ary+i))的大小是NCOLS*sizeof(double)。在

double** ptr;
Run Code Online (Sandbox Code Playgroud)

ptr[i](即*(ptr+i))的大小是sizeof(double*)

在这两种情况下,ary[i][j]ptr[i][j],都会获取正确的元素。


M.M*_*M.M 5

当符号网格[i] [j]访问数组的元素时,这段代码实际上被解释为*(grid+(i*5+j)).

不.(不知道为什么这么多答案对此表示肯定). *(grid+(i*5+j))是一样的grid[i*5+j],这是对i和的某些值的越界访问j.此外,它指定一个数组,而不是int.

在所有情况下,以下两个表达式完全相同:A[i][j] *(*(grid+i)+j).

你永远不会通过在两种不同的解引用符号之间进行转换来"获得"任何东西.对于指定特定对象的左值表达式,它只是两种等效的语法形式.

对于我的其余部分,我将使用[ ]语法,因为我发现它更清楚.

也许你想要问一些类似"with int A[5][5];,然后A[i][j]相当于i+5*j从一开始就抵消A?"

其他答案有点混乱,因为术语"抵消N"是模棱两可的.N个字节,或N个int,或N个int数组?

如果你想象在你的头脑中A是一个长度为25的一维数组(让我们称之为B),那么A[i][j]指定相同的对象B[i*5+j].

要在代码中表达这一点,您可以写:int *B = (int *)&A.这将int的2-D数组别名为1-D数组.

NB.写入是错误的int *B = (int *)A,因为A衰变&A[0]只有五个整数,所以B[6]仍然是一个超出界限的访问(未定义的行为).如果您没有在编译器中打开边界检查,那么您可能不会注意到任何事情.

  • 当`A`是`&`或`sizeof`的操作数时,它不会衰减. (2认同)

hac*_*cks 1

是的。你走的路是对的,但声明

double grid[5][5]
Run Code Online (Sandbox Code Playgroud)

double **grid; 
Run Code Online (Sandbox Code Playgroud)

是不同的。第一个是声明一个包含 25 个类型元素的二维数组double,第二个是声明一个指向double类型指针的指针。两者是不同的。请注意,数组不是指针

在第一种情况下,内存分配在堆栈上并且是连续的,因此编译器会grid[i][j]对其进行优化*(*(grid + i) + j),并进一步对其进行优化*(*grid + (i*5 + j))

在第二种情况下,内存是在堆上分配的,malloc不会创建连续的内存。在这种情况下,编译器会优化grid[i][j]为,*(*(grid + i) + j)但不会进一步优化为*(*grid + (i*5 + j))