如何指向数组的指针?

时间:2014-06-27 19:04:23

标签: c pointers

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)同时打印1234p = s[0]以及为什么p*p会得到相同的结果吗?

在期待中感谢你。

2 个答案:

答案 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]时,pp+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