c - C 中的垃圾值

标签 c arrays pointers undefined-behavior implicit-conversion

我原以为第一个 printf() 语句会出现垃圾值,但我得到了地址。为什么?

#include<stdio.h>
int main()
{
    int (*p)[10];
    int a[10]={1,2,3,4,5,6,7,8,9,0};
    p=a+10;
    printf("%d\n",*(p));
    printf("%u",(p));
}

最佳答案

首先,此声明

p=a+10;

无效。

赋值左侧的类型为 int( * )[10] 而赋值右侧的类型为 int * 并且没有隐式从一种类型到另一种类型的转换。

你必须写

p = ( int( * )[10] )( a + 10 );

其次是printf的这些调用

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

具有未定义的行为,因为使用了无效的转换说明符 du 以及指针类型的参数,因为 *pp 都是指针。

因此,一个有效的程序可以如下所示

#include <stdio.h>

int main(void) 
{
    int (*p)[10];
    int a[10]={1,2,3,4,5,6,7,8,9,0};

    p = ( int( * )[10] )( a + 10 );

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

    return 0;
}

指针可以指向对象(或数组)最后一个元素后面的内存。

所以在这句话之后

p = ( int( * )[10] )( a+10 );

指针p指向一个想象的二维数组的第一个元素,其中的元素又是int[10]类型的一维数组,并且想象的二维数组的第一个元素对应于数组a

表达式*p也是一个指针。它的类型是 int * 因为表达式 *p 给出了 int[10] 类型的左值,并且在表达式中这个左值被隐式转换为指向其第一个元素的指针(在本例中的类型为 int)。

因此表达式 p*p 都指向相同的内存并具有相同的值。

程序输出证明了这一点

0x7ffcfd46ea48
0x7ffcfd46ea48

这两个指针 p*p 之间的区别在于它们可能指向的对象的类型。

考虑以下演示程序

#include <stdio.h>

int main(void) 
{
    int (*p)[10];
    int a[10]={1,2,3,4,5,6,7,8,9,0};

    p = ( int( * )[10] )( a+10 );

    printf("%zu\n",sizeof( *p ) );
    printf("%zu\n",sizeof( **p ) );

    return 0;
}

它的输出是

40
4

如果你这样写,你可能会得到未定义的行为

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

在本例中,表达式 **p 的类型为 int,并且可以访问数组 a 之外的内存。

关于c - C 中的垃圾值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57495601/

相关文章:

Java 对象数组在初始化期间崩溃

java - 是否可以在 lambda 表达式中迭代数组? (java)

c - 这是 + 运算符在 C 中的实现方式吗?

c - tcp ip 检查我遗漏了一些东西

c++ - C++中对数组的误解

c - union 成员如何拥有指向 union 实例的指针?

c - 取消引用指针

c - 如何从内核缓冲区打印字符串?我使用 copy_from_user() 对吗?

c - GCC编译源码和库

c++ - 当我尝试删除指针时我的程序崩溃了