C库函数:stdio.h

stdio.h

C 标准库 – <stdio.h> | 菜鸟教程 (runoob.com)

下面是头文件 stdio.h 中定义的变量类型:

序号变量 & 描述
1size_t
这是无符号整数类型,它是 sizeof 关键字的结果。
2FILE
这是一个适合存储文件流信息的对象类型。
3fpos_t
这是一个适合存储文件中任何位置的对象类型。

其中的FILE比较常见,那么这个FILE到底是什么?

描述中声称FILE是一个适合存储文件流信息的对象类型。

在C语言中,用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。

定义文件指针的一般形式为:

FILE *fp;

这里的FILE,实际上是在stdio.h中定义的一个结构体,该结构体中含有文件名、文件状态和文件当前位置等信息,fopen 返回的就是FILE类型的指针。

注意:FILE是文件缓冲区的结构,fp也是指向文件缓冲区的指针。

不同编译器stdio.h 头文件中对 FILE 的定义略有差异,这里以标准C举例说明:

下面说一下如何控制缓冲区。

我们知道,当我们从键盘输入数据的时候,数据并不是直接被我们得到,而是放在了缓冲区中,然后我们从缓冲区中得到我们想要的数据 。如果我们通过setbuf()或setvbuf()函数将缓冲区设置10个字节的大小,而我们从键盘输入了20个字节大小的数据,这样我们输入的前10个数据会放在缓冲区中,因为我们设置的缓冲区的大小只能够装下10个字节大小的数据,装不下20个字节大小的数据。那么剩下的那10个字节大小的数据怎么办呢?暂时放在了输入流中。请看下图:

上面的箭头表示的区域就相当是一个输入流,红色的地方相当于一个开关,这个开关可以控制往深绿色区域(标注的是缓冲区)里放进去的数据,输入20个字节的数据只往缓冲区中放进去了10个字节,剩下的10个字节的数据就被停留在了输入流里!等待之后往缓冲区中放入!那么系统是如何来控制这个缓冲区呢?

再说一下 FILE 结构体中几个相关成员的含义:
cnt  // 剩余的字符,如果是输入缓冲区,那么就表示缓冲区中还有多少个字符未被读取
ptr  // 下一个要被读取的字符的地址
base  // 缓冲区基地址

在上面我们向缓冲区中放入了10个字节大小的数据,FILE结构体中的 cnt 变为了10 ,说明此时缓冲区中有10个字节大小的数据可以读,同时我们假设缓冲区的基地址也就是 base 是0x00428e60 ,它是不变的 ,而此时 ptr 的值也为0x00428e60 ,表示从0x00428e60这个位置开始读取数据,当我们从缓冲区中读取5个数据的时候,cnt 变为了5 ,表示缓冲区还有5个数据可以读,ptr 则变为了0x0042e865表示下次应该从这个位置开始读取缓冲区中的数据 ,如果接下来我们再读取5个数据的时候,cnt 则变为了0 ,表示缓冲区中已经没有任何数据了,ptr 变为了0x0042869表示下次应该从这个位置开始从缓冲区中读取数据,但是此时缓冲区中已经没有任何数据了,所以要将输入流中的剩下的那10个数据放进来,这样缓冲区中又有了10个数据,此时 cnt 变为了10 ,注意了刚才我们讲到 ptr 的值是0x00428e69 ,而当缓冲区中重新放进来数据的时候这个 ptr 的值变为了0x00428e60 ,这是因为当缓冲区中没有任何数据的时候要将 ptr 这个值进行一下刷新,使其指向缓冲区的基地址也就是0x0042e860这个值!因为下次要从这个位置开始读取数据!

在这里有点需要说明:当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会被转换为一个换行符\n,这个换行符\n也会被存储在缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而不是6。


缓冲区的刷新就是将指针 ptr 变为缓冲区的基地址 ,同时 cnt 的值变为0 ,缓冲区刷新后里面就没有数据了!

1int fclose(FILE *stream)
关闭流 stream。刷新所有的缓冲区。

C 库函数 int fclose(FILE *stream) 关闭流 stream。刷新所有的缓冲区。

直接传入一个文件类型指针即可。

如果流成功关闭,则该方法返回零。如果失败,则返回 EOF。

EOF
这个宏是一个表示已经到达文件结束的负整数。
3int feof(FILE *stream)
测试给定流 stream 的文件结束标识符。

当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。

注意,这句话的意思是,如果到了结束符,就返回一个非零值,要是还没读到结束符,就返回0。

5int fflush(FILE *stream)
刷新流 stream 的输出缓冲区。

7FILE *fopen(const char *filename, const char *mode)
使用给定的模式 mode 打开 filename 所指向的文件。
  • filename -- 字符串,表示要打开的文件名称(全路径)
  • mode -- 字符串,表示文件的访问模式,可以是以下表格中的值:
模式描述
"r"打开一个用于读取的文件。该文件必须存在。
"w"创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
"a"追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。
"r+"打开一个用于更新的文件,可读取也可写入。该文件必须存在。
"w+"创建一个用于读写的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
"a+"打开一个用于读取和追加的文件。

fopen() 会获取文件信息,包括文件名、文件状态、当前读写位置等,并将这些信息保存到一个 FILE 类型的结构体变量中,然后将该变量的地址返回。

该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。

在C语言中,操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。

打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中,程序还可以记录当前读写到了哪个位置,下次可以在此基础上继续操作。

标准输入文件 stdin(表示键盘)、标准输出文件 stdout(表示显示器)、标准错误文件 stderr(表示显示器)是由系统打开的,其本质也是个FILE类型指针,可直接使用。我们通常自定义的是我们自己的文件位置,而这三个位置是系统已经定义好的,标准化的。

10stderr、stdin 和 stdout
这些宏是指向 FILE 类型的指针,分别对应于标准错误、标准输入和标准输出流。
8size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
从给定流 stream 读取数据到 ptr 所指向的数组中。

参数

  • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
  • size -- 这是要读取的每个元素的大小,以字节为单位。
  • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

返回值

成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。

使用示例:

#include <stdio.h>
#include <string.h>
 
int main()
{
   FILE *fp;
   char c[] = "This is runoo";
   char buffer[20];
 
   /* 打开文件用于读写 */
   fp = fopen("file.txt", "w+");
 
   /* 写入数据到文件 */
   fwrite(c, strlen(c) + 1, 1, fp);
 
   /* 查找文件的开头 */
   fseek(fp, 0, SEEK_SET);
 
   /* 读取并显示数据 */
   fread(buffer, strlen(c)+1, 1, fp);
   printf("%s\n", buffer);
   fclose(fp);
   
   return(0);
}

运行结果:

这个程序是菜鸟教程中给的示例程序,但是有个疑惑。

fread中,第二个参数为啥是strlen() + 1,这也不像是要读取的元素的大小呀,第三个参数为啥是1,而不是所有字符的总个数?

教程中给的例子应该不会有问题,那么就是我的理解问题了。

我理解的元素是字符,即一个字符一个字符地去读取,显然,这里不是这个意思。

那么,上述中提到的“元素”指的是什么?

这个函数,很容易理解错误。以为是一个字符一个字符地去读取。

count是要读取的字符个数,size是每个字符的字节数。

我觉得上述官方的描述很有问题。

下面查阅资料,给到真正的理解。

参数

  • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
  • size -- 这是每次要读取的字节数。
  • nmemb -- 这是要分多少次来读取目标数据。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

fread是一个分段读取文件的函数,count就是分多少段,举例来说,同样在文件中读100个字节:
int a = fread(buf, 1, 100, fp);   // a = 100
int b = fread(buf, 100, 1, fp);   // b = 1
其实count影响的是返回值,fread返回的是成功读取多少段,所以一般情况下,如果需要准确的知道到底读取了多少个字节,把size设为1,把count设为你需要读取的字节数,这样fread的返回值就是读取的字节数了。
性能方面不用担心,fread底层并不是一段一段调用系统调用去读的,是优化过的。

(1) 调用格式:fread(buf, sizeof(buf), 1, fp);
读取成功时:当读取的数据量正好是sizeof(buf)个Byte时,返回值为1(即count)
(2)调用格式:fread(buf, 1, sizeof(buf), fp);
读取成功返回值为实际读回的数据个数(单位为Byte)

这样一来,就理解了该函数,如果是这样,那么在上述案例中,如果将strlen(c)+1换成sizeof(c),应该是一样的效果。经过测试,确实如此。

10int fseek(FILE *stream, long int offset, int whence)
设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。

参数

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset -- 这是相对 whence 的偏移量,以字节为单位。
  • whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
常量描述
SEEK_SET文件的开头
SEEK_CUR文件指针的当前位置
SEEK_END文件的末尾

返回值

如果成功,则该函数返回零,否则返回非零值。

示例如下:

注意,偏移量是不算第一个字符的。

也就是说文件的开头指的是第一个字符。

13size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
把 ptr 所指向的数组中的数据写入到给定流 stream 中。

fwrite()函数常用于将一块内存区域中的数据写入到本地文本。

fwrite是fread的逆操作,参数是一样的。返回值也是一样的。只不过传输的方向不同。 

14int remove(const char *filename)
删除给定的文件名 filename,以便它不再被访问。

如果成功,则返回零。如果错误,则返回 -1,并设置 errno。 

15int rename(const char *old_filename, const char *new_filename)
把 old_filename 所指向的文件名改为 new_filename。

如果成功,则返回零。如果错误,则返回 -1,并设置 errno。 

16void rewind(FILE *stream)
设置文件位置为给定流 stream 的文件的开头。

17void setbuf(FILE *stream, char *buffer)
定义流 stream 应如何缓冲。

该函数应在与流 stream 相关的文件被打开时,且还未发生任何输入或输出操作之前被调用一次。

参数

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
  • buffer -- 这是分配给用户的缓冲,它的长度至少为 BUFSIZ 字节,BUFSIZ 是一个宏常量,表示数组的长度。
BUFSIZ
这个宏是一个整数,该整数代表了 setbuf 函数使用的缓冲区大小。

返回值

该函数不返回任何值。

示例如下:

18int setvbuf(FILE *stream, char *buffer, int mode, size_t size)
另一个定义流 stream 应如何缓冲的函数。

参数

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
  • buffer -- 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
  • mode -- 这指定了文件缓冲的模式:
模式描述
_IOFBF全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。
_IOLBF行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。
_IONBF无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。
  • size --这是缓冲的大小,以字节为单位。

返回值

如果成功,则该函数返回 0,否则返回非零值。

实例演示:

和setbuf相比,主要多了可以选择缓冲模式。

21int fprintf(FILE *stream, const char *format, ...)
发送格式化输出到流 stream 中。

参数

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format -- 这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:
specifier(说明符)输出
c字符
d 或 i有符号十进制整数
e使用 e 字符的科学科学记数法(尾数和指数)
E使用 E 字符的科学科学记数法(尾数和指数)
f十进制浮点数
g自动选择 %e 或 %f 中合适的表示法
G自动选择 %E 或 %f 中合适的表示法
o有符号八进制
s字符的字符串
u无符号十进制整数
x无符号十六进制整数
X无符号十六进制整数(大写字母)
p指针地址
n无输出
%字符
 
flags(标识)描述
-在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space)如果没有写入任何符号,则在该值前面插入一个空格。
#与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。
与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。
与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。

思考:为什么我们在日常使用时,很多时候明明没有“-”号也是左对齐?


答:左对齐还是右对齐是在有对齐需要的时候才有意义的。由于你并没有指定每个int值输出的长度,因此int 值有多长就会输出多长,此时没有讨论左对齐或者右对齐的意义。
你只有加上%10d(10 只是我举的例子),这时候限定了int 值输出长度为10,而12345这个int值的长度为5,这时候就有左对齐还是右对齐的分别了。

参考此题:

width(宽度)描述
(number)要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断
*宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
注意,这里的number是指定的数字。
.precision(精度)描述
.number对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。
对于 e、E 和 f 说明符:要在小数点后输出的小数位数。
对于 g 和 G 说明符:要输出的最大有效位数。
对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.*精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
 
length(长度)描述
h参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。
  • 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

返回值

如果成功,则返回写入的字符总数,否则返回一个负数。

下面的实例演示了 fprintf() 函数的用法。

和printf类似,只是fprintf指定了一个输出的目标。

个人总结:宽度这个选项因为不会对更长的输出做截断,所以通常只在决定左对齐还是右对齐时有一定的作用。精度这个选项通常用在浮点数输出或者字符串输出时。

22int printf(const char *format, ...)
发送格式化输出到标准输出 stdout。
  • format -- 这是字符串,包含了要被写入到标准输出 stdout 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:

格式字符意义
a, A

以十六进制形式输出浮点数(C99 新增)。

实例 printf("pi=%a\n", 3.14); 输出 pi=0x1.91eb86p+1

d以十进制形式输出带符号整数(正数不输出符号)
o以八进制形式输出无符号整数(不输出前缀0)
x,X以十六进制形式输出无符号整数(不输出前缀Ox)
u以十进制形式输出无符号整数
f以小数形式输出单、双精度实数
e,E以指数形式输出单、双精度实数
g,G以%f或%e中较短的输出宽度输出单、双精度实数
c输出单个字符
s输出字符串
p输出指针地址
lu32位无符号整数
llu64位无符号整数

对于字符串来说,注意%ns和%.ns的区别:

#include <stdio.h>

int main()
{	
    printf("Hello, World! %5s\n","abcdefg");//Hello, World! abcdefg
	printf("Hello, World! %.5s\n","abcdefg");//Hello, World! abcde
   
    return 0;
}

%s:例如:printf("%s", "CHINA")输出"CHINA"字符串(不包括双引号)
%ms:输出的字符串占m列,如果字符串本身长度大于m,则突破m的限制,将字符串全部输出。若串长小于m,则左补空格。
%-ms:输出的字符串占m列,如果字符串本身长度大于m,则突破m的限制,将字符串全部输出。如果串长小于m,则在m列范围内,字符串向左靠,右补空格。
%m.ns:输出占m列,但只取字符串中左端n个字符。这n个字符输出在m列的右侧,左补空格。
%-m.ns:其中m、n含义同上,n个字符输出在m列范围的左侧,右补空格。如果n>m,则自动取n值,即保证n个字符正常输出。 

当格式符个数小于后面的变量个数,则忽略后面多余的变量。

当需要输出%时,可以使用%%,此时,输出的就是%本身。

验证如下:

23int sprintf(char *str, const char *format, ...)
发送格式化输出到字符串。

如果想要把数字转成字符串,可以使用sprintf函数。

其实,还有个常见的itoa函数,int to array,但是itoa并不是一个标准的C函数,它是Windows特有的,如果要写跨平台的程序,请用sprintf。标准库中有sprintf,功能比itoa更强,但是其比itoa系列函数运行速度慢。嵌入式中一般使用sprintf。

注意:sprintf传入char *没用,只能传入char数组

更多用法参考:

sprintf的用法-腾讯云开发者社区-腾讯云

27int fscanf(FILE *stream, const char *format, ...)
从流 stream 读取格式化输入。

 

we are in 2014,输入时,遇到空格就视作是一个输入的结束。

比如,我将这里改成:

输出就变成了:

28int scanf(const char *format, ...)
从标准输入 stdin 读取格式化输入。

&a、&b、&c 中的 & 是地址运算符,分别获得这三个变量的内存地址。

所以说,输入时,实际是存入变量对应的内存地址的。

注意:

1、输入时,格式符之间是什么样的分隔,输入时就要是什么样的分隔。

2、在用 %c 输入时,空格和"转义字符"均作为有效字符。

3、接收字符串:

注:

*这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。
width这指定了在当前读取操作中读取的最大字符数。

30int fgetc(FILE *stream)
从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。

该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。

34int getc(FILE *stream)
从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。

35int getchar(void)
从标准输入 stdin 获取一个字符(一个无符号字符)。

该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。

 32int fputc(int char, FILE *stream)
把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。

参数

  • char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。

返回值

如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。

实例演示:

37int putc(int char, FILE *stream)
把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
38int putchar(int char)
把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。

31char *fgets(char *str, int n, FILE *stream)
从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

参数

  • str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n -- 这是要读取的最大字符数(包括最后的空字符)。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

返回值

如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针。

也就是说,只要读取不成功,就会返回NULL。

33int fputs(const char *str, FILE *stream)
把字符串写入到指定的流 stream 中,但不包括空字符

该函数返回一个非负值,如果发生错误则返回 EOF。

36char *gets(char *str)
从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

如果成功,该函数返回 str。如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL。

看一道题:

gets()函数从终端输入一个字符串到数组,直到按回车键为止,并把回车键保存为'\0‘

strcat会寻找第一个'\0'所以后面的数字才被清除了。

get(ss)之后,ss的内容变成了"ABC\03,4,5",之后strcat会寻找\0来接续,所以最后的结果是ABC6789

39int puts(const char *str)
把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。

41void perror(const char *str)
把一个描述性错误消息输出到标准错误 stderr。首先输出字符串 str,后跟一个冒号,然后是一个空格。

该函数不返回任何值。

补充

关于EOF

看这道题:

EOF是End Of File的意思,在C语言中定义的一个宏,用作文件结束标志。
该宏定义在stdio.h中,从数值角度看,就是-1
#define EOF (-1)

在C语言中,或更精确地说成C标准函数库中表示文件结束符 (endof file )。这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII 代码值的形式存放。我们知道,ASCII 代码值的范围是 0~255,不可能出现-1,因此可以用EOF作为文件结束标志。

文本文件和二进制文件到底啥区别?

文件分为文本文件和二进制文件两种。

文本文件和二进制文件的区别不在于两者的物理存储,而是在于两者对所存储二进制数的逻辑解释上。

所谓文本文件,也就是文件存储的是我们人类可读的一个个字符,比如"hello", "你好”等。当然,最后也是以二进制的方式存储在计算机上。为了把字符表示成二进制,事先得有一个所谓的码表,给出了每个字符与二进制数的对应关系,比如著名的ASCII码表。

除了用上面这种方式存储的文件,其余文件都应该被理解为二进制文件。有人说二进制文件其实就是存储的二进制数,这个不完全正确。因为本质上文件都是存储的二进制数。比如65表示成二进制数为01000001,如果是文本文件,那查ASCII码表,则是大写字母'A‘,但如果不是文本文件,它就是二进制的01000001,至于说到底代表什么含义,则是创建这个文件的用户自定义的。它可以是一个二进制的整数值,也可以是某个指令的编号,或者是某个内存地址的一部分。

那到底怎么区分文本文件和二进制文件呢?

有人说根据文件的扩展名区分,但是扩展名完全可以人为地修改,而且有些文件压根就没有扩展名,因此通过扩展名区分文件是文本文件还是二进制文件是不可靠的。

那有没有完全可靠的方法来区分文本文件和二进制文件呢?

很遗憾,严格意义上来说,不存在!哦,也不对,只能说是对文件创建者之外的人或机器来说,不存在。唯一知道能完全确定文件是文本文件还是二进制文件的就是文件创建者。

打印时,int的话%d不会有问题,64位使用%lld打印

浅谈%d, %ld, %lld 区别-CSDN博客

printf不是线程安全函数,在多线程打印时大概率会出问题,因为会插入其他的数据,会让人误以为是需要的数据,其实并不是。这一点千万注意。 

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值