为何C语言中printf输出结构体成员取地址符后结果异常?

C语言(C99)声明结构体后,给里面加值,printf输出时多加了取地址符结果很奇怪,尝试复盘没想明白。

int main() {
//声明student 结构体
    struct student{
        int num;char name[20];char sex;
        int age;float score;char addr[30];
    };
    struct student s= {1001,"lele",'M',20,85.4,"Shenzhen"};
    //定义一个student类型的结构体s,同时初始化.
    struct student sarr[3];
    int i;
    printf("%d %s %c %d %f %s\n",s.num,s.name,s.sex,s.age,s.score,s.addr);
    for(i=0;i<1;i++){
        scanf("%d%s %c%d%f%s",&sarr[i].num,&sarr[i].name,&sarr[i].sex,
              &sarr[i].age,&sarr[i].score,&sarr[i].addr);
    }
    for(i=0;i<1;i++){
//下面是错掉的输出代码,为什么会犯错主要是因为复制粘贴了上面的一部分代码偷懒。
        printf("%d %s %c %d %f %s\n",&sarr[i].num,&sarr[i].name,&sarr[i].sex,
               &sarr[i].age,&sarr[i].score,&sarr[i].addr);
    }
    return 0;
}

测试用例
1002 Meme M 20 85.419998 SZ
不改动代码的输出结果为
6421760 Meme  6421788 0.000000 SZ
其中在Clion的输出框里显示的是个不认识的占位符
把取地址符全去了改成正确的,输出结果
1002 Meme M 20 85.419998 SZ
说明scanf应该没啥问题。
输出改为

    printf("%d %s %c %d %f %s\n",&sarr[i].num,&sarr[i].name,sarr[i].sex,
           sarr[i].age,&sarr[i].score,sarr[i].addr);

//保留了.num,.name,.score的取地址符,输出结果下面一行

          6421760 Meme M 20 0.000000 SZ

打断点后,发现&sarr[0].num 地址值61FD00,换算十进制刚好就是第一个输出结果6421760,也能拿到输进去的数字。
于是我用*&去看赋值有没有问题,发现赋值都没问题,.name的char数组存好了,.score也存到了输进去的分数。图片.png
再进一步我回头去看类型的时候注意到num是int型,&int或许是输出了他的地址,这个可以理解。但name是char型,&sarr[i].name结果输出的不是地址,而是我输进去的测试用例MeMe。&sarr[i].score输出的也不是地址,而是0.00000.
百科试着查了一下取地址符,查出来也就是知道C中&除了取地址还是按位运算的运算符,但还是想不通为什么在这个写错的printf输出里面&sarr[i].num 输出了地址,&sarr[i].name 输出了我想要的值,而&sarr[i].score输出了一个0.0000(可能是真的就按位运算输出了个0)。
猜测是&可能对于不同情况有不同的默认匹配,但是百度也没搜到c语言中的&具体是怎么实现的,求大佬们解惑。

阅读 819
1 个回答
✓ 已被采纳

使用printf函数输出结构体成员的值时,是否需要使用取地址符&取决于结构体成员的类型。

对于基本数据类型的成员(如int、float等),直接使用成员名即可,不需要取地址符。而对于数组名(如char数组),数组名本身就表示数组的首地址,也不需要再使用取地址符。

在你的代码中:

  • sarr[i].num是int类型,使用&取地址后输出的是该整数变量的地址。
  • sarr[i].name是char数组名,它本身就代表了数组的首地址,所以当你使用&sarr[i].name时,输出的实际上是数组的首地址,但printf函数在遇到%s格式说明符时,会将该地址视为字符串的起始地址,并按照字符串的方式进行输出,从而显示出你输入的字符串"Meme"。
  • 至于&sarr[i].score输出为0.0000,这是因为score是float类型,使用取地址符后得到的是float类型变量的地址。然而,printf函数使用%f格式说明符期望的是一个float类型的值,而不是地址。当你将地址作为%f的参数时,它会尝试将该地址所指向的内容解释为float类型的值,但由于该地址可能并不指向有效的float数据,或者解释出来的结果是未定义的,所以输出了一个奇怪的0.0000。

正确的方式:

printf("%d %s %c %d %f %s\n", sarr[i].num, sarr[i].name, sarr[i].sex,
       sarr[i].age, sarr[i].score, sarr[i].addr);

还是要去深入理解*&

顺着你的的描述写了这么多,也不知道有不有用。
给你推荐一个很不错的教程 C语言基础教程

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏