在第6行,而不是multiArray[0],当我写multiArray时,程序仍然可以工作。不明白为什么。我之前认为multiArray是指向multiArray[0]的指针,它是指向multiArray[0][0]的指针。因此,multiArray本身就是一个指向指针的指针。multiArray[0]是一个指向4元素int数组的指针。看来multiArray和multiArray[0]肯定不一样。但在下面的代码中,两者都有效。我编写的Print函数需要一个指向4元素int数组的指针。因此,只有multiArray[0]必须工作,而multiArray不能工作。但两者都有效。我不明白。
#include <stdio.h>
void printArr(int(*ptr)[4]);
int i, k;
int main(void){
int multiArray[3][4] = { { 1, 5, 2, 4 }, { 0, 6, 3, 14 }, { 132, 4, 22, 5 } };
int(*point)[4] = multiArray[0];
for (k = 0; k < 3; k++)
{
printArr(point++);
}
getchar();
}
void printArr(int(*ptr)[4]){
int *temp = (int *)ptr;
for (i = 0; i < 4; i++)
{
printf("%d ", *temp);
temp++;
}
puts("n");
}
还有人写过"多维数组是1-D数组的语法糖"。
这有点像说int
只是unsigned char[4]
的句法糖。您可以去掉像4 + 5
这样的表达式,并通过操作4字节的数组来获得相同的结果。
如果你想进一步理解这个概念,你甚至可以说C只是通用图灵机脚本的语法糖。
事实上,多维数组是C中类型系统的一部分,它们有与之相关的语法。剥猫皮的方法不止一种。
接下来,C排列我们称之为多维数组的方式是:"数组只能有一个维度,但元素类型本身可能是另一个数组"。我们说"多维数组"是为了方便,但语法和类型系统实际上反映了数组的一维性质。
因此,int multiArray[3][4]
是一个由3个元素组成的数组。这些元素中的每一个都是4个CCD_ 5的阵列。
在内存中,一个数组的元素是连续存储的,而不管元素类型是什么。因此,内存布局是一个4个int
的数组,紧接着是另一个4 int
的数组,最后是另一组4 int
的数组。
内存中有12个连续的int
,在C型系统中,它们被分为3组,每组4个。
您将注意到,12的第一个int
是,也是第一组4的第一个int
。这就是为什么我们发现,如果我们问"第一个int的内存位置是什么?"、"第一组4 int的内存地址是什么??"one_answers"整个12 int组的内存位置如何?",我们每次都会得到相同的答案。(在C中,多字节对象的内存位置被认为从其第一个字节的位置开始)。
现在,我们来谈谈指针语法和表示。在C中,指针告诉您在内存中的什么位置可以找到对象。这有两个方面:对象的内存位置,以及它是什么类型的对象。(对象的大小是类型的必然结果)。
有些演示只关注其中的第一个,他们会说"指针只是一个数字"之类的话。但这就是忘记了类型信息,而类型信息是指针的关键部分。
使用%p
打印指针时,会丢失类型信息。你只是把第一个字节在内存中的位置放出来。因此,它们看起来都是一样的,尽管三个指针指向不同大小的物体(它们像马特鲁斯卡娃娃一样相互重叠)。
在C的大多数实现中,类型信息都是在编译时计算的,所以如果你试图通过比较源代码和汇编代码来理解C(有些人这样做),你只会看到指针的内存位置部分。如果您忘记了类型信息也是至关重要的,这可能会导致误解。
脚注:所有这些都独立于C的一些语法怪癖;这些年来引起了很多混乱(但有时也很有用)。如果x
是数组,则表达式x
是&x[0]
的快捷方式,但用作&
或sizeof
的操作数时除外。(否则,这将是一个递归定义!)。第二个怪癖是,如果你在函数形式参数列表中写一个看起来像数组声明符的东西,实际上就像你写了一个指针声明符。我再次强调,这些只是语法上的奇怪之处,它们并没有说明数组和指针的本质,实际上并没有那么复杂。如果没有这两种怪癖,这种语言也同样有效。
多维数组var_t arr[size_y][size_x]
提供了以方便的方式声明和访问数组元素(内存)的方法。但所有的多维校正阵列都是内部连续的存储块。
你可以说arr[y][x] = arr[y*cols+x]
。
就指针级别而言,指针multiArray
和multiArray[0]
是相同的,它们是int*
——尽管arr的形式类型将是int (*)[2]
。使用该类型将允许利用所有指针机制(此类指针上的++将使地址移动8个字节,而不是4个字节)。
试试这个:
void t1(int* param)
{
printf("t1: %dn", *param);
}
void t2(int** param)
{
printf("t2: %dn", **param);
}
int main(void) {
int arr[2][2] = { { 1, 2 } , { 3, 4 } };
t1(arr); // works ok
t1(arr[0]); // works ok
t2(arr); // seg fault
t2(arr[0]);
}
int(*point)[4] = multiArray[0];
这是因为multiArray[0]
和multiArray
都指向相同的地址,即数组的第一个元素的地址:multiArray[0][0]
。
然而,在这种情况下,您可能会收到编译器的警告,因为multiArray[0]
的类型是int*
,而point
的类型是int [4]*
(指向4
整数数组的指针)。