标准输出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!
", 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
", 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("%[^
]s", str) != EOF) { //[] -- 指定匹配模式,[^
]表示除了换行符之外,其他字符全部读入 
 7         printf("str: %s
", 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!跟回车 的时候,这些字符串首先会被存入到输入缓冲区中,而由于我们在格式控制字符串中指定[^ ](除了换行符之外,其他字符全部输入),在缓冲区中,只能成功读出缓冲区的Hello world!赋值给str,而 永远都存在缓冲区中,只要缓冲区中有数据,scanf函数就会一直会返回。接下来我们会给出version3,解决 一直存在缓冲区的问题。

 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("%[^
]s", str)) != EOF) { //[] -- 指定匹配模式,[^
]表示除了换行符之外,其他字符全部读入
 8         getchar(); //强制从输入缓冲区中读出一个字符.
 9         printf("str: %s, ret = %d
", str, ret);
10     }
11     return 0;
12 }

  这里,我们调用getchar()函数,强制从缓冲区中读出一个字符,这样就可以解决 一直存在输入缓冲区的情况了。

  ydq@ubuntu:20201013$ ./a.out
  Hello world!
  str: Hello world!, ret = 1
  ydq@ubuntu:20201013$

  至此,我们version3版本已经可以完成题目的要求。

原文地址:https://www.cnblogs.com/ydqblogs/p/13823910.html