C语言的格式化输入函数scanf

来源:互联网 发布:sql的delete语句 编辑:程序博客网 时间:2024/05/22 05:30

scanf是C语言的标准输入输出库stdio中提供的库函数,所以在使用它时,需要使用预处理指令#include <stdio.h>包含stdio.h头文件。

scanf的功能是根据由格式化字符串表示的特定格式读取输入。输入参数包括格式化字符串和用以存储输入的变量地址。变量地址(指针)的个数没有限制,但要保证格式化字符串中的转换说明的数量和类型与对应位置的输入变量一致。

  scanf(格式化字符串, 变量地址1,变量地址2...)

格式化字符串中包含普通字符和转换说明。调用scanf函数时,从左边开始依次处理格式化字符串中的信息。

格式化字符串中的普通字符

处理格式化字符串中的普通字符时,scanf函数的处理方式因字符为空白字符而不同:

  • 空白字符。如果在格式化字符串中遇到一个或多个连续空白字符,scanf函数会从输入缓冲区中重复读空白字符,直到遇到一个非空白字符为止,并且把该非空白字符放回输入缓冲区,供下次读取。
/************************************ * using_scanf_1.c                  * *                                  * * 格式化字符串的空白字符           * ************************************/#include <stdio.h>int main(){  int x1 = 0;  scanf("  %d", &x1);  int x2 = 0;  scanf(" %d", &x2);  int x3 = 0;  scanf("%d", &x3);  printf("x1 = %d, x2 = %d, x3 = %d\n", x1, x2, x3);  return 0;}

空白字符
- 其他字符。如果在格式化字符串中遇到一个非空白字符,scanf函数将把它与下一个输入字符进行比较。如果两者匹配,则放弃输入字符并继续处理格式化字符串的后续内容;若不匹配,则将该字符放回输入缓冲区,异常退出,不继续处理剩下的格式化字符串。

/********************************* * using_scanf_2.c               * *                               * * 格式化字符串中的非空白字符        * *********************************/#include <stdio.h>int main(){  int x1 = 0;  scanf("x1 = %d", &x1);  printf("x1: %d\n", x1);  /**********************************   *scanf函数执行完成后,会忽略最后 *   *的换行符,留由下一次scanf调用时 *   *读取。因此这里调用scanf函数时第 *   *一个字符为\n,所以要把\n作为转换*   *说明中的第一个字符              *   **********************************/  scanf("\nx1 = %d", &x1);  printf("x1: %d\n", x1);  return 0;}

上例子在为x1读入第二个值时,期望的形式是x1 = 30,但却直接输入30,因此scanf异常退出,x1值不变。
转换说明非空格字符

格式化字符串中的转换说明

scanf的格式说明的通用格式为%<*><m><L>X

  • 转换说明符X。用于scanf的转换说明符及其意义如下表:
转换说明符 含义 d 匹配十进制整数,对应的变量地址为指向int型值 i 匹配整数,对应的变量地址指向int型值。若输入数据以0开头则以八进制格式读入,若输入数据以0x0X开头,则以十六进制读入,否则以十进制读入。 o 匹配八进制整数,对应的变量地址指向unsigned int型值 u 匹配十进制整数,对应的变量地址指向unsigned int型值 x,X 匹配十六进制整数,对应的变量地址指向unsigned int型值 e,E,f,g,G 匹配float型,对应的变量地址执行float型值 s 匹配一个非空字符序列,并在末尾添加空字符,对应的变量地址指向字符串 [ 匹配来自匹配集合的非空字符序列,并在末尾添加空字符,对应的变量地址指向字符串。匹配集合的形式为%[集合],表示输入字符必须是集合中声明的字符,还有一种形式%[^集合],表示输入字符不能是集合中声明的字符 c 如果指定了最大字符宽度m, 则匹配m个字符,否则匹配一个字符。对应的变量地址指向字符 p 匹配printf函数可以写出的格式的指针值,对应的变量地址指向void *类型值 n 把目前为止读入的字符数量存储在此变量中。 % 匹配字符%
/******************************************* * using_scanf_6.c                         * *                                         * * 转换声明中的转换声明符                  * *******************************************/#include <stdio.h>int main(){  int x1 = 0;  scanf("%d", &x1);  printf("x1 = %d\n", x1);  int x2 = 0;  int x3 = 0;  int x4 = 0;  scanf("\n%i,%i,%i", &x2, &x3, &x4);  printf("x2 = %i, x3 = %i, x4 = %i\n", x2, x3, x4);  unsigned int x5 = 0;  scanf("\n%o", &x5);  printf("x5 = %d\n", x5);  unsigned int x6 = 0;  scanf("\n%u", &x6);  printf("x6 = %d\n", x6);  unsigned int x7 = 0;  scanf("\n%x", &x7);  printf("x7 = %d\n", x7);  unsigned int x8 = 0;  scanf("\n%X", &x8);  printf("x8 = %d\n", x8);  float x9 = 0.0f;  scanf("\n%f", &x9);  printf("x9 = %f\n", x9);  char x10[10] = "";  scanf("\n%s", x10);  printf("x10 = %s\n", x10);  char x11[10] = "";  scanf("\n%[123]", x11);  printf("x11 = %s\n", x11);  char x12;  scanf("\n%c", &x12);  printf("x12 = %c\n", x12);  char x13[2] = "";  scanf("\n%2c", x13);  printf("x13_1 = %c, x13_2 = %c\n", x13[0], x13[1]);  printf("%p\n", x13);  char *p = NULL;  scanf("\n%p", &p);  printf("x13_1 = %c\n", p[0]);  int num = 0;  scanf("\n%d%d%n", &x1, &x2, &num);  printf("num = %d\n", num);  int x14 = 0;  scanf("\n%%%d", &x14);  printf("x14 = %d\n", x14);  return 0;}

转换声明符

  • 长短整型标记Lh,l,L中的一个,可选。当读取整数时,h表示对应的变量地址指向short型整数值,l说明对应的变量地址指向long型整数值。当读取浮点数时,l说明对应的变量地址指向double型值,L说明对应的变量地址指向long double型值。
/***************************************** * using_scanf_5.c                       * *                                       * * 转换说明中的长短整型标记              * *****************************************/#include <stdio.h>int main(){  short x1 = 0;  long  x2 = 0;  double x3 = 0.0;  long double x4 = 0.0;  scanf("%hd,%ld,%lf,%Lf", &x1, &x2, &x3, &x4);  printf("x1 = %hd, x2 = %ld, x3 = %f, x4 = %Lf\n", x1, x2, x3, x4);  return 0;}

长短型标记

  • 最大字段宽度m,可选。限制输入项的字符数量,达到最大值则此数据项的转换结束,不包括转换开始跳过的空白字符。
/****************************************** * using_scanf_4.c                        * *                                        * * scanf转换说明的最大字符宽度               * ******************************************/#include <stdio.h>int main(){  int x1 = 0;  int x2 = 0;  scanf("%5d,%5d",&x1, &x2);  printf("x1 = %d, x2 = %d\n", x1, x2);  return 0;}

最大字符宽度

  • 字符*,可选。用以赋值屏蔽:读入此数据项,但不把它赋值给变量,也不包含在scanf函数返回的计数中。
/************************************ * using_scanf_3.c                  * *                                  * * 转换声明中的赋值屏蔽符*          * ************************************/#include <stdio.h>int main(){  int x1 = 0;  int x2 = 0;  int num = scanf("%*d, %d, %d", &x1, &x2);  printf("x1 = %d, x2 = %d, num = %d\n", x1, x2, num);  return 0;}

赋值屏蔽符

处理格式化字符串中的转换说明时,scanf函数跳过输入缓冲区中必要的空格,定位适当类型的项,然后读入数据项存储于相应的变量地址。若读入成功,则继续处理后续的格式化字符串,否则立即返回,不再查看格式化字符串的剩余部分。

当转换声明指定要输入的变量为数时,scanf函数会忽略空白字符(包括空格符,横向和纵向制表符,换页符和换行符)。因此数值开以放在一行或多行内输入。

  • 读入整数。当要求读入整数时,scanf函数首先找到一个数字、正号或负号,然后继续读取数字知道遇到非数字的符号为止。
  • 读入浮点数。当要求读入浮点数时,scanf函数首先会找到一个数字、正号或符号,然后继续读取一串数字,最后读取由eE和正负号、数字构成的指数。

scanf函数执行完后,会忽略最后的换行符,留由下一次scanf函数作为首个符号读取。

scanf的可能错误及检测

scanf的返回值说明了存储的数据项的个数,可以根据期望的返回值和实际的返回值之间的比较检测是否发生了输入错误。

scanf的错误包括三种可能情况:

  • 文件末尾。在完全匹配格式化字符串前遇到了文件结尾。
  • 错误。程序的其他部分发生了错误。
  • 匹配失败。数据项格式错误。

当scanf函数返回小于预期值时,可以使用feof和ferror函数检测问题。若feof返回非零值,则说明输入达到了文件的末尾。如果ferror返回非零值,则表示在输入过程中出现了错误。如果两个都为0,则一定是发生了匹配错误。

/************************************** * using_scanf_7.c                    * *                                    * * scanf的可能错误及检测              * **************************************/#include <stdio.h>int main(){  int x1 = 0;  int num = scanf("x1 = %d", &x1);  printf("期望输出1,实际输出%d\n", num);  int isEOF = feof(stdin);  int hasError = ferror(stdin);  printf("是否文件结尾标识: %d\n", isEOF);  printf("是否存在错误标识: %d\n", hasError);  printf("x1 = %d\n", x1);  return 0;}

scanf的可能错误及检测

调用scanf函数是读取数据的一种有效但不理想的方法,更稳妥的方法是采用字符格式读取所有数据,再将其转换为数值形式。

参考文献

  1. K.N. King 著,吕秀峰 译. C语言程序设计-现代方法. 人民邮电出版社
0 0