首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >‘`int *p’和‘`int (*p)[3]之间的差异?

‘`int *p’和‘`int (*p)[3]之间的差异?
EN

Stack Overflow用户
提问于 2022-02-22 07:19:28
回答 4查看 300关注 0票数 2
代码语言:javascript
复制
#include <stdio.h>

int main() {
    int arr[3] = { 1, 2, 3 };
    int *p = arr;
    int (*r)[3] = arr;
    
    printf("%u %u", p, r);
    printf("\n%d %d %d", p[0], p[1], p[2]);
    
    printf("\n%d %d %d", r[0], r[1], r[2]);
    printf("\n%d %d %d", *r[0], *r[1], *r[2]);
    printf("\n%d %d %d", (*r)[0], (*r)[1], (*r)[2]);
}

输出:

代码语言:javascript
复制
1483745184 1483745184
1 2 3
1483745184 1483745196 1483745208
1 0 -647513344
1 2 3

如您所见,pr包含相同的地址。

为什么p[0]

  • why工作,但r[0]不工作?

  • (*r)[0]工作,其他人不工作?

编辑:除了接受的答案,这个答案也是有帮助的https://stackoverflow.com/a/71218214/12491154

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2022-02-22 08:59:44

这两种声明之间的区别

代码语言:javascript
复制
int *p = arr;
int (*r)[3] = arr;

在第二个声明中,使用了错误的初始化器。用作初始化器的数组arr被隐式转换为指向其类型int *的第一个元素的指针。因此,在第二个声明中,初始化对象和初始化器有不同的指针类型,并且类型之间没有隐式转换。

要使第二个声明正确,您需要编写

代码语言:javascript
复制
int (*r)[3] = &arr;

现在,指针p和r存储相同的值:数组占用内存范围的地址,但类型不同。

例如,如果您要编写

代码语言:javascript
复制
printf( "sizeof( *p ) = %zu\n", sizeof( *p ) );
printf( "sizeof( *r ) = %zu\n", sizeof( *r ) );

然后,第一个调用将输出int类型的对象的大小,该对象的大小等于4,而第二个调用将输出等于12的类型int[3]的整个数组的大小。

在这里,你的呼唤,打印

代码语言:javascript
复制
printf("%u %u", p, r);

指针使用了不正确的转换说明符。相反,你必须写

代码语言:javascript
复制
printf("%p %p", ( void * )p, ( void * )r);

表达式r、r1、r2的类型为int3。在此调用中使用

代码语言:javascript
复制
printf("\n%d %d %d", r[0], r[1], r[2]);

如前所述,它们被隐式转换为指向其第一个元素的指针。但是,除了表示数组arr的数组r外,这些数组不存在。所以在数组arr之外进行内存访问,

你可以写

代码语言:javascript
复制
printf( "\n%p\n", ( void * )r[0] );

这个电话就相当于

代码语言:javascript
复制
printf("\n%p\n", ( void * )arr );

这是印刷品的呼唤

代码语言:javascript
复制
printf("\n%d %d %d", *r[0], *r[1], *r[2]);

也不正确,因为不存在类型为r[1]r[2]的数组int[3]

这是印刷品的呼唤

代码语言:javascript
复制
printf("\n%d %d %d", (*r)[0], (*r)[1], (*r)[2]);

由于使用表达式arr,因此输出数组*r的元素。

票数 2
EN

Stack Overflow用户

发布于 2022-02-22 08:39:54

rp之间的区别仅仅在于类型。

首先要注意的是,赋值int (*r)[3] = arr;是不正确的;赋值中的arr衰变到指向其第一个元素int的指针,这是一个与r不同的类型,后者是一个指向由三个int组成的数组的指针。诚然,C最初并不是那么挑剔,不同指针类型之间以及指针和整数之间的赋值并没有得到太多的考虑--都是数字,对吗?但是现代C为了更好的理由尝试更安全的类型,所以正确的分配应该是int (*r)[3] = &arr;:如果您想要数组的地址,只需取地址即可。您的代码“工作”,因为在数字上,第一个元素的地址是数组的地址。这是错误的类型,而不是价值。

现在让您感到困惑:正如您所注意到的,两者都指向相同的地址;但是p所指向的对象是一个简单的int (恰好后面是内存中的另外两个int,它们一起包含arr),而r则指向数组本身。

因此,*p的类型是int,而*r的类型是int[3],因此sizeof *r == 3 * sizeof *p保持不变。

如您所知,C在大多数情况下模糊了这种区别:例如,您可以合法地说是p = *r;,因为数组在赋值或参数初始化中对指向其第一个元素的指针进行了“调整”或“衰减”。

但对于sizeof,它们没有。这是因为索引会将index * sizeof(element)添加到指针的数值中;如果指针指向整个数组,比如r (而不是它的第一个元素,比如p),那么第二个元素将是下一个数组,它不存在--只有一个数组,所以程序出错了。

代码语言:javascript
复制
#include <stdio.h>
int main() {
    int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int (*r)[3] = arr;

    printf("%p %p\n", (void*)r[0], (void*)r[1]);
}

这个小程序说明了这一点。注意arr是如何再次衰变到其第一个元素的地址的;只是这一次,该二维数组的第一个元素是一个数组本身,由三个it组成,因此它非常适合。

票数 1
EN

Stack Overflow用户

发布于 2022-02-22 09:45:16

pr的类型非常不同:

  • p是指向int的指针,初始化为指向数组arr的第一个元素,
  • r是指向3int数组的指针:初始化不正确,应该是r = &arr.
  • printf("%u %u", p, r)有未定义的行为:%u希望使用unsigned int类型的参数,%p.
  • printf("\n%d %d %d", p[0], p[1], p[2])r是指针,应该转换为(void *),并与r转换为正确的指针,并产生1 2 3,因为p具有未定义的行为:r[0]r[1]衰变为指向int的指针,它们应该转换为(void *),并使用%p打印。behavior.
  • postfix是一个无效的指针:计算其值并将其作为参数传递给它时,未定义的r[2]一元运算符比前缀运算符绑定更强,因此解析为*(r[0])*r[0]与数组arr的第一个元素r[0][0]相同。相反,behavior.
  • conversely与r[1][0]等价,后者指的是无效区域,在arr结束后,*r[2]也是如此,因此,读取这两个原因导致的未定义的*r[1] (*r)[0](r[0])[0]相同,因此r[0][0]arr的第一个元素,而相似的(*r)[1]r[0][1]所以printf("\n%d %d %d", (*r)[0], (*r)[1], (*r)[2])输出1 2 3的情况相同,就像printf("\n%d %d %d", p[0], p[1], p[2]).

一样

pr (初始化为r = &arr)确实指向相同的位置,但它们有不同的类型,在编写代码时必须加以考虑。

以下是修改后的版本:

代码语言:javascript
复制
#include <stdio.h>

int main() {
    int arr[3] = { 1, 2, 3 };
    int *p = arr;
    int (*r)[3] = &arr;

    printf("arr: address %p,  sizeof(arr): %2zu bytes,  sizeof(*arr): %2zu bytes\n",
           (void *)arr, sizeof(arr), sizeof(*arr));
    printf("p:   address %p,  sizeof(p):   %2zu bytes,  sizeof(*p):   %2zu bytes\n",
           (void *)p, sizeof(p), sizeof(*p));
    printf("r:   address %p,  sizeof(r):   %2zu bytes,  sizeof(*r):   %2zu bytes\n",
           (void *)r, sizeof(r), sizeof(*r));

    printf("arr: %p,  arr+1: %p\n", (void *)arr, (void *)(arr + 1));
    printf("p:   %p,  p+1:   %p\n", (void *)p, (void *)(p + 1));
    printf("r:   %p,  r+1:   %p\n", (void *)r, (void *)(r + 1));

    printf("%d %d %d\n", p[0], p[1], p[2]);
    printf("%d %d %d\n", r[0][0], r[0][1], r[0][2]);
    printf("%d %d %d\n", (*r)[0], (*r)[1], (*r)[2]);

    return 0;
}

输出:

代码语言:javascript
复制
arr: address 0x7fff544137f8,  sizeof(arr): 12 bytes,  sizeof(*arr):  4 bytes
p:   address 0x7fff544137f8,  sizeof(p):    8 bytes,  sizeof(*p):    4 bytes
r:   address 0x7fff544137f8,  sizeof(r):    8 bytes,  sizeof(*r):   12 bytes
arr: 0x7fff544137f8,  arr+1: 0x7fff544137fc
p:   0x7fff544137f8,  p+1:   0x7fff544137fc
r:   0x7fff544137f8,  r+1:   0x7fff54413804
1 2 3
1 2 3
1 2 3
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71217293

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档