You need to enable JavaScript to run this app. 指针与struct练习中,通过struct指针传参,用fgets+strtof替代scanf为float成员赋值出现段错误
优惠活动
大模型
产品
解决方案
定价
更多

指针与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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 19:15:05