在C中,A[i][j]的含义是否取决于如何声明A



假设我有一个二维数组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);

实际上我有一个代码可以做到这一点。问题是,它会像以前一样,使用双下标表示法访问grid的元素。这种情况不同吗?在这种情况下,grid[i][j]是否转换为*(*(grid+i)+j),即转换为双重解引用?这是我唯一能看到它正确发生的方式。

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

编辑:

好的,让我们看看我是否明白了:

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

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

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

没有。(不知道为什么这么多答案都是肯定的(。*(grid+(i*5+j))grid[i*5+j]相同,是对ij的某些值的越界访问。此外,这指定了一个数组,而不是内部

以下两个表达式在所有情况下都是完全等价的:A[i][j] *(*(grid+i)+j)

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

在剩下的回答中,我将使用[ ]语法,因为我发现它更清晰。

也许你想问这样的问题:"对于int A[5][5];,那么A[i][j]是否等效于从A开始偏移i+5*j?">

其他答案有点混乱,因为"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数组。

注:。写int *B = (int *)A是错误的,因为A衰变为只有5个int的&A[0],所以B[6]仍然是一个越界访问(未定义的行为(。如果您的编译器中没有启用边界检查,那么您可能不会注意到任何东西。

x[i][j]总是与*(*(x+i)+j)完全等价。。。但你必须记住,指针运算会考虑所指向类型的大小

double ary[NROWS][NCOLS];

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

double** ptr;

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

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

是。你走的是正确的路,但申报

double grid[5][5]

double **grid; 

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

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

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

除其他答案外:

当声明网格时,一个连续的内存块被分配为5*5倍,不多也不少;

这并不完全正确(少的部分总是正确的(,但有时你会发现,即使你在数组结束后访问内存,程序似乎也能工作(不会立即出错(。这意味着有时malloc可以分配比您要求的更多的内存。当然,这并不意味着你应该访问过多的内存。

是的,A[i][j]所指的地址是否取决于A的声明方式。

用于计算array_variable[i][j]的指针算术取决于列数(在第二维度上(:这是因为每行(第一维度(的所有元素都存储在一起,列数影响第二行、第三行等的数据存储位置。

这个URL声明,如果你有一个二维数组,声明为:

int [NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]

然后:

x = y[a][b]

相当于:

x = *((int *)y + a * NUMBER_OF_COLUMNS + b);

网址:如何使用指针表达式访问C中二维数组的元素?

该URL表示(二维数组(的元素按行主顺序存储:例如,首先存储行1的所有元素。

http://www.cse.msu.edu/~cse251/electure11.pdf

这个URL有一个类似的计算,取决于第二个维度的大小:

http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html

addr( & arr[ row ][ col ] ) = addr( arr ) + [ sizeof( int ) * COLS * row ]
                                          + [ sizeof( int ) * col ]

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

A不,没有。

如果你有,

int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

a[i]被评估为*(a+i)

如果你有

int ** create2DArray(int d1, int d2)
{
   int i = 0;
   int ** a = malloc(sizeof(*a)*d1);
   for ( ; i != d1; ++i )
   {
      a[i] = malloc(sizeof(int)*d2);
   }
   return a;
}
int **a = create2DArray(3, 3);

a[i]仍然被评估为*(a+i)

无论它们是如何声明的,a[i][j]都被评估为*(a[i] + j)

您仍然可以调用以下函数:

void func(int* p, int size)
{
   int i = 0;
   for ( ; i != size; ++i )
   {
      printf("%d ", p[i]);
   }
   printf("n");
}

使用

func(a[i]);

不管CCD_ 64是如何定义的。

a的第一个定义和a的第二个定义之间的主要区别在于如何为其分配内存。在第一种情况下,内存是在堆栈上分配的,并且是连续的。在第二种情况下,内存是在堆上分配的,并且很可能是不连续的。然而,如何使用它和编译器如何处理它是完全相同的。

相关内容

  • 没有找到相关文章

最新更新