当前位置: 首页 > 知识库问答 >
问题:

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

聂宜
2024-07-09

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语言中的&具体是怎么实现的,求大佬们解惑。

共有1个答案

蓝飞
2024-07-09

使用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语言基础教程

 类似资料:
  • 主要内容:结构体变量,成员的获取和赋值前面的教程中我们讲解了 数组(Array),它是一组具有相同类型的数据的集合。但在实际的编程过程中,我们往往还需要一组类型不同的数据,例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组为字符,成绩为小数,因为数据类型不同,显然不能用一个数组来存放。 在C语言中,可以使用 结构体(Struct)来存放一组不同类型的数据。结构体的定义形式为: struct 结构体名{    

  • C++ 运算符 .(点)运算符和 ->(箭头)运算符用于引用类、结构和共用体的成员。 点运算符应用于实际的对象。箭头运算符与一个指向对象的指针一起使用。例如,假设有下面的结构: struct Employee { char first_name[16]; int age; } emp; (.)点运算符 下面的代码把值 "zara" 赋给对象 emp 的 first_name 成员:

  • 运算符和表达式 运算符 C语言的运算范围很宽,把除了控制语句和输入/输出以外的几乎所有的基本操作都作为运算符处理。运算符主要分为三大类:算术运算符、关系逻辑运算符、按位运算符。根据运算符的运算对象的个数,C语言的运算符又可分成单目运算符、双目运算符、三目运算符。运算符具体分类情况如下表所示: C语言运算符 分类名称 运算符 算术运算符 +、-、*、/、% 关系运算符 <、>、<=、>=、==、!=

  • 主要内容:获取结构体成员,结构体指针作为函数参数当一个 指针变量指向结构体时,我们就称它为 结构体指针。 C语言结构体指针的定义形式一般为: struct 结构体名 *变量名; 下面是一个定义结构体指针的实例: 也可以在定义结构体的同时定义结构体指针: 注意,结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加 ,所以给 pstu 赋

  • 所谓 结构体数组,是指数组中的每个元素都是一个结构体。在实际应用中, C语言结构体数组常被用来表示一个拥有相同 数据结构的群体,比如一个班的学生、一个车间的职工等。 在C语言中,定义结构体数组和定义结构体变量的方式类似,请看下面的例子: 表示一个班级有5个学生。 结构体数组在定义的同时也可以初始化,例如: 当对数组中全部元素赋值时,也可不给出数组长度,例如: 结构体数组的使用也很简单,例如,获取

  • 本文向大家介绍简单总结C语言中的运算符优先级,包括了简单总结C语言中的运算符优先级的使用技巧和注意事项,需要的朋友参考一下 C语言中有很多运算符,除了四则运算,还有位运算、比较运算、逻辑运算、赋值运算等等,令人眼花缭乱的同时,优先级也让人头疼。通常建议在写代码的时候不用省略括号,但是并不是所有程序员都会按照这个规矩来,因此还是有必要记录一下,以备查阅。 总结几个比较重要的原则: 取成员的“0”目运