2

请考虑以下二维数组:

int array[2][2] = {
                    {1,2},
                    {3,4}
                  };

根据我的理解: - 'array' 表示二维数组的基地址(与数组的第一个元素的地址相同,即数组 [0] [0])。

  • 二维数组在内存中的实际排列就像一个大的一维数组。

  • 现在,我知道基地址 = 数组。因此,我应该能够到达包含元素的内存块:array[0][0]。

  • 如果我忘记了二维数组的事情并尝试将此数组视为简单的一维数组: array[0] = *(array+0) 给出第一个数组的基地址而不是元素 array[0 ][0]。为什么?

  • 二维数组不存储任何内存地址(如指针数组)。

  • 如果我知道基地址,我必须能够以线性一维数组的形式访问该内存。

请帮我澄清这个疑问。

谢谢。

4

5 回答 5

5

“你不应该害怕 poynter arythmethyc”...

int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)&array[0][0];
int i;
for (i = 0; i < 4; i++) {
    printf("%d\n", ptr[i]);
}

为什么这行得通?C 标准规定多维数组在内存中是连续的。这意味着,您的 2D 数组的排列方式,就其元素的顺序而言,类似于

array[0][0]
array[0][1]
array[1][0]
array[1][1]

当然,如果你把数组的地址当作一个指向int的指针(int *,让我们命名它ptr),那么各项的地址如下:

ptr + 0 = &array[0][0]
ptr + 1 = &array[0][1]
ptr + 2 = &array[1][0]
ptr + 3 = &array[1][1]

这就是它最终起作用的原因。

于 2012-09-05T17:59:55.873 回答
5

array[0]是一维数组。其地址与 的地址array相同,与 的地址相同array[0][0]

assert((void*)&array == (void*)&(array[0]));
assert((void*)&array == (void*)&(array[0][0]));

由于array[0]它是一个数组,因此您不能将其分配给变量,也不能将其传递给函数(如果您尝试这样做,您将传递一个指向第一个元素的指针)。您可以通过查看(array[0])[0]and来观察它是一个数组(array[0])[1](括号是多余的)。

printf("%d %d\n", (array[0])[0], (array[0])[1]);

您可以观察到它的大小是 2 个int对象的大小。

printf("%z %z %z\n", sizeof(array), sizeof(array[0]), sizeof(array[0][0]));

这是一个表示内存布局的图表:

+-------------+-------------+-------------+-------------+
|      1      |      2      |      3      |      4      |
+-------------+-------------+-------------+-------------+
 `array[0][0]' `array[0][1]' `array[1][0]' `array[1][1]'
`---------array[0]---------' `---------array[1]---------'
`-------------------------array-------------------------'
于 2012-09-05T18:04:00.627 回答
3
  1. 二维数组在内存中的实际排列就像一个大的一维数组。

    是的,存储区域是连续的,就像一维数组一样。但是索引方法有点不同。

    2-D[0][0] = 1-D[0] 
    
    2-D[0][1] = 1-D[1] 
    
    ... 
    
    2-D[i][j] = 1-D[ i * rowsize + j]
    
    ...
    
  2. 如果我忘记了二维数组的事情并尝试将此数组视为简单的一维数组: array[0] = *(array+0) 给出第一个数组的基地址而不是元素 array[0 ][0]。为什么?
    *(array+0) 表示指向数组的指针。这种格式的第一个元素索引应该是*((*array+0)+0)。

    所以最后应该是 *(*array)

  3. 二维数组不存储任何内存地址(如指针数组)。当然可以 。例如 ,

    int * array[3][3] ={ null, };
    
  4. 如果我知道基地址,我必须能够以线性一维数组的形式访问该内存。

    使用这个正式的 2-D[i][j] = 1-D[ i * rowsize + j]...

于 2012-09-05T18:05:06.117 回答
1

数组不是指针。

在大多数情况下1,“N-element array of”类型的表达式T将被转换(“decay”)为“pointer to T”类型的表达式,表达式的值将是第一个元素的地址大批。

表达式 的类型array是“2 元素数组的 2 元素数组int”。根据上面的规则,在大多数情况下,这将衰减为“指向int( int (*)[2]) 的 2 元素数组的指针。这意味着表达式*array(以及扩展,*(array + 0)and array[0])的类型是“2 元素数组int”,这反过来会衰减到 type int *

因此,*(array + i)为您提供以下第i' 个2 元素数组intarray(即 int 的第一个 2 元素数组在array[0]( *(array + 0)) 处,第二个 2 元素数组intarray[1]( *(array + 1)) 处。

如果您想将array视为 的一维数组int,则必须按照以下方式进行一些铸造体操

int *p = (int *) array;
int x = p[0];

或者

int x = *((int *) array + 0);


1. 例外情况是数组表达式是一元运算符sizeof或一元运算符的操作数&,或者是用于在声明中初始化另一个数组的字符串文字。

于 2012-09-05T18:37:48.743 回答
0

我喜欢H2CO3的回答。但是您也可以将指向数组的指针视为可递增变量,如下所示:

int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)array;
int i;
for (i = 0; i < 4; i++) 
{
    printf("%d\n", *ptr);
    ptr++;  
}

++ 运算符在指针上工作得很好。在这种情况下,它会将指针增加其类型的一个地址,或 int 的大小。

必须始终小心使用 c 中的数组,以下将编译得很好:

int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)array;
int i;
for (i = 0; i < 100; i++)  //Note the 100
{
    printf("%d\n", *ptr);
    ptr++;  
}

这将溢出数组。如果你正在写这个,你可能会破坏程序中的其他值,包括 for 循环中的 i 和指针本身中的地址。

于 2012-09-05T18:22:44.380 回答