指针与struct练习中,通过struct指针传参,用fgets+strtof替代scanf为float成员赋值出现段错误
段错误根因定位
核心错误点
- 输入缓冲区定义不匹配
原代码中char pNum[] = {0};初始化的字符数组仅占1字节栈空间,而后续fgets(pNum, SIZE, stdin)需要向该缓冲区最多写入49字节内容,直接触发栈缓冲区溢出,破坏栈上函数返回地址等关键数据,这是触发段错误的直接原因。正确的定义方式是明确指定缓冲区长度,与fgets的读取参数匹配,即写成char pNum[SIZE] = {0};。 strtof参数使用错误strtof()的第二个形参是指向字符指针的地址,用于存储转换结束时的字符位置,仅需要传入已定义的指针变量的地址即可,完全不需要提前用malloc()为其分配堆内存。原代码中为pEnd申请堆内存的操作既无实际作用,还会造成永久性的堆内存泄漏(申请的内存永远不会被释放)。- 无效判断逻辑
main函数中pItem = &product;是取栈上局部变量的地址,该地址属于栈空间的有效地址,不可能为NULL,后续的空指针判断属于完全无效的冗余逻辑,不影响程序运行但没有实际防护作用。
之前转换尝试失败的原因
此前使用atof()、atoi()等函数转换失败,本质原因不是转换函数本身存在缺陷,而是fgets写入输入缓冲区时已经发生了栈溢出,程序在缓冲区溢出阶段就已经崩溃,根本走不到后续的类型转换环节。
修正后的可运行代码
#include <stdio.h> #include <stdlib.h> #include <ctype.h> struct Stock { float cost; }; #define SIZE 50 void ReadIn(struct Stock *purchase); void PrintOut(struct Stock *receipt); int main () { struct Stock product; struct Stock *pItem = &product; ReadIn(pItem); PrintOut(pItem); return 0; } //---- Function Definitions ----// void ReadIn(struct Stock *purchase) { // 明确指定缓冲区大小,匹配fgets的读取长度 char pNum[SIZE] = {0}; // 直接定义指针变量,不需要堆内存申请 char *pEnd = NULL; printf("\nEnter the price: "); fgets(pNum, SIZE, stdin); // 执行字符串到float的转换 purchase->cost = strtof(pNum, &pEnd); // 可选校验:判断是否成功读取到有效数值 if (pEnd == pNum) { printf("警告:输入内容不是有效数字,价格将置为0\n"); purchase->cost = 0.0f; } } void PrintOut(struct Stock *receipt) { printf("\nPrice: %.2f\n", receipt->cost); }
补充优化方向
- 读取输入后可手动剔除fgets带入的末尾换行符,避免后续字符串处理出现意外干扰
- 可增加输入长度校验,避免用户输入过长内容时,剩余字符残留在输入缓冲区影响后续读取操作
内容的提问来源于stack exchange,提问作者Den
相关产品推荐
相关产品推荐

