C:低级字符格式:(输入+换行符)使用fgetc

时间:2012-05-29 06:57:34

标签: c newline enter fgetc

我正在研究C上的一个项目,该项目读取文本文件并将其转换为布尔数组。 首先,我将文件读取为大小为n的字符串(是一个unsigned char数组),然后我使用一个函数将该字符串转换为大小为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 个答案:

答案 0 :(得分:4)

制作fopen二进制文件:

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

否则您的标准库只会吞掉\r0x0D)。


作为旁注,以二进制模式打开文件还可以缓解另一个问题,即文件中间的某个序列在DOS上看起来像EOF。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

while ((c = fgetc(sp)) != EOF) {
   /* Work with c. */
}

答案 3 :(得分:0)

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

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

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

麻烦的是,当fgetc()获得EOF时,你将它视为一个角色(可能将其映射到ÿ,y-umlaut,U + 00FF,带有DIAERESIS的LATIN SMALL LETTER Y)。 feof()测试错位;它在尝试读取下一个字符之前没有检测到EOF。此外,函数fgetc()及其亲属getc()getchar()都返回int,而不是char。你必须学会​​使用标准的C语言:

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

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

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