如何指向数组的指针?

int s[4][2] = { {1234, 56}, {1212, 33}, {1434, 80}, {1312, 78} }; int (*p)[1]; p = s[0]; printf("%d\n", *(*(p + 0))); // 1234 printf("%d\n", *(s[0] + 0)); // 1234 printf("%u\n", p); // 1256433(address of s[0][0]) printf("%u\n", *p); // 1256433(address of s[0][0]) 

任何人都可以解释为什么做*(*(p + 0))打印1234 ,做*(s[0] + 0)也打印1234 ,当p = s[0] ,为什么p*p给出相同的结果?

感谢你在期待。

这是数组在C中工作的方式 – 数组不是第一类类型,因为除了声明它们并获得它们的大小之外,你不能对它们做任何事情。 在任何其他上下文中,当您使用带有类型数组(任何内容)的表达式时,它会以静默方式转换为指向数组第一个元素的指针。 这通常被称为“衰减”到指针中的数组。

所以让我们逐一看看你的陈述:

 p = s[0]; 

这里, s有数组类型(它是一个int[4][2] – 一个2D int数组),所以它默默地转换为指向它的第一个元素的指针(一个int (*)[2] ,指向包含的单词1234 )。 然后使用[0]对此进行索引,将0 * sizeof(int [2])个字节添加到指针,然后取消引用它,给出一个int [2] (1个数组为2个整数)。 由于这是一个数组,它默默地转换为指向其第一个元素的指针(指向1234int * )。 请注意,这与索引之前的指针相同,只是指向的类型不同。

然后将此int *赋给p ,它被声明为int (*)[1] 。 由于C允许将任何指针指向任何其他指针(即使指向的类型不同),这也行,但任何合理的编译器都会给出类型不匹配警告。

p现在指向包含1234的单词(从s指向的指针所在的位置相同)

 printf("%d\n", *(*(p+0))); 

这首先将0*sizeof(int[1])到p并取消引用它,给出一个数组(int [1]),它立即衰减到指向其第一个元素的指针(一个int *仍然指向同一个地方)。 然后取消引用该指针,给出打印的int值1234

 printf("%d\n", *(s[0]+0)); 

我们再次使用s[0] ,其通过在第一行的描述中提到的多重衰减和解除引用过程变为指向1234int * 。 我们向它添加0*sizeof(int) ,然后取消引用,给出整数1234

 printf("%u\n", p); 

p是一个指针,因此只需打印指针的地址。

 printf("%u\n",*p) 

p被解除引用,给出一个int [1] (1D整数数组),它衰减成指向其第一个元素的指针。 然后打印该指针。

s[0]指向内存中的某个位置。 那个记忆位置恰好是int s[4][2]的起点。 当你进行赋值p = s [0]时, pp+0也指向s [0]。 因此,当您使用“%d”说明符打印其中任何一个时,您将获得存储在该位置的值恰好为“1234”。 如果要validation所有这些地址是否相同,请使用格式说明符“%p”而不是“%d”。

编辑解决OP评论问题…

以下是使用您自己的int **的示例:

首先,C使用指针 。 只有指针。 没有数组。 []表示法给出了数组的外观,但是使用[]表示法创建的任何变量(例如int s[4][2] )都被解析为一个简单的指针(例如int **s )。 此外,指针指针仍然只是一个指针。

int a[8]={0}; (或int * a然后malloced)在内存中看起来会一样:
int a[2][4]; (或** a = 0;然后是malloced)

声明:
s[row][col] = 1;
创建相同的对象代码
*(*(s + row) + col) = 1;

这也是事实

s [row] == *(s + row)

由于s[row]解析为指针,因此*(s + row)

由此得出s[0] == *(s + 0) == *s

如果这三个相等,则在打印时将显示该地址保持的值。

在你的代码中如下:假设你已经分配了p = s [0]; 和s [0] == * s

 *(*(p + 0)) == *(s[0] + 0) == *s[0] == **s printf("%d\n", >>>fill in any one<<<); //will result in 1234 

请注意,在以下printf语句中,您的注释表示已打印地址。 但是因为你使用了unsigned int格式说明符“%u”,

 Consider p == s[0]; which is a pointer to the first location of s. Note that either s[0][0] or **s would give you the value held at the first location of s, but s[0] is the _address_ of the first memory location of s. Therefore, since p is a pointer, pointing to the address at s[0], the following will give you the address of p, or s[0] (both same): printf("%p\n", *p); // 1256433(address of s[0][0]) 

至于* p,p被创建为int(* p)[1]; 和1个元素的指针数组。 一个数组被解析成一个指针,所以再次,在下面你将获得指向s [0]的地址:

 printf("%u\n", **p); 

总之 ,p和* p都是指针。 两者都会在打印时产生地址。

编辑2回答你的问题: 所以我的问题是简单指针和指向数组的指针有什么区别?

查看本教程的底部下载pdf 。 它可以解释得更好......

但简而言之,C不像其他语言那样实现数组 。 在C中,任何数据类型的数组总是解析为指针。 int a[10]; 真的是int *a; ,留出空间以便连续保存10个整数。 在内存中它看起来像:

a [0] a [9] | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | (如果所有都初始化为零)

同样,你会想到float b[2][2][2]; 作为一个三维数组:2x2x2,它不是。 它实际上是内存中的一个位置,从b[0] ,有8个浮点数。 看看这里的插图。