12 - scanf()函数

1 函数原型

scanf():从标准输入流stdin中读取格式化数据,函数原型如下:

int scanf(const char *format, ...);

cstdio库描述如下:

Read formatted data from stdin
1. Reads data from stdin and stores them according to the parameter format into the locations pointed by the additional arguments.
2. The additional arguments should point to already allocated objects of the type specified by their corresponding format specifier within the format string.

2 参数

scanf()函数的参数分为两类:

  1. format :格式化字符串,用于指定如何解析和提取输入流中的数据;
  2. … :可变数量的参数。

2.1 格式化字符串

在scanf()函数中,格式化字符串是必不可少的,cstdio库描述如下:

C string that contains a sequence of characters that control how characters extracted from the stream are treated:

Whitespace character :
1. The function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters -- see isspace). 
2. A single whitespace in the format string validates any quantity of whitespace characters extracted from the stream (including none).

Non-whitespace character, except format specifier (%) :
1. Any character that is not either a whitespace character (blank, newline or tab) or part of a format specifier (which begin with a % character) causes the function to read the next character from the stream, compare it to this non-whitespace character and if it matches, it is discarded and the function continues with the next character of format. 
2. If the character does not match, the function fails, returning and leaving subsequent characters of the stream unread.

Format specifiers :
1. A sequence formed by an initial percentage sign (%) indicates a format specifier, which is used to specify the type and format of the data to be retrieved from the stream and stored into the locations pointed by the additional arguments.

2.1.1 空白字符

空白字符包括空格、制表和换行,即’ ‘,’\r’,‘\n’,‘\t’,‘\v’和’\f’。

空白字符的处理

  1. 显示指定
    如果在格式化字符串中显式地包含空白字符,则scanf()函数会跳过输入流中的任意数量的空白字符(包括零个),直到遇到第一个非空白字符为止;
  2. 自动跳过
    即使在格式化字符串中不显示包含空白字符,scanf()函数仍会自动跳过输入流中的空白字符,直到遇到第一个非空白字符为止。

注意:输入流中的空白字符一般用于分隔不同的输入项(对应多个格式说明符)。

2.2.2.1 示例1 - 自动跳过

示例代码如下所示:

int main()
{
   //
   int a = 0;
   int b = 0;
   //
   printf("自动跳过:格式说明符前无空格字符+输入\"空格+制表+123+空格+制表+456\"\n");
   scanf("%d%d", &a, &b);
   printf("a = %d\n", a);
   printf("b = %d\n", b);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于第1个%d:自动跳过第1组空格+制表,读取数字123,遇到空格停止读取;
  2. 对于第2个%d:自动跳过第2组空格+制表,读取数字456,遇到换行停止读取。
2.1.1.2 示例2 - 显示指定

示例代码如下所示:

int main()
{
   //
   int a = 0;
   int b = 0;
   //
   printf("显示指定:格式说明符前有空格字符+输入\"123+空格+制表+456\"\n");
   scanf(" %d %d", &a, &b);
   printf("a = %d\n", a);
   printf("b = %d\n", b);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于第1个%d:读取数字123,遇到空格停止读取;
  2. 对于第2个%d:跳过空格和制表符,读取数字456,遇到换行停止读取。

2.1.2 格式说明符

格式说明符以百分号’%'开头,格式如下:

%[*][最大宽度][类型长度]类型

cstdio库描述如下:

1. A format specifier for scanf follows this prototype : %[*][width][length]specifier
2. Where the specifier character at the end is the most significant component, since it defines which characters are extracted, their interpretation and the type of its corresponding argument:
2.1.2.1 类型

类型字段是格式说明符中必不可少的部分,用于指定scanf()函数期望从标准输入流stdin中读取的有效字符范围,常用的类型如下图所示:

在这里插入图片描述

2.1.2.1.1 整形
  1. %d和%u:
    (1)从输入流读取一个十进制整数;
    (2)期望的有效字符包括符号±和十进制数字0-9;
  2. %x:
    (1)从输入流读取一个十六进制整数;
    (2)期望的有效字符包括符号±、前导0x或0X和十六进制数字0-9、a-f、A-F;
  3. %d、%u和%x:
    (1)可自动跳过空白字符;
    (2)遇到无效字符停止读取。

示例代码如下所示:

int main()
{
   //
   int intData1 = 0;
   int intData2 = 0;
   unsigned int uintData = 0;
   //
   printf("以\"%%d%%x%%u\"形式输入\"制表符+-123+制表符+0x123+制表符+123abc\":\n");
   // 三个格式说明符前面无空格字符,三个数以制表符隔开
   scanf("%d%x%u", &intData1, &intData2, &uintData);
   printf("intData1 = %d\n", intData1);
   printf("intData2 = %#x\n", intData2);
   printf("uintData = %u\n", uintData);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于%d:自动跳过第1个制表符,读取-123,遇到第2个制表符停止读取;
  2. 对于%x:自动跳过第2个制表符,读取0x123,遇到第3个制表符停止读取;
  3. 对于%u:自动跳过第3个制表符,读取123,遇到字母a停止读取。
2.1.2.1.2 浮点型
  1. %f:
    (1)从输入流读取一个十进制形式的浮点数;
    (2)期望的有效字符包括符号±、十进制数字0-9、小数点;
  2. %e:
    (1)从输入流读取一个科学计数法形式的浮点数;
    (2)期望的有效字符包括尾数部分(符号±、十进制数字0-9、小数点)和指数部分(e或E和十进制数字0-9);
  3. %g:以%f或%e形式从输入流读取一个浮点数
  4. %f、%e和%g:
    (1)可自动跳过空白字符;
    (2)遇到无效字符停止读取。

示例代码如下所示:

int main()
{
   //
   float floatData1 = 0.0f;
   float floatData2 = 0.0f;
   float floatData3 = 0.0f;
   //
   printf("以\"%%f%%e%%g\"形式输入\"制表符+-1.23+制表符+1.23e-02+制表符+123.456\":\n");
   // 三个格式说明符前面无空格字符,三个数以制表符隔开
   scanf("%f%e%g", &floatData1, &floatData2, &floatData3);
   printf("floatData1 = %f\n", floatData1);
   printf("floatData2 = %e\n", floatData2);
   printf("floatData3 = %g\n", floatData3);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于%f:自动跳过第1个制表符,读取-1.23,遇到第2个制表符停止读取;
  2. 对于%e:自动跳过第2个制表符,读取1.23e-02,遇到第3个制表符停止读取;
  3. 对于%g:自动跳过第3个制表符,读取123.456,遇到换行停止读取。
2.1.2.1.3 字符
  1. %c:
    (1)从输入流读取一个字符;
    (2)期望的有效字符包括所有的ASCII码字符;
    (3)默认情况下不会自动跳过输入流中的空白字符(空白字符对%c来说也是有效字符);
    (4)如果希望跳过空白字符,只需在%c之前显式地放置一个空格作为格式化字符串的一部分。

示例代码如下所示:

int main()
{
   //
   char ch1 = 0;
   char ch2 = 0;
   char ch3 = 0;
   //
   printf("以\"%%c%%c %%c\"形式输入\"空格+a+空格+b+空格+c\":\n");
   // 前两个格式说明符中前面无空格字符,后一个格式说明符前面有空格字符,三个字符以空格隔开
   scanf("%c%c %c", &ch1, &ch2, &ch3);
   printf("ch1 = %c\n", ch1);
   printf("ch2 = %c\n", ch2);
   printf("ch3 = %c\n", ch3);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于第1个%c:前无空格字符,从输入流中读取第1个字符空格’ ';
  2. 对于第2个%c:前无空格字符,从输入流中读取第2个字符’a’;
  3. 对于第3个%c:前有空格字符,跳过输入流中的第3个字符空格’ ‘,读取第4个字符’b’。
2.1.2.1.4 字符合集
  1. %[character]:
    (1)从输入流中读取所有包含在字符合集中的字符;
    (2)字符合集是方括号括起来的字符;
    (3)遇到字符合集的字符时停止读取。
  2. %[^character]:
    (1)从输入流中读取字符合集之外的所有字符;
    (2)字符合集是方括号括起来的字符;
    (3)遇到字符合集的字符时停止读取。

示例代码如下所示:

int main()
{
   //
   char str1[80] = { 0 };
   char str2[80] = { 0 };
   char str3[80] = { 0 };
   //
   printf("以\"%%[^a-z]%%[a-z] %%[^a-z\\n]\"形式输入\"空格+123+abc+空格+456def\":\n");
   // 前两个格式说明符中前面无空格字符,后一个格式说明符前面有空格字符,第3个格式说明符必须将换行符'\n'排除在外
   scanf("%[^a-z]%[a-z] %[^a-z\n]", str1, str2, str3);
   //
   printf("str1 = %s\n", str1);
   printf("str2 = %s\n", str2);
   printf("str3 = %s\n", str3);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于%[^a-z]:
    (1)从输入流读取小写字母a-z之外的所有字符,包括空白字符;
    (2)前无空格字符,读取空格+123,遇到字母a停止读取;
  2. 对于%[a-z]:
    (1)从输入流读取小写字母a-z之间的所有字符;
    (2)前无空格字符,读取abc,遇到空格停止读取;
  3. 对于%[^a-z\n]:
    (1)从输入流读取小写字符a-z和换行符’\n’之外的所有字符,包括空白字符;
    (2)前有空格字符,先跳过输入流中的空格字符,后读取456,遇到字母d停止读取;
    (3)注意,此处必须将换行符’\n’排除在外,否则会一直提示继续输入。
2.1.2.1.5 字符串
  1. %s:
    (1)从输入流读取一个字符串;
    (2)期望的有效字符包括除空白字符外的所有ASCII码字符;
    (3)可自动跳过空白字符;
    (4)遇到无效字符时停止读取。

示例代码如下所示:

int main()
{
   //
   char str1[80] = { 0 };
   char str2[80] = { 0 };
   //
   printf("以\"%%s%%s\"形式输入\"空格+hello+空格+world\":\n");
   // 两个格式说明符前面无空格字符
   scanf("%s%s", str1, str2);
   //
   printf("%s\n", str1);
   printf("%s\n", str2);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于第1个%s:自动跳过第1个空格,读取hello,遇到第2个空格停止读取;
  2. 对于第2个%s:自动跳过第2个空格,读取world,遇到换行停止读取。
2.1.2.2 类型长度

类型长度字段在格式说明符中是可选的,cstdio库描述如下:

1. One of hh, h, l, ll, j, z, t, L (optional).
2. This alters the expected type of the storage pointed by the corresponding argument.

常用的类型长度字段如下图所示:

在这里插入图片描述

2.1.2.3 最大宽度

最大宽度字段在格式说明符中是可选的:

  1. 如果输入流中的有效字符数小于指定的最大宽度,则按照实际的有效字符数读取;
  2. 如果输入流中的有效字符数大于指定的最大宽度,则按照指定的最大宽度读取。

示例代码如下图所示:

int main()
{
   //
   int intData1 = 0;
   int intData2 = 0;
   //
   printf("以\"%%5d%%5d\"形式输入\"123+空格+456789\":\n");
   // 两个格式说明符前面无空格字符
   scanf("%5d%5d", &intData1, &intData2);
   //
   printf("%d\n", intData1);
   printf("%d\n", intData2);
   //
   return 0;
}

代码运行结果如下图所示:

在这里插入图片描述

代码及运行结果分析如下:

  1. 对于第1个%5d:指定最大宽度5,输入流中有3个有效字符123,读取123,遇到空格停止读取;
  2. 对于第2个%5d:指定最大宽度5,输入流中有6个有效字符456789,按指定最大宽度读取45678后停止读取。
2.1.2.5 特别说明
  1. 2.1.1节空白字符处理部分,对于自动跳过处理方式的描述并不完全准确,这里必须补充说明:
    (1)对于%d、%f、%e、%g和%s等格式说明符,会自动跳过输入流中的空白字符;
    (2)对于%c格式说明符,空白字符输入有效字符,必须在%c前面添加空白字符(如空格)来跳过输入流中的空白字符;
    (3)对于%[]和%[^]格式说明符,空白字符可能是有效字符,需要根据具体需求来决定是否跳过输入流中的空白字符。
  2. 格式说明符指定scanf()函数期望从标准输入流stdin中读取的有效字符范围,当遇到无效字符时停止读取,并将读取的无效字符回退至标准输入流stdin中

2.1.3 非空白字符(除了格式说明符%)

当scanf()函数在格式化字符串中遇到非空白字符,它会尝试从输入流中读取下一个字符,并将其与格式化字符串中的非空白字符进行比较。

  1. 如果这两个字符相匹配,那么继续处理格式化字符串中的下一个字符。
  2. 如果这两个字符不匹配,那么停止处理输入流中的后续字符。

特别说明:

  1. 在格式化字符串中,非空白字符不是必须的;
  2. 在格式化字符串中,只包含空白字符和格式说明符即可。

2.2 可变数量的参数

在scanf()函数中,可变数量的参数:

  1. 必不可少的;
  2. 数量和类型应与格式化字符串中的格式说明符相匹配;
  3. 类型是指针类型(如&变量名)。

cstdio库描述如下:

1. Depending on the format string, the function may expect a sequence of additional arguments, each containing a pointer to allocated storage where the interpretation of the extracted characters is stored with the appropriate type.
2. There should be at least as many of these arguments as the number of values stored by the format specifiers. Additional arguments are ignored by the function.
3. These arguments are expected to be pointers: to store the result of a scanf operation on a regular variable, its name should be preceded by the reference operator (&) .

3 返回值

scanf()函数的返回值类型为int型:

  1. 读取成功,返回成功读取的项数;
  2. 读取失败,返回EOF。

cstdio库描述如下:

1. On success, the function returns the number of items of the argument list successfully filled. 
2. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.
3. If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror). And, if either happens before any data could be successfully read, EOF is returned.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值