在第6行而不是multiArray [0],当我编写multiArray时,程序仍然有效。不明白为什么。我之前想过,multiArray是一个指向multiArray [0]的指针,它是指向multiArray [0] [0]的指针。所以multiArray就是一个指向指针的指针。 multiArray [0]是指向4个元素int数组的指针。所以似乎multiArray和multiArray [0]必须是不同的。但是在下面的代码中,两者都有效。我写的打印函数需要一个指向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");
}
答案 0 :(得分:3)
其他人写道“多维数组是1-D数组的语法糖”。
这有点像说int
只是unsigned char[4]
的语法糖。您可以取消像4 + 5
这样的表达式,并通过操作4个字节的数组来获得相同的结果。
如果你想进一步理解这个概念,你甚至可以说C只是Universal Turing Machine脚本的语法糖。
现实情况是,多维数组是C中类型系统的一部分,并且它们具有与之相关的语法。皮肤猫的方法不止一种。
接下来,C安排我们称之为多维数组的方式是:“数组只能有一个维度,但元素类型本身可能是另一个数组”。我们说“多维数组”是为了方便,但语法和类型系统实际上反映了数组的一维性质。
因此,int multiArray[3][4]
是一个包含3个元素的数组。每个元素都是4 ints
的数组。
在内存中,数组的元素是连续存储的 - 无论元素类型是什么。因此,内存布局是一个4 int
的数组,紧接着是另一个4 int
数组,最后是另一个4 int
数组。
内存中有12个连续int
,在C类型系统中,它们分为3组,每组4个。
您会注意到,12中的第一个int
也第一组4中的第一个int
。这就是为什么我们发现如果我们问“第一个int的内存位置是什么?“,”第一组4个整数的内存位置是什么?“,”整个12个整数组的内存位置是多少?“,我们得到相同的答案每次。 (在C中,多字节对象的内存位置被认为是从其第一个字节的位置开始的。)
现在,谈谈指针语法和表示。在C中,指针告诉您在内存中可以找到对象的位置。这有两个方面:对象的内存位置,以及它的对象类型。 (对象的大小是类型的推论)。
有些演讲只关注第一部分,他们会说“指针只是一个数字”。但这就是忘记了类型信息,这是指针的关键部分。
使用%p
打印指针时,会丢失类型信息。你只是在第一个字节的内存中输出位置。所以它们看起来都一样,尽管三个指针指向不同大小的物体(它们像matruskha娃娃一样重叠)。
在C的大多数实现中,类型信息都是在编译时计算的,所以如果你试图通过比较源代码和汇编代码来理解C(有些人这样做),你只能看到内存位置的一部分。指针。如果您忘记了类型信息也很重要,这可能会导致误解。
脚注:所有这些都与C所具有的几个语法怪癖无关;这些年来引起了很多混乱(但有时也很有用)。如果x
是数组,则表达式&x[0]
是x
的快捷方式,除非用作&
或sizeof
的操作数。 (否则这将是一个递归定义!)。第二个怪癖是,如果你在函数形式参数列表中编写类似于数组声明符的内容,实际上就好像你编写了一个指针声明符。我再次强调这些只是语法怪异,他们并没有说任何关于数组和指针的本质的基本原理,实际上并没有那么复杂。如果没有这两种怪癖,这种语言也会起作用。
答案 1 :(得分:1)
多维数组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: %d\n", *param);
}
void t2(int** param)
{
printf("t2: %d\n", **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]);
}
答案 2 :(得分:0)
int(*point)[4] = multiArray[0];
这是有效的,因为multiArray[0]
和multiArray
都指向相同的地址,即数组的第一个元素的地址:multiArray[0][0]
。
但是在这种情况下,您可能会收到编译器的警告,因为multiArray[0]
的类型为int*
而point
的类型为int [4]*
(指向{{1的数组的指针)整数)。