C语言结构体数组填充逻辑移至main函数的实现及scanf的&使用规则
程序运行异常的修复方案
当前代码存在的具体问题
- 循环变量
i未在main函数作用域内声明,编译阶段就会直接报错,属于基础语法错误 - 循环内传入函数的地址没有做对应偏移:三次循环都把数组首地址
std传给getDetail,不管循环执行多少次,永远只会给数组的第一个元素赋值,剩下两个学生的存储空间从来没有被写入 getDetail函数内部的ptr++是无效操作:C语言的函数参数是值传递,函数内对形参ptr做的自增修改,只会影响函数内部的局部变量副本,完全不会影响外面传入的实参,在你当前的设计下这段代码属于旧逻辑遗留,没有任何作用- 最初参考的示例代码末尾多写了一个闭合大括号
},存在语法错误
调整后的可正常运行的代码
#include <stdio.h> // 学生结构体定义 struct student { char id[15]; char firstname[64]; char lastname[64]; float points; }; // 函数声明 void getDetail(struct student *); int main(void) { // 存储3个学生信息的结构体数组 struct student std[3]; int i; // 显式定义循环变量i for (i = 0; i < 3; i++) { printf("Enter detail of student #%d\n", (i + 1)); // 传入当前遍历位置的学生结构体地址,等价于 std + i getDetail(&std[i]); } return 0; } // 函数定义:仅负责给传入的单个结构体填充用户输入的信息 void getDetail(struct student *ptr) { printf("Enter ID: "); scanf("%s", ptr->id); printf("Enter first name: "); scanf("%s", ptr->firstname); printf("Enter last name: "); scanf("%s", ptr->lastname); printf("Enter Points: "); scanf("%f", &ptr->points); }
scanf参数中
&的使用规则 scanf的核心要求是:必须拿到目标存储位置的内存地址,才能把用户输入的值写入到对应的内存空间,要不要加&,完全看你传入的表达式本身是不是已经代表了内存地址。
- 读取数组成员(比如
id、firstname、lastname)时不需要加&:
C语言中,数组名作为普通表达式使用时,会自动隐式转换为指向数组首元素的指针,本质就是一个地址值。比如ptr->id本身就等价于&ptr->id[0],已经满足scanf对参数的地址要求,不需要额外加取地址符。 - 读取非数组的标量成员(比如
points)时必须加&:points是普通的浮点类型变量,直接写ptr->points拿到的是这个变量存储的浮点数值,而不是它的内存地址。scanf无法通过值定位到要写入的内存位置,必须加上&取地址,把points的内存位置传给scanf,才能正确完成输入写入。
注意:不要混淆数组首元素地址和整个数组地址的区别。虽然
ptr->id(首元素地址)和&ptr->id(整个数组的地址)的数值是完全一样的,但二者类型不同,直接写数组名是和scanf的字符串读取要求完全匹配的正确写法。
内容的提问来源于stack exchange,提问作者pingu
相关产品推荐
相关产品推荐

