请考虑以下2-D阵列:
int array[2][2] = {
{1,2},
{3,4}
};
根据我的理解: - 'array'表示二维数组的基地址(与数组的第一个元素的地址相同,即数组[0] [0])。
内存中二维数组的实际安排就像一个大型的一维数组。
现在,我知道base address = array。因此,我应该能够到达包含元素的内存块:array [0] [0]。
如果我忘记了2-D阵列的事情&尝试将此数组视为一个简单的1-D数组: array [0] = *(array + 0)给出第一个数组的基地址&不是元素数组[0] [0]。为什么呢?
2-D数组不存储任何内存地址(如指针数组)。
如果我知道基地址,我必须能够以线性1-维数组的形式访问此内存。
请帮我澄清这个疑问。
感谢。
答案 0 :(得分:5)
“你不要害怕激素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]
这就是为什么它最终有效。
答案 1 :(得分: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]
和(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-------------------------'
答案 2 :(得分:3)
内存中二维数组的实际安排就像一个大型的一维数组。
是的,存储区域就像1D arrary一样是连续的。但索引方法略有不同。2-D[0][0] = 1-D[0]
2-D[0][1] = 1-D[1]
...
2-D[i][j] = 1-D[ i * rowsize + j]
...
如果我忘记了2-D阵列的事情&amp;尝试将此数组视为一个简单的1-D数组:array [0] = *(array + 0)给出第一个数组的基地址&amp;不是元素数组[0] [0]。为什么呢?
*(array + 0)表示指向数组的指针。这种格式的第一个元素索引应该是*((* array + 0)+0)。
所以最后它应该是*(* array)
二维数组不存储任何内存地址(如指针数组)。 当然可以 。例如,
int * array[3][3] ={ null, };
如果我知道基地址,我必须能够以线性1-维数组的形式访问此内存。
使用这个正式的2-D [i] [j] = 1-D [i * rowsize + j] ......
答案 3 :(得分:1)
数组不是指针。
在大多数情况下 1 ,类型为“{-1}}的N元素数组”的表达式将被转换(“衰变”)为表达式输入“指向T
的指针”,表达式的值将是数组第一个元素的地址。
表达式 T
的类型是“array
的2元素数组的2元素数组”。根据上面的规则,在大多数情况下,这将衰减为“指向int
(int
}的2元素数组。这意味着表达式int (*)[2]
的类型(并通过扩展名) ,*array
和*(array + 0)
)是“array[0]
的2元素数组”,而后者将衰减为int
类型。
因此,int *
会在*(array + i)
之后为您提供i
' 2元素数组int
(即,第一个int的元素数组位于array
(array[0]
),而*(array + 0)
的第二个2元素数组位于int
(array[1]
)。
如果你想将*(array + 1)
视为array
的一维数组,你必须按照
int
或
int *p = (int *) array;
int x = p[0];
<小时/> 1。例外情况是数组表达式是
int x = *((int *) array + 0);
或一元sizeof
运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字。
答案 4 :(得分: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和指针本身的地址。