2

我正在开发一个 C 项目,该项目读取文本文件并将其转换为布尔数组。首先我将文件读入一个大小的字符串n(是一个无符号字符数组),然后我使用一个函数将该字符串转换为一个大小为布尔数组n * 8。该功能完美运行,对此毫无疑问。

我使用以下代码从文件中获取字符串:

unsigned char *Data_in; // define pointer to string
int i;

FILE* sp = fopen("file.txt", "r"); //open file

fseek(sp, 0, SEEK_END);            // points sp to the end of file
int data_dim = ftell(sp);          // Returns the position of the pointer (amount of bytes from beginning to end)
rewind(sp);                        // points sp to the beginning of file

Data_in = (unsigned char *) malloc ( data_dim * sizeof(unsigned char) ); //allocate memory for string
unsigned char carac; //define auxiliary variable 

for(i=0; feof(sp) == 0; i++)       // while end of file is not reached (0)
{
   carac = fgetc(sp);              //read character from file to char
   Data_in[i] = carac;             // put char in its corresponding position
}
//

fclose(sp);                        //close file

问题是在 Windows XP 中有一个由记事本制作的文本文件。在里面我有这个 4 个字符串":\n\nC"(冒号、输入键、输入键、大写 C)。

这就是 HxD(十六进制编辑器)的样子:3A 0D 0A 0D 0A 43.

这张表更清楚了:

character             hex      decimal    binary
 :                    3A       58         0011 1010
 \n (enter+newline)   0D 0A    13 10      0000 1101 0000 1010    
 \n (enter+newline)   0D 0A    13 10      0000 1101 0000 1010
 C                    43       67         0100 0011

现在,我执行程序,该程序以二进制形式打印该部分,所以我得到:

character      hex      decimal      binary
 :             3A         58         0011 1010
 (newline)     0A         10         0000 1010    
 (newline)     0A         10         0000 1010
 C             43         67         0100 0011

好吧,既然显示了这一点,我提出以下问题:

  • 读法正确吗?
  • 如果是这样,为什么要取出 0D?
  • 这是如何运作的?
4

4 回答 4

4

制作fopen二进制文件:

fopen("file.txt", "rb");
                    ^

否则你的标准库只会吃掉\r( 0x0D)。


附带说明一下,以二进制模式打开文件还可以缓解另一个问题,即文件中间的某个序列看起来像 DOS 上的 EOF。

于 2012-05-29T07:01:45.000 回答
1

这是因为您将该文件视为 ASCII 文件。如果将其视为二进制文件,您将能够看到这两个字符。为此,在打开文件时使用“rb”作为模式。还可以使用 fread 来读取文件内容。

于 2012-05-29T07:04:18.890 回答
1

除了“rb”问题之外,还有一个错误:你会在最后读取一个额外的字符,因为feof(sp)读取最后一个字符后仍然为 0。只有在您尝试读取 EOF之后,它才会设置为 1 。这是初学者的常见错误。迭代输入字符的惯用 C 代码是

int c;   /* int, not char due to EOF. */

while ((c = fgetc(sp)) != EOF) {
   /* Work with c. */
}
于 2012-05-29T07:16:35.647 回答
0

其他答案讨论了二进制与文本模式输入。

您的代码实际上有一个单独的问题。这个成语适用于 Pascal,而不是 C:

for (i = 0; feof(sp) == 0; i++)
{
   carac = fgetc(sp);
   Data_in[i] = carac;
}

麻烦的是,当fgetc()获取 EOF 时,您将其视为一个字符(可能将其映射为 ÿ、y-变音符号、U+00FF、带有分音符号的拉丁小写字母 Y)。测试feof()错位;它不会在尝试读取下一个字符之前检测到 EOF。此外,该函数fgetc()及其亲属getc()getchar()返回一个int,而不是一个char。你必须学会​​使用标准的 C 习语:

int c;
for (i = 0; (c = fgetc(sp)) != EOF; i++)
   Data_in[i] = c;

习语是作业和测试的结合。围绕它的计数不太标准。事实上,这可能相当罕见。但这并没有错;它适用于您的程序。

feof()在大多数 C 代码中不需要使用;几乎任何时候你使用它,它都是一个错误。不总是; 它的存在是有目的的。但是这个目的是在一个函数返回 EOF 之后区分 EOF 和错误fgetc(),而不是在读取函数说它已经到达 EOF 之前测试你是否已经到达 EOF。(在我所有的数百个程序中,我认为对 的引用并不多feof():2884 个源文件,18 个对 的引用feof(),以及大部分由其他人最初编写的代码。)

于 2012-05-29T07:17:55.997 回答