如何指向数组的指针?
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个整数)。 由于这是一个数组,它默默地转换为指向其第一个元素的指针(指向1234
的int *
)。 请注意,这与索引之前的指针相同,只是指向的类型不同。
然后将此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]
,其通过在第一行的描述中提到的多重衰减和解除引用过程变为指向1234
的int *
。 我们向它添加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]时, p
和p+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个浮点数。 看看这里的插图。