首页 > 解决方案 > C中的垃圾值

问题描述

我期待第一个 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));
}

标签: carrayspointersundefined-behaviorimplicit-conversion

解决方案


对于初学者来说,这个声明

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]并且在表达式中,该左值被隐式转换为指向其第一个元素的指针(在这种情况下为 type 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


推荐阅读