标准输出printf与标准输入scanf
一、标准输出printf
头文件: stdio.h
原型: int printf(const char *format, ...);
参数:
format: 格式控制字符串
...: 可变参数列表
返回值:输出字符的数量。
注意点:
对于标准输出printf,我们需要注意的是返回值,很多人会忽略返回值的类型和代表的含义。
二、标准输入scanf
头文件:stdio.h
参数:
format:格式控制字符串
...:可变参数列表
返回值:成功读入的参数个数
注意点:
1)分隔符,scanf中,默认会把空格,回车换行,tab字符当成是分隔符,对格式控制字符串分隔称子串来并与后面的可变参数列表进行匹配,如果需要修改分隔符,需要用正则表达式来指定。
2)返回值,scanf函数的返回值表示成功读入的参数的个数,类型为int型。
三、例程
1,请使用printf函数,求解一个数字n的十进制表示的数字位数
1 //1.test.c 2 #include <stdio.h> 3 4 int main(void) { 5 int n; 6 while (scanf("%d", &n) != EOF) { 7 printf(" has %d digits!\n", printf("%d", n)); 8 } 9 10 return 0; 11 }
首先,上述代码需要注意的点为EOF(end of file),Linux有一句名言--一切皆文件,对于二进制值EOF,表示的是文件结尾,对于标准输入而言,就是输入已经到达结尾,在Linux中我们用ctrl+D表示EOF,window为ctrl+Z。
ydq@ubuntu:20201013$ gcc 1.test.c
ydq@ubuntu:20201013$ ./a.out
1234
1234 has 4 digits! --》如果想结束输入,可以按下键盘ctrl+D表示输入结束(EOF)。
ydq@ubuntu:20201013$
现在1.test.c就是用来测printf返回值的代码,通过运行结果我们可以知道printf函数返回值就是代表输出的字符数量。
2.请写一个程序,读入一行字符串(可能包含空格),输出这个字符串(可能包含空格),输出这个字符串中字符的数量。
例如
输入:Hello world!
输出:Hello world!
首先我们给出version1代码。
1 //2.test_version.c 2 #include <stdio.h> 3 4 int main(void) { 5 char str[100] = {0}; 6 while (scanf("%s", str) != EOF) { 7 printf("str: %s\n", str); 8 } 9 return 0; 10 }
ydq@ubuntu:20201013$ g++ 2.test_version1.c
ydq@ubuntu:20201013$ ./a.out
Hello world!
str: Hello
str: world!
ydq@ubuntu:20201013$
第一个版本,我们运行出来的结果是分开的两个字符串,分别为Hello和world!,在这里就是默认分隔符起的作用,所以我们得在version2解决这个问题。
1 //2.test_version2.c 2 #include <stdio.h> 3 4 int main(void) { 5 char str[100] = {0}; 6 while (scanf("%[^\n]s", str) != EOF) { //[] -- 指定匹配模式,[^\n]表示除了换行符之外,其他字符全部读入 7 printf("str: %s\n", str); 8 } 9 return 0; 10 }
ydq@ubuntu:20201013$ ./a.out > output.txt
Hello world!
^C
在这里我们把输出结果重定向到文件output.txt,再通过vim命令去打开该文件查看它里面的内容。
ydq@ubuntu:20201013$ vi output.txt
1 str: Hello world!, ret = 1
2 str: Hello world!, ret = 0
3 str: Hello world!, ret = 0
4 str: Hello world!, ret = 0
5 str: Hello world!, ret = 0
6 str: Hello world!, ret = 0
7 str: Hello world!, ret = 0
8 str: Hello world!, ret = 0 --》不止怎么多行,文件接下来有很多行。
首先ret是scanf的返回值,这里我们第一次就已经成功把Hello world!读入并赋值到str数组中,其中返回值为0,接下来scanf还是一直返回0,表示成功读入0个参数,这时候是不是很奇怪,其实在标准输入和标准输入有缓冲区的概念,首先我们在键盘输入的字符串Hello world!最先开始的时候是存储到输入缓冲区,当遇到是遇到换行符或缓冲区满之后或程序结束后才输出缓冲,当我们在键盘输入Hello world!跟回车\n的时候,这些字符串首先会被存入到输入缓冲区中,而由于我们在格式控制字符串中指定[^\n](除了换行符之外,其他字符全部输入),在缓冲区中,只能成功读出缓冲区的Hello world!赋值给str,而\n永远都存在缓冲区中,只要缓冲区中有数据,scanf函数就会一直会返回。接下来我们会给出version3,解决\n一直存在缓冲区的问题。
1 //2.test_version3.c 2 #include <stdio.h> 3 4 int main(void) { 5 char str[100] = {0}; 6 int ret; 7 while ((ret = scanf("%[^\n]s", str)) != EOF) { //[] -- 指定匹配模式,[^\n]表示除了换行符之外,其他字符全部读入 8 getchar(); //强制从输入缓冲区中读出一个字符. 9 printf("str: %s, ret = %d\n", str, ret); 10 } 11 return 0; 12 }
这里,我们调用getchar()函数,强制从缓冲区中读出一个字符,这样就可以解决\n一直存在输入缓冲区的情况了。
ydq@ubuntu:20201013$ ./a.out
Hello world!
str: Hello world!, ret = 1
ydq@ubuntu:20201013$
至此,我们version3版本已经可以完成题目的要求。