You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取文件时strcmp对比相同字符串失效问题排查

问题根因

你遇到的两个异常是同一个根因连锁导致的,最高概率触发点按优先级排序:

  1. fscanf读取带空格的tdeeprint字段时错误使用了%s格式符:%s的读取规则是遇到任意空白字符(空格、换行、制表符)就终止,而字段值"Jarang Berolahraga"本身包含空格,实际只会把"Jarang"读入tdeeprint变量,剩余的"Berolahraga"会留在输入流中被后续读取逻辑当成下一个字段解析,直接造成所有后续字段读取错位——这也是你直接读TDEE浮点数始终拿不到正确值的核心原因。至于你打印tdeeprint看到完整字符串,大概率是结构体定义时tdeeprint数组后紧挨着其他内存区域,printf扫到连续内存里的内容刚好凑出了完整串,但实际字符串早就读断、内存已经越界。
  2. 字符串尾部携带不可见空白字符:Windows环境下文本文件默认用\r\n作为换行符,如果读取时没有过滤,tdeeprint尾部很可能残留\r(回车符,ASCII码0x0D)或者尾部空格、换行符。这类字符打印时完全不可见,但strcmp是逐字节严格比较,只要多一个不可见字符就会判定不相等,所有匹配分支自然全部未命中。
  3. 浮点数读取格式符与变量类型不匹配:fscanf读取float类型需要用%f,读取double类型必须用%lf,如果搞混格式符,读出来的浮点值会完全错乱,甚至直接得到0。
  4. 没有校验fscanf返回值:fscanf会返回成功读取的字段个数,未做这个校验的情况下,字段读错位、读失败了也继续往下跑逻辑,自然得到全错的结果。
修复方案

按以下步骤调整代码即可解决问题:

  • 替换字符串读取逻辑:带空格的结构化字段绝对不能用%s读取,要根据文件的字段分隔符用扫描集格式,同时必须加长度限制防止缓冲区溢出。比如字段用逗号分隔、tdeeprint字符数组长度为64,就用%63[^,]作为格式符,意思是最多读63个字符、遇到逗号就停止,刚好能把带空格的完整字段读进来,留1位给字符串结束符\0。
  • 每次读取后清理输入流残留分隔符:读完一个字段后,用fgetc或者格式串里加%*c吃掉流里残留的逗号、回车、换行符,避免分隔符被读入下一个字段。
  • 字符串比较前做清洗:写个简单的trim函数,把读入的tdeeprint首尾所有空白字符(空格、\t、\r、\n)全部截断,再拿去和常量字符串做strcmp比较,从根源避免不可见字符导致的匹配失败。
  • 修正浮点数读取格式:根据TDEE变量的实际类型选对格式符,double类型必须用%lf读。
  • 强制校验fscanf返回值:每次调用fscanf后判断返回值是否等于你预期读取的字段总数,如果不相等直接打印错误信息退出,不要继续执行后续逻辑,避免错位数据导致更离谱的异常。
参考实现代码
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define BUF_SIZE 64
// 按需补全你自己的结构体字段
typedef struct {
    char tdeeprint[BUF_SIZE];
    double tdeenum;
    double tdee_val;
} UserData;

// 去除字符串首尾空白字符
void str_trim(char *s) {
    if (!s) return;
    int len = strlen(s);
    // 清尾部空白
    while (len > 0 && isspace((unsigned char)s[len-1])) {
        s[--len] = '\0';
    }
    // 清头部空白
    char *start = s;
    while (*start && isspace((unsigned char)*start)) {
        start++;
    }
    memmove(s, start, strlen(start) + 1);
}

int main() {
    FILE *fp = fopen("test.txt", "r");
    if (!fp) {
        perror("打开test.txt失败");
        return 1;
    }

    UserData user = {0};
    // 示例为逗号分隔的CSV格式,根据你实际的文件分隔符调整格式串
    // 这里示例读2个字段:tdeeprint字符串、TDEE浮点值,按你实际字段数改
    int read_cnt = fscanf(fp, "%63[^,],%lf", user.tdeeprint, &user.tdee_val);
    // 校验读取成功的字段数,这里预期是2,按实际字段数调整
    if (read_cnt != 2) {
        printf("文件格式错误,仅成功读取%d个字段\n", read_cnt);
        fclose(fp);
        return 1;
    }

    // 清洗字符串
    str_trim(user.tdeeprint);

    // 再做分支匹配
    if (strcmp(user.tdeeprint, "Jarang Berolahraga") == 0) {
        user.tdeenum = 1.2; // 替换成你实际对应的系数值
    } else if (strcmp(user.tdeeprint, "其他活动等级字符串") == 0) {
        user.tdeenum = 1.55;
    } // 补全其余分支

    printf("活动等级:%s\n活动系数:%lf\nTDEE值:%lf\n", 
           user.tdeeprint, user.tdeenum, user.tdee_val);

    fclose(fp);
    return 0;
}
快速排查技巧
  • 遇到字符串打印正常但strcmp匹配失败的情况,第一时间打印两个字符串的长度:printf("读入串长度:%zu,常量串长度:%zu\n", strlen(tdeeprint), strlen("Jarang Berolahraga")),如果长度不一致,100%是读入串带了隐藏字符。
  • 浮点数读取异常优先排查两个点:一是前面的字符串读取是否错位把浮点内容读走了,二是fscanf的格式符和变量类型是否匹配。

内容的提问来源于stack exchange,提问作者LearnerC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:33:16