【问题标题】:While (( c = getc(file)) != EOF) loop won't stop executingWhile (( c = getc(file)) != EOF) 循环不会停止执行
【发布时间】:2012-11-21 13:50:17
【问题描述】:

我不知道为什么我的 while 循环不起作用。没有它,代码可以正常工作...代码的目的是在 bin 文件中查找秘密消息。所以我得到了查找字母的代码,但是现在当我尝试让它循环到文件末尾时,它不起作用。我是新来的。我做错了什么?

main(){

FILE* message;
int i, start;
long int size;
char keep[1];

message = fopen("c:\\myFiles\\Message.dat", "rb");

if(message == NULL){
    printf("There was a problem reading the file. \n");
    exit(-1);
}

//the first 4 bytes contain an int that tells how many subsequent bytes you can throw away
fread(&start, sizeof(int), 1, message);
printf("%i \n", start); //#of first 4 bytes was 280
fseek(message, start, SEEK_CUR); //skip 280 bytes
keep[0] = fgetc(message); //get next character, keep it
printf("%c", keep[0]); //print character

while( (keep[0] = getc(message)) != EOF) {
    fread(&start, sizeof(int), 1, message);
    fseek(message, start, SEEK_CUR);
    keep[0] = fgetc(message);
    printf("%c", keep[0]);
}

fclose(message);

system("pause");
}

编辑:

在调试器中查看我的代码后,似乎在 while 循环中添加了“getc”,这一切都搞砸了。我通过创建一个名为 letter 的新字符来修复它,然后用以下代码替换我的代码:

fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);

while( (letter = getc(message)) != EOF) {
    printf("%c", letter);
    fread(&start, sizeof(int), 1, message);
    fseek(message, start, SEEK_CUR);
}

它现在就像一个魅力。当然欢迎任何更多的建议。谢谢大家。

【问题讨论】:

  • 你试过用 feof 替换循环条件吗?
  • @user1161318:这会引入错误,请记住 feof() 仅在尝试读取最后一个字节之后返回 true。
  • 你还没有告诉我们什么是行不通的。你得到了什么结果,你想要得到什么结果?这将帮助我们帮助您找到答案。
  • 拥有一个只有 1 个元素的数组是没有意义的 - 只需使用 char keep 并在任何地方摆脱 [0]
  • 其实keep应该是一个int来修复。请参阅 JonathanLeffler 的回答。致@user1695758,如果乔纳森的回答能解决问题,请务必采纳。

标签: c file input output


【解决方案1】:

getc() 及其亲属的返回值是int,而不是char

如果将getc() 的结果分配给char,当它返回EOF 时会发生以下两种情况之一:

  • 如果普通 char 是无符号的,则 EOF 将转换为 0xFF,并且 0xFF != EOF,因此循环永远不会终止。
  • 如果普通 char 已签名,则 EOF 等效于有效字符(在 8859-1 代码集中,即 ÿ、y-变音符号、U+00FF、带分音符号的拉丁小写字母 Y)和您的循环可能会提前终止。

鉴于您面临的问题,我们可以初步猜测您将普通的char 作为无符号类型。

getc() 等人返回 int 的原因是,他们必须返回所有可以放入 char 的可能值以及一个不同的值 EOF。在 C 标准中,它说:

ISO/IEC 9899:2011 §7.21.7.1 fgetc() 函数

int fgetc(FILE *stream);

如果stream 指向的输入流的文件结束指示符未设置并且 如果存在下一个字符,fgetc 函数会将该字符作为 unsigned char 转换为 int ...

如果设置了流的文件结束指示符,或者如果流处于文件结束,则结束- 流的文件指示符已设置,fgetc 函数返回 EOF。

类似的措辞适用于getc() 函数和getchar() 函数:它们被定义为类似于fgetc() 函数,除了如果getc() 被实现为宏,它可能会随意使用文件流通常不授予标准宏的参数 - 具体来说,流参数表达式可能会被多次评估,因此使用副作用 (getc(fp++)) 调用 getc() 非常愚蠢(但更改为 fgetc() 会安全,但仍然古怪)。


在你的循环中,你可以使用:

int c;

while ((c = getc(message)) != EOF) {
    keep[0] = c;

这会保留对keep[0] 的分配;我不确定你是否真的需要它。

您应该检查对fgets()getc()fread() 的其他调用,以确保您得到您期望的输入。尤其是在输入时,你真的不能跳过这些检查。迟早会出现问题,如果您不认真检查返回状态,您的代码可能会崩溃,或者只是“出错”。

【讨论】:

  • +1 我认为这是问题所在,但不知道如何简洁地表达它。
  • 也赞成。建议您明确告诉他如何修复(将 keep 声明为 int),因此没有理由不接受您的答案。
  • 谢谢!!我现在更了解发生了什么。
【解决方案2】:

getc() 可能会返回 256 个不同的 char 值,并存储在 char 变量中,例如 keep[0](是的,我过度总结了)。为了可靠地检测文件结尾,EOF 必须具有与所有这些不同的值。这就是getc() 返回int 而不是char 的原因:因为EOF 的第257 个不同值不适合char

因此,您需要将getc() 返回的值存储在int 中,至少在您对照EOF 进行检查之前:

int tmpc;
while( (tmpc = getc(message)) != EOF) {
    keep[0] = tmpc;
    ...

【讨论】:

  • 也许是“......因为 257 个不同的值不适合 char”。 OP 的系统,当然是 Windows,char 签名 确实 持有EOF,这可能是-1。它只是无法区分EOF(char) 255
  • @chux:确实,这就是 distinct 的意思。