关于printf中的字符串

时间:2018-05-16 18:50:12

标签: c printf file-handling

来自这篇文章https://stackoverflow.com/a/22059317/5859944

FILE *fileptr;
char *buffer;
long filelen;

fileptr = fopen("myfile.txt", "rb");  // Open the file in binary mode
fseek(fileptr, 0, SEEK_END);          // Jump to the end of the file
filelen = ftell(fileptr);             // Get the current byte offset 
                                         in the file
rewind(fileptr);                      // Jump back to the beginning of 
                                         the file

buffer = (char *)malloc((filelen+1)*sizeof(char)); // Enough memory 
                                                      for file + \0
fread(buffer, filelen, 1, fileptr); // Read in the entire file
fclose(fileptr); // Close the file

您将文件读取为字节数组。

很明显它只不过是一根绳子。 可以添加一个

buffer[filelen] = '\0';

printf("%s" , buffer);

应该打印文件的委托内容,就好像它是一个字符串一样。它在简单的文本文件中完成,但不在二进制文件中。

对于二进制文件,必须按如下方式编写函数:

void traverse(char *string ,size_t size){
  for(size_t i=0;i<size;i++)
    printf("%c",string[i]);
}

逐个打印每个字符。 这会在屏幕上显示乱码。

  • 为什么printf不会将buffer视为包含二进制文件的字符串?
  • 为什么函数printf中的traverse会出现乱码而不是字符?

对于第二个要点,我知道这可能是由于signed char,但即使字符串存储为unsigned char,结果仍然相同。

2 个答案:

答案 0 :(得分:2)

  

为什么printf不会将缓冲区视为包含二进制文件的字符串?

printf("%s",buffer) 确实假设buffer包含C字符串。问题是,这不是buffer实际包含的内容。您的buffer实际上包含二进制文件中的字节。

C字符串由第一个零字节(a.k.a。,'\ 0',a.k.a。,ASCII NUL)终止,并且任意非文本文件(a.k.a。,“二进制文件”)可以在其自身内的任何位置包含零字节。 printf“%s”格式一看到第一个零字节就会停止。

  

为什么函数遍历中的printf会出现乱码而不是字符?

“乱码”字符。但是这些字符并不意味着任何东西,因为你试图解释为一系列字符的文件并不意味着以这种方式解释。

文本文件是一系列字节,意在根据某些 character encoding 呈现,而通常意味着传达某种人类可读的信息。任意“二进制”文件可能包含不应该表示人类可读文本的字节序列。它们代表了其他一些计算机程序能够理解的东西。

printf "%s" 尝试根据某些字符编码系统(通常是UTF-8US-ASCII)渲染这些字节,但是(a)它赢了总是能够这样做,(b)即使 能够这样做,字符序列也不会有任何意义。

答案 1 :(得分:1)

这里的第一个问题是你正在混淆阅读文件的目的。要从文件中读取二进制数据,然后打印该二进制数据,您应始终使用unsigned charunsigned char*来存储从二进制文件中读取的数据文件。

这是因为为了准确表示打印的数据,您需要在"%u"格式字符串中使用printf类型标记。根据ASCII,只有some characters are printable,这意味着如果您希望查看文件中的所有二进制数据,则在使用"%c"标志时,您将无法看到其中的一些数据。

你的函数的二进制版本是:

void traverse(unsigned char *string ,size_t size){
  for(size_t i=0;i<size;i++)
    printf("%u",string[i]);
}

第二个问题是

  

应该打印文件的委托内容,就好像它是一个字符串一样。它在简单的文本文件中完成,但不在二进制文件中。

事实并非如此。使用"%s"标志打印字符就好像它们是可打印的字符一样,它会在到达空\0字符时终止。您无法有效地使用%s打印二进制数据。