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
会得到相同的结果吗?
在期待中感谢你。
答案 0 :(得分:3)
这是数组在C - 数组中工作的方式不是一流类型,因为除了声明它们并获得它们的大小之外,你不能对它们做任何事情。在任何其他上下文中,当您使用带有类型数组(任何内容)的表达式时,它会被静默转换为指向数组的第一个元素的指针。这通常被称为阵列"衰变"进入指针。
让我们一个一个地看你的陈述:
p = s[0];
这里,s
有数组类型(它是一个int[4][2]
- 一个2D int数组),所以它默默地转换为指向它的第一个元素的指针({{1} },指向包含int (*)[2]
)的单词。然后使用1234
对此进行索引,将[0]
字节添加到指针,然后取消引用它,为您提供0 * sizeof(int [2])
(1个数组,包含2个整数)。由于这是一个数组,它会无声地转换为指向其第一个元素的指针(指向int [2]
的{{1}})。请注意,这与索引之前的指针相同,只是指向的类型不同。
然后,您将此int *
分配给1234
,其被声明为int *
。由于C允许将任何指针指向任何其他指针(即使指向的类型不同),这也行,但任何合理的编译器都会给你一个类型不匹配的警告。
p
现在指向包含int (*)[1]
的单词(与p
指向的指针相同的位置)
1234
首先将s
添加到p并取消引用它,给出一个数组(int [1]),它立即衰减到指向其第一个元素的指针(printf("%d\n", *(*(p+0)));
仍然指向同一个地方) 。然后取消引用该指针,给出打印的int值0*sizeof(int[1])
。
int *
我们再次1234
通过第一行描述中提到的多重衰减和解除引用流程成为printf("%d\n", *(s[0]+0));
,指向s[0]
。我们向其添加int *
,然后取消引用,给出整数1234
。
0*sizeof(int)
1234
是一个指针,因此只需打印指针的地址。
printf("%u\n", p);
p
被解除引用,给出一个printf("%u\n",*p)
(1D整数数组),它衰变成指向其第一个元素的指针。然后打印该指针。
答案 1 :(得分:0)
s[0]
指向内存中的某个位置。该内存位置恰好是int s[4][2]
的起点。当您进行赋值p = s [0]时,p
和p+0
也指向s [0]。因此,当您使用“%d”说明符打印其中任何一个时,您将获得存储在该位置的值恰好为“1234”。如果您要验证所有这些地址是否相同,请使用格式说明符“%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 回答您的问题:所以我的问题是简单指针和指向数组的指针有什么区别?
请查看本教程的底部 download a 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个浮点数。请查看插图 HERE 。