欢迎来到博主的专栏——C语言进阶指南
输入输出函数其实在C语言的初学阶段就一直在使用,比如printf函数,scanf函数;getc函数,gets函数。
C语言的输入\输出函数包含在
#include
输入\输出函数的对象都是输入“流”或输出“流”
有些人觉得有点疑惑了,因为前文提到了“流”在进行输入或者输出的操作时,都需要将这个“流”进行打开。但是初学者在使用printf函数,scanf函数时,并没有打开过任何的“流”。
这是因为
标准流有以下三个
标准输出流——stdout。大多数标准输出流都是输出到显示器上,比如printf函数就是将字符串显示在屏幕上。
标准输入流——stdin。大多数标准输入流都是从键盘上输入,比如scanf函数就是在键盘上获取输入的数据。
标准误差流——stderr,这个标准流的作用是将错误信息输出到显示器上,后续会讲到这个流的使用方法
有些输入\输出函数并非能作用于所有类型的“流”,这里先来介绍一些适用性高一些的输入\输出函数
c是一个int类型的数据,是一个字符的ascii码形式。也可以直接使用字符作为参数。
stream是一个FILE*类型的指针,是一个已经打开的任意输出流
fputc是字符输入函数。其作用是向“流”输出字符类型的数据。
这个函数可以向任意的输出“流”输出。所以可以用于标准输出流(stdout)或者是一个文件流。以向文件“data.txt”输出字符为例。
FILE*pf=fopen("data.txt", "w");//打开一个文件输出流
//"w"是说明流的模式是写入数据,即创建一个输出流。
if (pf == NULL)
{
exit(EXIT_FAILURE);
}
fputc('h',pf);//向文件输出流输出'h'.
fputc('e', pf);//输出'e'
fputc('l', pf);
fputc('l', pf);
fputc('o', pf);
fclose(pf);//关闭文件输出流
运行程序,打开文件“data.txt”。
(这可不是手打的哈- -!)
其原理如下(后续的输出函数原理类似,不再画图说明)
fputs的作用是向文件输出流输出一串字符串。
fputs的函数原型有两个参数
string是一个const char *类型的指针,可以是一个常量字符串,也可以是字符数组里的一串字符串。
stream是一个FILE*的指针,已经打开的待输出的输出流,
FILE* pf = fopen("data.txt", "w");//打开data.txt文件的文件输出流
char buf[10] = "world";//包含在字符数组中的字符串"world"
if (pf == NULL)
{
exit(EXIT_FAILURE);
}
fputs("hello,", pf);//向文件输出流输出"hello,"
fputs(buf, pf);//向文件输出流输出"world"
fclose(pf);
fprintf函数的第一个参数,stram是一个已打开的待输出的输出流。
重点在于第二个参数format。这是一个格式串
格式串大家已经见识过很多了。比如
printf("hello,world");
中的字符串就是一个格式串。格式串的讲解在C语言入门指南中已经谈过了,这里不在过多介绍。
我们对比下面两行代码
fprintf(stdout,"hello,world");
printf("hello,world");
运行发现,这两段代码的结果都是在屏幕上打印“hello,world”
这是因为,printf函数的作用,是默认向标准输出流输出数据的,也就是说使用fprintf函数向标准输出流(stdout)输出数据,和使用printf函数直接输出数据是一样作用的。
fprintf可以向任意输出流输出数据,那么fprintf也可以向文件流输出数据。
FILE*pf=fopen("data.txt", "w");
fprintf(pf, "%s\n,%d\n","hello",2024);
fclose(pf);
这段代码是将格式串
“%s\n,%d\n”
输出到文件输出流中。
运行程序,打开“data.txt”文件。可以发现数据已经输出到“data.txt”文件中了。
stram是一个FILE*类型的指针,是一个已经打开的文件输入流
fgetc从文件输入流读取一个字符,并且将该字符的ASCII码值作为函数的返回值
还是以“data.txt”为例,我们在与程序文件的同一目录下创建一个文本文件“data.txt”。并在该文本文件中输入“hello,world”
以下面的代码为例
char a, b, c, d;
FILE*pf=fopen("data.txt", "r");//打开"data.txt"的文件流
//"r"是限定这个文件流为只读,即文件输入流
a=fgetc(pf);//读取'h'
b = fgetc(pf);//读取'e'
c = fgetc(pf);//读取'l'
d = fgetc(pf);//读取'l'
fclose(pf);//关闭文件流
运行可以发现,a,b,c,d四个变量都读取了“data.txt”的文本信息
读取的原理如下图(其他的输入函数也是如此,后续不在说明)
文件被读取时,会将文件内的数据读入至文件流当中,并且在文件的末尾处加上一个EOF(end of file——文件结束标志)。
当我们使用fgetc时,计算机会向文件输入流中读取一个字符,并且将光标移动至下一个字符,直至读取到了EOF。
如果fgetc函数读取到了EOF(EOF的值为-1),函数的返回值为-1,因此可以用此来判断程序是否读取完了整个文本文件
FILE* pf = fopen("data.txt", "r");
char a;
a = fgetc(pf);
if (a == EOF)
{
//文件到了末尾应执行语句
}
fgets是字符串输入函数,其作用是在打开的输入流中读取一串字符串。
fgets的函数原型有三个参数
string是一个char*类型的指针,是用来存放从流中读取的数据的字符串,通常是一个字符数组。
n是一个整型变量,限定了一次读取的字符串中最大字符数。
stream是一个输入流
以文件输入流为例。
fgets会依次读取字符,直到读取了换行符(\n)或者文件结束标志(EOF)时停止。
当fgets发生了读取错误,或者读取了EOF时,函数的返回值为NULL,因此通过判断函数的返回值,可以判断文件是否读取完成。
以文件“data.txt”为例,我们在其输入一段文本。
使用fgets将文本中的数据传递进字符数组中。
int main()
{
FILE* pf = fopen("data.txt", "r");//打开"data.txt"的文本输入流
if (pf==NULL)
{
exit(EXIT_FAILURE);//说明程序运行发生错误
}
char buf[256] = { 0 };//buf是用来接收数据的数组
if (fgets(buf, 20, pf) == NULL)//检测读取信息
//并将文件输入流中的数据读取至buf中
{
exit(EXIT_FAILURE);
}
printf("%s", buf);
return 0;
}
运行可以发现,buf成功读入了“data.txt”中的第一行的文本。
将限定的最大字符数改成10
fgets(buf, 10, pf)
运行这段程序,可以发现buf并没有读取到\n为止。
buf只读取了9个字符,这是由于fgets如果读取到了限定的最大字符数时,只读取最大字符数-1个字符,并在最后一个字符的后面加上‘\0’。
使用fgets函数读取文本行时,一次只能读取到“\n”,或者读取到了限定的最大字符数(n-1)处停止。
fscanf是格式化输入函数,既然提到了格式化,那么参数中就应该存在格式串。
对比两个使用格式串的函数——fscanf和scanf的函数原型
可以发现,fscanf的参数只比scanf多了一个输入流
fscanf的第二个参数是可变参数列表,可变参数列表则说明参数的数量不具体。
虽然可变参数列表大家不太了解,但是可以将fscanf函数的参数分为两个部分 函数的第一个参数是一个流,这个流是已经打开的输入流
函数的第二个参数是一个格式串,这个格式串在scanf函数中已经使用过很多次了。
比如scanf(“%d”,&i);这个“%d”就是一个格式串。
关于格式串在C语言入门指南中已经提过了,这里不再说明
对比下面两个代码
char str[24] = { 0 };
scanf("%s", str);
printf("%s", str);
char str[24] = { 0 };
fscanf(stdin,"%s", str);//stdin是标准输入流
printf("%s", str);
运行可以发现,这两段代码的效果没有区别。
这是因为scanf函数默认从标准输入流(stdin)中读取信息,而将fscanf函数读取的流设定为stdin,那么fscanf的作用就和scanf函数的作用一致了
那么fscanf函数是如何读取文件流的呢?
以文件“data.txt”为例。我们在该文件中输入“hello,world”
运行下列代码,将“data.txt”中的信息输入至字符数组buf中
=int main()
{
char buf[256] = { 0 };
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
exit(EXIT_FAILURE);
}
fscanf(pf, "%s", buf);
printf("%s", buf);
return 0;
}