在C中逐字符读取文件

Posted

技术标签:

【中文标题】在C中逐字符读取文件【英文标题】:Reading a file character by character in C 【发布时间】:2011-06-16 22:16:51 【问题描述】:

我正在用 C 编写一个 BF 解释器,但在读取文件时遇到了问题。我曾经使用scanf 来读取第一个字符串,但是你的BF 代码中不能有空格或cmets。

现在这就是我所拥有的。

char *readFile(char *fileName)

  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  
    *code++ = (char)fgetc(file);

   while(*code != EOF);
  return code;

我知道问题出在我如何将文件中的下一个字符分配给代码指针,但我只是不确定那是什么。 我缺乏指针知识,这是本练习的重点。 解释器工作正常,全部使用指针,我只是在读取文件时遇到问题。

(稍后我将实现仅将+-><[]., 读取到文件中,尽管如果有人有好的方法可以做到这一点,如果你能告诉我会很棒!)

【问题讨论】:

【参考方案1】:

您的代码有很多问题:

char *readFile(char *fileName)

    FILE *file;
    char *code = malloc(1000 * sizeof(char));
    file = fopen(fileName, "r");
    do 
    
      *code++ = (char)fgetc(file);

     while(*code != EOF);
    return code;

    如果文件大于 1000 字节怎么办? 每次读取字符时都会增加code,并且将code返回给调用者(即使它不再指向内存块的第一个字节,因为它是由malloc返回的)。 您将fgetc(file) 的结果转换为char。在将结果转换为 char 之前,您需要检查 EOF

维护malloc返回的原始指针很重要,以便以后可以释放它。如果我们忽略文件大小,我们仍然可以通过以下方式实现:

char *readFile(char *fileName)

    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL)
        return NULL; //could not open file

    code = malloc(1000);

    while ((c = fgetc(file)) != EOF)
    
        code[n++] = (char) c;
    

    // don't forget to terminate with the null character
    code[n] = '\0';        

    return code;

有多种系统调用可以为您提供文件的大小;一个常见的是stat

【讨论】:

什么是计算文件中字符数的最简单方法,以便我可以将“1000”设置为?另外,我不确定您所说的数字 2 是什么意思,我知道我这样做是错误的,但是我将如何修改呢? @pwnmonkey:我的意思是当它指向文件的 end 时,您正在返回 code,而不是在它指向开头时。 @deamlax 您的示例似乎有一个小错字。 fgets 需要多个参数。你的意思是fgetc 或许? 我不得不将 malloc 转换为 code = (char*)malloc(1000);,因为在 c++ 中将 char* 转换为 void 时出错 @A.k.如果您使用 C++,请不要使用 malloc。使用std::istream 读取文件,并使用std::vector<char> 或其他结构来处理缓冲区。使用new char[] 作为最后的手段,但在编写 C++ 代码时避免使用malloc,因为有更好的(类型安全)替代方案:)【参考方案2】:

从@dreamlax 扩展上述代码

char *readFile(char *fileName) 
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL) return NULL; //could not open file
    fseek(file, 0, SEEK_END);
    long f_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    code = malloc(f_size);

    while ((c = fgetc(file)) != EOF) 
        code[n++] = (char)c;
    

    code[n] = '\0';        

    return code;

这会给你文件的长度,然后逐个字符地读取它。

【讨论】:

你能解释一下 fseek 和 ftell 是如何工作的吗?我认为您需要某种循环来计算文件的字符数。 fseek 视为重新定位光标的一种方式。 fseek(文件,0,SEEK_END);将光标放在文件末尾,然后ftell 告诉您光标在哪里。这给了你文件的大小。 fseek(file, 0, SEEK_SET); 将光标放回文件的开头以便可以读取。如果不这样做,则会从头开始读取文件,这会导致错误并破坏整个操作。【参考方案3】:

这是一种简单的方法,可以忽略除有效的脑残字符之外的所有内容:

#define BF_VALID "+-><[].,"

if (strchr(BF_VALID, c))
    code[n++] = c;

【讨论】:

是的,我以前使用过这个,但问题是如果文件中有换行符,它会将这些换行符放入字符串中。如果我想在一行中将纯 BF 代码写入文件,甚至将其打印到控制台,这很糟糕。 @pwnmonkey:不,这不会将任何换行符存储到目标字符串中(如果您将\n 添加到BF_VALID,它会)。【参考方案4】:

每次调用函数时,文件都被打开而不是关闭

【讨论】:

是的,我知道,我已经更改了,但感谢您告诉我。【参考方案5】:

我认为最重要的问题是你在读入内容时递增code,然后返回code 的最终值,即你将返回一个指向end 的字符串。您可能想在循环之前复制code,然后将其返回。

此外,C 字符串需要以空值结尾。您需要确保将'\0' 直接放在您读入的最后一个字符之后。

注意:您可以只使用fgets() 一次性获得整行。

【讨论】:

对,但我将排除任何不是 BF 代码的内容,因此一次运行更容易。【参考方案6】:

两者中的任何一个都可以解决问题 -

char *readFile(char *fileName)

  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  char *p = code;
  file = fopen(fileName, "r");
  do 
  
    *p++ = (char)fgetc(file);
   while(*p != EOF);
  *p = '\0';
  return code;


char *readFile(char *fileName)

  FILE *file;
  int i = 0;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  
    code[i++] = (char)fgetc(file);
   while(code[i-1] != EOF);
  code[i] = '\0'
  return code;

就像其他发帖人指出的那样,您需要确保文件大小不超过 1000 个字符。另外,请记住在使用完毕后释放内存。

【讨论】:

【参考方案7】:

这里的问题是双重的

a) 在检查读入的值之前增加指针,并且 b) 你忽略了 fgetc() 返回一个 int 而不是 char 的事实。

第一个很容易解决:

char *orig = code; // the beginning of the array
// ...
do 
  *code = fgetc(file);
 while(*code++ != EOF);
*code = '\0'; // nul-terminate the string
return orig; // don't return a pointer to the end

第二个问题更微妙 -fgetc 返回一个 int 以便可以将 EOF 值与任何可能的 char 值区分开来。解决此问题时使用临时 int 进行 EOF 检查,并且可能使用常规 while 循环而不是 do / while。

【讨论】:

如果 EOF 介于 -1 和 -128 之间,那么 可表示为 char 值(假设实现的普通 char 类型已签名) .在这种情况下,从intchar 的转换完全定义为当值可以由char 表示时,EOF 可能就是这种情况。

以上是关于在C中逐字符读取文件的主要内容,如果未能解决你的问题,请参考以下文章

使用 mmap 在 C 中逐行读取文件的最佳方法? [关闭]

Objective C - 创建文本文件以在 Cocoa 中逐行读取和写入

有没有办法从 ASC 文件中逐行读取并在特定子字符串后检查它?

C - 读取文件并将文本放入具有动态内存分配的字符指针

在 C 中逐行浏览文本文件

在 Java 中逐行处理文本文件和连字符字符串