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

C语言fscanf使用[^ ]格式符时会自动处理\r回车符吗?

问题描述

我正在使用如下文本文件测试fscanf:

1 George Washington
2 John Adams
...
9 William Henry Harrison
...
46 Joseph R. Biden Jr.

使用如下struct:

struct president_of_united_state {
    unsigned char presidency;
    char president[23]; // 9. William Henry Harrison (22)
};

我想要理解搭配[^\n]使用时fscanf的行为:

void set_presidents_of_united_states(struct president_of_united_state *const p) {
    assert(p != NULL);
    static const char FILENAME_PRESIDENTS_OF_UNITED_STATES[] = "presidents_of_united_states.txt";
    FILE *stream = fopen(FILENAME_PRESIDENTS_OF_UNITED_STATES, "r");
    if (stream == NULL) {
        fprintf(stderr, "failed to open %s\n", FILENAME_PRESIDENTS_OF_UNITED_STATES);
        return;
    }
    for (int i = 0; i < NUMBER_OF_PRESIDENTS_OF_UNITED_STATES; i++) {
        int const n = fscanf(stream, "%hhu %22[^\n]", &p[i].presidency, p[i].president);
        assert(n == 2);
    }
    if (fclose(stream) == EOF) {
        fprintf(stderr, "failed to close the stream");
    }
}

当行分隔符仅为0a(\n)时:

3120 4765 6f72 6765 2057 6173 6869 6e67  1 George Washing
746f 6e0a 3220 4a6f 686e 2041 6461 6d73  ton.2 John Adams

程序运行符合预期,读取到的字符数组内容如下:

[7] = {char} 87 'W'
[8] = {char} 97 'a'
[9] = {char} 115 's'
[10] = {char} 104 'h'
[11] = {char} 105 'i'
[12] = {char} 110 'n'
[13] = {char} 103 'g'
[14] = {char} 116 't'
[15] = {char} 111 'o'
[16] = {char} 110 'n'
[17] = {char} 0 '\000'
[0] = {char} 74 'J'
[1] = {char} 111 'o'
[2] = {char} 104 'h'
[3] = {char} 110 'n'
[4] = {char} 32 ' '
[5] = {char} 65 'A'
[6] = {char} 100 'd'
[7] = {char} 97 'a'
[8] = {char} 109 'm'
[9] = {char} 115 's'
[10] = {char} 0 '\000'

当行分隔符为0d(\r)加0a(\n)时:

3120 4765 6f72 6765 2057 6173 6869 6e67  1 George Washing
746f 6e0d 0a32 204a 6f68 6e20 4164 616d  ton..2 John Adam

程序也正常运行,读取到的字符数组内容如下:

[7] = {char} 87 'W'
[8] = {char} 97 'a'
[9] = {char} 115 's'
[10] = {char} 104 'h'
[11] = {char} 105 'i'
[12] = {char} 110 'n'
[13] = {char} 103 'g'
[14] = {char} 116 't'
[15] = {char} 111 'o'
[16] = {char} 110 'n'
[17] = {char} 0 '\000'
[0] = {char} 74 'J'
[1] = {char} 111 'o'
[2] = {char} 104 'h'
[3] = {char} 110 'n'
[4] = {char} 32 ' '
[5] = {char} 65 'A'
[6] = {char} 100 'd'
[7] = {char} 97 'a'
[8] = {char} 109 'm'
[9] = {char} 115 's'
[10] = {char} 0 '\000'

我的问题是:fscanf是否自动忽略了\r字符?


解答

不是fscanf自动忽略了\r,这个效果来自C标准库文本模式打开文件的默认行为。
你调用fopen时使用了"r"模式,也就是文本读模式。在Windows平台下,文本模式会自动将磁盘上存储的\r\n换行序列转换为内存中的单个\n,所以读取操作完成后你在程序中完全看不到\r字符;反之如果是文本写模式,库也会自动将程序输出的\n转换为磁盘上的\r\n存储。
如果想要原样读取文件的所有字节,需要使用二进制模式打开文件,也就是把fopen的第二个参数改为"rb",这时你就会读取到\r字符,现有格式化字符串%hhu %22[^\n]会把\r也读进president数组的末尾,和现在的运行结果就会有差异。
另外补充:你当前代码的格式化字符串读完[^\n]后会停在\n的位置,下一次循环%hhu前面的空格会自动跳过所有空白字符(包括\n),所以可以正常读取下一行的序号,这个逻辑是符合预期的。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 04:06:04