EOF 函数在 C 中的正确用法

EOF function proper usage in C

提问人:100MIL 提问时间:5/20/2023 最后编辑:Ken White100MIL 更新时间:5/20/2023 访问量:69

问:

因此,以下是用于反转文件中输入数据的代码。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
  int i=0;
  char ch,str[10];
  FILE *ptr;
  ptr=fopen("input.txt","w");
  if(ptr==NULL){
    printf("File error\n");
    exit(0);
  }
  while((ch=getchar())!=EOF){
    putc(ch,ptr);
  }
  putc(' ',ptr);
  fclose(ptr);
  ptr=fopen("input.txt","r");
  while((ch=getc(ptr))!=EOF){
    str[i]=ch;
    i++;
    if(ch==' '){
      str[i]='\0';
      i=0;
      strrev(str);
      printf("%s",str);
    }
  }
}

此代码反转数据,但在新行中打印最后一个单词...对于 EOF,我使用“Enter”->“Ctrl+Z”->“Enter”...这是正确的方法吗? 我期望以与输入相同的方式反转数据。 在换行中获得最后一个单词的原因是什么?请告诉我我应该做出哪些更改以获得所需的输出。

C 文件处理 EOF

评论

1赞 Retired Ninja 5/20/2023
文本文件的内容是什么?它有行尾吗?如果你读一个字符串,包括行尾,然后反转它,会发生什么? 应该是char ch;int ch;
0赞 Shawn 5/20/2023
@adabsurdum 文本文件应以新行结尾,但它们不会神奇地添加。
0赞 Shawn 5/20/2023
@adabsurdum 也许某个特定的编辑器会,但在操作系统级别上什么都没有。就 Linux 而言,它甚至没有文本文件在内部处理与二进制文件不同的概念。这是 Windows 的区别。(另外,使用 Ctrl-Z 而不是 Ctrl-D 表示 EOF 无论如何都建议 Windows,而且我很确定它也不会神奇地添加换行符,只是在 CRLF 和 LF 之间转换)
0赞 ad absurdum 5/20/2023
@Shawn -- 好吧,我现在不能在测试程序中实现它。过去,我曾在 POSIX .txt 文件的末尾附加了神奇的换行符,但现在我不确定是什么原因造成的;正如你所建议的那样,可能是一个编辑技巧。
2赞 phuclv 5/20/2023
ch 必须是 int 为什么 getchar() 的返回类型是 int?

答:

2赞 Shawn 5/20/2023 #1

如果是您在通过按 和 + 发出 EOF 信号之前输入的最后一个单词,则文件的最后一部分将是 .由于在点击空格时会反转读取缓冲区中的内容,因此最后一个单词打印出来的内容是 。xyzEnterCtrlZxyz<newline><space><space><newline>zyx

一个可能的解决方法:将换行符和空格视为分词符,而不仅仅是空格(也许任何使 isspace() 返回 true 的东西)。我还会在反转的单词后面打印空格字符,而不是将其作为要反转的文本的一部分(这也将解决您的问题)。包括修复 ch 应该是 int 而不是 char 的问题,以及其他一些调整,但没有解决任何超过 9 个字符的单词会导致程序写入数组末尾的问题,它可能看起来像这样:str

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef WIN32
// _strrev() (strrev() is a deprecated alias) is a Windows-specific
// function.  Quick and dirty implementation for other systems.
char *_strrev(char *s) {
  char *start = s;
  char *end = strchr(s, '\0');
  if (s == end) {  // Empty string
    return start;
  }
  end -= 1;
  while (s != end) {
    char temp = *end;
    *end = *s;
    *s = temp;
    s += 1;
    end -= 1;
  }
  return start;
}
#endif

int main(void) {
  int i = 0;
  int ch;
  char str[10];
  FILE *ptr;
  ptr = fopen("input.txt", "w");
  if (ptr == NULL) {
    printf("File error\n");
    exit(1);
  }
  while ((ch = getchar()) != EOF) {
    putc(ch, ptr);
  }
  putc(' ', ptr);
  fclose(ptr);
  ptr = fopen("input.txt", "r");
  while ((ch = getc(ptr)) != EOF) {
    if (isspace(ch)) {
      if (i > 0) { // Skip empty words (Caused by multiple spaces in a row)
        char delim = ch;
        str[i] = '\0';
        i = 0;
        _strrev(str);
        printf("%s%c", str, delim);
      }
    } else {
      str[i++] = ch;
    }
  }
}

评论

0赞 Shawn 5/20/2023
@DavidC.Rankin:你认为如何找到字符串的末尾?strrchr()
0赞 Shawn 5/20/2023
@DavidC.Rankin,它必须首先通过查看前面的每个字符来找到尾随的nul。请记住,C 字符串不会跟踪自己的长度。
0赞 Shawn 5/20/2023
例如,请参阅我从另一个答案中的实现。在这里使用它没有任何好处。strrchr()strchr()
0赞 David C. Rankin 5/20/2023
我纠正了,glibc strrchr() 确实向前迭代——你不会在那里保存任何东西。老狗重学老把戏。