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

C语言中fgetc与&&、||运算符的正确使用问询

关于fgetc与逻辑运算符结合的常见问题解答

嘿,我来帮你拆解这些fgetc和&&、||运算符搭配时的坑,这些都是C文件操作里很容易踩的点!

1. 两次调用fgetc时会给ch赋值两次吗?

当然会!而且这正是你最初输出异常的核心原因。举个例子,假设你写了这样的循环条件:

char ch; // 注意:这里应该用int,后面会说原因
while ((ch = fgetc(fp1)) != EOF && (ch = fgetc(fp2)) != EOF) {
    putchar(ch);
}

这里的&&是短路求值:先执行左边的ch = fgetc(fp1),判断是否不等于EOF。如果成立,才会执行右边的ch = fgetc(fp2)——这时候ch会被fp2的字符覆盖,而且两次fgetc调用会分别消耗fp1和fp2的一个字符,等于你每次循环跳过了fp1的一个字符,只输出fp2的内容,自然会出现输出异常。

如果是||的情况,比如:

while ((ch = fgetc(fp1)) != EOF || (ch = fgetc(fp2)) != EOF) {
    putchar(ch);
}

短路求值同样生效:左边为真时(fp1没到EOF),右边的fgetc(fp2)完全不会执行,所以你会先把fp1的所有字符读完,才开始读fp2的字符。而如果ch是char类型,当读到EOF时,-1会被转成无符号的255,输出就是你看到的“垃圾字符”。

2. 如何正确结合&&运算符使用fgetc?

&&的逻辑是“两个条件都满足才继续循环”,对应到合并文件的场景,应该是每次循环同时读取两个文件的一个字符,直到其中一个文件到EOF,之后再处理剩下的字符。

正确的写法需要用两个变量分别存储两个文件的字符,避免覆盖,同时必须把变量定义为int(因为fgetc返回int类型,包含EOF的-1,用char会丢失EOF的判断):

#include <stdio.h>

int main() {
    FILE *fp1 = fopen("file1.txt", "r");
    FILE *fp2 = fopen("file2.txt", "r");
    if (!fp1 || !fp2) {
        perror("Failed to open file");
        return 1;
    }

    int ch1, ch2;
    // 同时读两个文件,直到其中一个到EOF
    while ((ch1 = fgetc(fp1)) != EOF && (ch2 = fgetc(fp2)) != EOF) {
        putchar(ch1);
        putchar(ch2);
    }

    // 处理fp1剩余的字符
    while ((ch1 = fgetc(fp1)) != EOF) {
        putchar(ch1);
    }
    // 处理fp2剩余的字符
    while ((ch2 = fgetc(fp2)) != EOF) {
        putchar(ch2);
    }

    fclose(fp1);
    fclose(fp2);
    return 0;
}

这里的逻辑很清晰:先交替读取两个文件的字符,当其中一个文件读完后,再把另一个文件剩下的内容全部输出。

3. 如何正确结合||运算符使用fgetc?

||的逻辑是“只要有一个条件满足就继续循环”,对应到合并文件的场景,应该是只要任意一个文件还有字符,就继续读取输出(比如交替读取直到两个都读完,或者先读完第一个再读第二个)。

先解决你遇到的两个问题:

  • 两次调用fgetc出现垃圾字符:大概率是因为你把ch定义成了char,而不是int。EOF是-1,当用无符号char存储时会变成255,输出就是乱码,所以必须用int来接收fgetc的返回值。
  • 单次调用出现无限循环:应该是你的写法错误,比如没有正确标记文件是否读完,导致重复读取EOF进入死循环。

正确的写法可以用标记位跟踪每个文件的状态,避免短路求值导致的漏读:

#include <stdio.h>

int main() {
    FILE *fp1 = fopen("file1.txt", "r");
    FILE *fp2 = fopen("file2.txt", "r");
    if (!fp1 || !fp2) {
        perror("Failed to open file");
        return 1;
    }

    int ch;
    int fp1_eof = 0, fp2_eof = 0;

    // 只要有一个文件没读完就继续循环
    while (!fp1_eof || !fp2_eof) {
        if (!fp1_eof) {
            ch = fgetc(fp1);
            if (ch == EOF) {
                fp1_eof = 1;
            } else {
                putchar(ch);
            }
        }
        if (!fp2_eof) {
            ch = fgetc(fp2);
            if (ch == EOF) {
                fp2_eof = 1;
            } else {
                putchar(ch);
            }
        }
    }

    fclose(fp1);
    fclose(fp2);
    return 0;
}

如果你想要的是“先读完第一个文件,再读第二个”,那逻辑更简单,直接用两个独立的while循环即可,本质上也是||的逻辑:

// 先读file1
int ch;
while ((ch = fgetc(fp1)) != EOF) {
    putchar(ch);
}
// 再读file2
while ((ch = fgetc(fp2)) != EOF) {
    putchar(ch);
}

这种写法完全避免了逻辑运算符和fgetc结合的坑,适合简单的顺序合并场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:16:04