约 19860 字

约 99 分钟

#C 语言标准库函数 scanf

/*********************************************
 * @brief 从标准输入中获取输入
 * @param format 格式字符串
 * @param ... 可变长度参数,要打印的变量
 * @return 打印的字符数量
 ********************************************/
int scanf(const char* restrict format, ...);

说明

从标准输入中获取输入。

参数

  • format - 格式化字符串,指向以空字符(\0)结尾的字符串指针,指定如何解释数据
    • 普通字符直接输入,如果不匹配则导致失败
    • 转义字符按照转义打印
    • 空格字符将读取输入的所有连续空白字符,包括空格,\n,\t 等
    • 以 % 开头的 格式占位符,按照指定格式读取输入并写入后续相应位置的参数
  • ... - 可变长度参数,为接收输入的地址,需要与 format 参数中的格式占位符一一对应

返回值

  • 成功分配的接收参数的数量
  • 分配第一个接收参数之前发生匹配失败时返回 0
  • 分配第一个接收参数之前发生输入失败时返回 EOF

#示例

#include <stdio.h>

int main(void)
{
    int age;
    float height;
    double weight;
    char initial;
    char name[50];      // 存储姓名(无空格)
    char sentence[100];  // 存储带空格的整行输入

    // 示例1:读取整数、浮点数、字符
    printf("请输入您的年龄、身高(米)、体重(kg)和姓氏首字母(用空格分隔):");
    int items_read = scanf("%d %f %lf %c", &age, &height, &weight, &initial);

    if (items_read != 4) {
        printf("输入错误!请确保输入4个值(年龄 身高 体重 首字母)。\n");
        while (getchar() != '\n'); // 清空输入缓冲区
    } else {
        printf("结果:您今年%d岁,身高%.2f米,体重%.1lfkg,姓名首字母是'%c'。\n",
               age, height, weight, initial);
    }

    // 示例2:读取名称首字母(无空格)
    printf("\n请输入您的名称首字母(不要带空格):");
    if (scanf("%49s", name) == 1) {  // 限制长度防止溢出
        printf("您好,%s!\n", name);
    } else {
        printf("未能读取姓名。\n");
    }

    // 示例3:读取整行(允许空格)
    printf("\n请输入一句话(可以带空格):");
    while (getchar() != '\n'); // 清空之前的输入缓冲区
    if (scanf("%99[^\n]", sentence) == 1) {  // 读取直到换行符
        printf("您输入的是:「%s」\n", sentence);
    } else {
        printf("未接收到输入。\n");
    }

    // 示例4:安全读取整数(错误处理)
    int number;
    printf("\n请输入一个整数:");
    while (scanf("%d", &number) != 1) {  // 循环直到输入有效
        printf("输入无效!请重新输入整数:");
        while (getchar() != '\n'); // 清空缓冲区
    }
    printf("您输入的整数是:%d\n", number);

    return 0;
}

运行结果:

请输入您的年龄、身高(米)、体重(kg)和姓氏首字母(用空格分隔):17 160 50 h
结果:您今年17岁,身高160.00米,体重50.0kg,姓名首字母是'h'。

请输入您的名称首字母(不要带空格):bc
您好,bc!

请输入一句话(可以带空格):hello world
您输入的是:「hello world」

请输入一个整数:233
您输入的整数是:233

#格式占位符

格式占位符以 %[*][宽度][长度修饰]说明符 的形式出现。

  • * 是赋值抑制符,表示这部分输入不赋值给接收参数
  • 宽度:输入的最大字符数
  • 长度修饰:表示类型长度,例如 %d 是 int,而 %ld 是 long
说明符
说明
参数类型hhhllljztL
%百分号(%)本身---------
c单个字符char*--wchar_t-----
s字符串,以空字符(\0)结尾char*--wchar_t*-----
d有符号十进制整数int*signed char*short*long*long long*intmax_t*size_t*ptrdiff_t*-
i有符号十进制整数,同 %dint*signed char*short*long*long long*intmax_t*size_t*ptrdiff_t*-
u无符号十进制整数unsigned int*unsigned char*unsigned short*unsigned long*unsigned long long*uintmax_t*size_t*ptrdiff_t*-
o无符号八进制整数unsigned int*unsigned char*unsigned short*unsigned long*unsigned long long*uintmax_t*size_t*ptrdiff_t*-
x无符号十六进制整数,字母小写unsigned int*unsigned char*unsigned short*unsigned long*unsigned long long*uintmax_t*size_t*ptrdiff_t*-
X无符号十六进制整数,字母大写unsigned int*unsigned char*unsigned short*unsigned long*unsigned long long*uintmax_t*size_t*ptrdiff_t*-
f浮点数,字母小写float*--double*----long double*
F浮点数,同 %ffloat*--double*----long double*
e浮点数,科学计数法,字母小写float*--double*----long double*
E浮点数,科学计数法,字母大写float*--double*----long double*
g浮点数,省略小数末尾的 0,值较大时使用科学计数法,字母小写float*--double*----long double*
G浮点数,省略小数末尾的 0,值较大时使用科学计数法,字母大写float*--double*----long double*
a浮点数,十六进制,科学计数法,字母小写float*--double*----long double*
A浮点数,十六进制,科学计数法,字母大写float*--double*----long double*
p指针地址void*--------
n将当前已读取的字符数量写入参数中int*siged char*short*long*long long*intmax_t*size_t*ptrdiff_t*-
[set]匹配字符集合,类似正则表达式的中括号char*--wchar_t*-----

非字符类型的格式,例如 %d,%x 等,在读取输入时将忽略开头的空白字符,例如向 %d 输入 " 12 34" 可以得到 12," 34" 将保留在输入缓冲区。

匹配字符集合 [set] 用于指定匹配某些字符。例如:

  • %[abc] 表示读取连续的多个 a,b 或 c,遇到其它字符时停止匹配
  • %[^abc] 表示读取连续的多个除了 a,b,c 以外的字符,遇到 a,b 或 c时停止匹配
  • %[^\n] 表示读取连续的多个除了 \n 以外的字符,遇到 \n 时停止匹配;也就是读取整行
  • %[a-z] 表示读取连续的多个小写字母,遇到其它字符时停止匹配
  • %[0-9] 表示读取连续的多个数字,遇到其它字符时停止匹配
  • %9[0-9] 表示读取连续的多个数字,遇到其它字符时停止匹配;最多读取 9 个字符
  • %*[^A-Za-z] 表示读取连续的多个字母,遇到其它字符时停止匹配;并将这些输入丢弃

#特殊格式宏

由于 C 语言中类型的长度不是固定的。反过来说,固定长度的类型,其原始类型是不确定的。

例如 int32_t 在某些环境下是 int,另外某些环境下是 long;前者使用 scanf 读取时应使用 %d,而后者应使用 %ld。

为了方便,可以使用以下宏来标识格式。

scanf 格式标准说明
SCNd8C99scanf 中用于输入 int8_t 的 d 格式(有符号十进制)
SCNd16C99scanf 中用于输入 int16_t 的 d 格式
SCNd32C99scanf 中用于输入 int32_t 的 d 格式
SCNd64C99scanf 中用于输入 int64_t 的 d 格式
SCNdPTRC99scanf 中用于输入 intptr_t 的 d 格式
SCNdMAXC99scanf 中用于输入 intmax_t 的 d 格式
SCNdFAST8C99scanf 中用于输入 int_fast8_t 的 d 格式
SCNdFAST16C99scanf 中用于输入 int_fast16_t 的 d 格式
SCNdFAST32C99scanf 中用于输入 int_fast32_t 的 d 格式
SCNdFAST64C99scanf 中用于输入 int_fast64_t 的 d 格式
SCNdLEAST8C99scanf 中用于输入 int_least8_t 的 d 格式
SCNdLEAST16C99scanf 中用于输入 int_least16_t 的 d 格式
SCNdLEAST32C99scanf 中用于输入 int_least32_t 的 d 格式
SCNdLEAST64C99scanf 中用于输入 int_least64_t 的 d 格式
SCNi8C99scanf 中用于输入 int8_t 的 i 格式(有符号十进制)
SCNi16C99scanf 中用于输入 int16_t 的 i 格式
SCNi32C99scanf 中用于输入 int32_t 的 i 格式
SCNi64C99scanf 中用于输入 int64_t 的 i 格式
SCNiPTRC99scanf 中用于输入 intptr_t 的 i 格式
SCNiMAXC99scanf 中用于输入 intmax_t 的 i 格式
SCNiFAST8C99scanf 中用于输入 int_fast8_t 的 i 格式
SCNiFAST16C99scanf 中用于输入 int_fast16_t 的 i 格式
SCNiFAST32C99scanf 中用于输入 int_fast32_t 的 i 格式
SCNiFAST64C99scanf 中用于输入 int_fast64_t 的 i 格式
SCNiLEAST8C99scanf 中用于输入 int_least8_t 的 i 格式
SCNiLEAST16C99scanf 中用于输入 int_least16_t 的 i 格式
SCNiLEAST32C99scanf 中用于输入 int_least32_t 的 i 格式
SCNiLEAST64C99scanf 中用于输入 int_least64_t 的 i 格式
SCNu8C99scanf 中用于输入 uint8_t 的 u 格式(无符号十进制)
SCNu16C99scanf 中用于输入 uint16_t 的 u 格式
SCNu32C99scanf 中用于输入 uint32_t 的 u 格式
SCNu64C99scanf 中用于输入 uint64_t 的 u 格式
SCNuPTRC99scanf 中用于输入 uintptr_t 的 u 格式
SCNuMAXC99scanf 中用于输入 uintmax_t 的 u 格式
SCNuFAST8C99scanf 中用于输入 uint_fast8_t 的 u 格式
SCNuFAST16C99scanf 中用于输入 uint_fast16_t 的 u 格式
SCNuFAST32C99scanf 中用于输入 uint_fast32_t 的 u 格式
SCNuFAST64C99scanf 中用于输入 uint_fast64_t 的 u 格式
SCNuLEAST8C99scanf 中用于输入 uint_least8_t 的 u 格式
SCNuLEAST16C99scanf 中用于输入 uint_least16_t 的 u 格式
SCNuLEAST32C99scanf 中用于输入 uint_least32_t 的 u 格式
SCNuLEAST64C99scanf 中用于输入 uint_least64_t 的 u 格式
SCNo8C99scanf 中用于输入 uint8_t 的 o 格式(有符号八进制)
SCNo16C99scanf 中用于输入 uint16_t 的 o 格式
SCNo32C99scanf 中用于输入 uint32_t 的 o 格式
SCNo64C99scanf 中用于输入 uint64_t 的 o 格式
SCNoPTRC99scanf 中用于输入 uintptr_t 的 o 格式
SCNoMAXC99scanf 中用于输入 uintmax_t 的 o 格式
SCNoFAST8C99scanf 中用于输入 uint_fast8_t 的 o 格式
SCNoFAST16C99scanf 中用于输入 uint_fast16_t 的 o 格式
SCNoFAST32C99scanf 中用于输入 uint_fast32_t 的 o 格式
SCNoFAST64C99scanf 中用于输入 uint_fast64_t 的 o 格式
SCNoLEAST8C99scanf 中用于输入 uint_least8_t 的 o 格式
SCNoLEAST16C99scanf 中用于输入 uint_least16_t 的 o 格式
SCNoLEAST32C99scanf 中用于输入 uint_least32_t 的 o 格式
SCNoLEAST64C99scanf 中用于输入 uint_least64_t 的 o 格式
SCNx8C99scanf 中用于输入 uint8_t 的 x 格式(有符号十六进制,小写)
SCNx16C99scanf 中用于输入 uint16_t 的 x 格式
SCNx32C99scanf 中用于输入 uint32_t 的 x 格式
SCNx64C99scanf 中用于输入 uint64_t 的 x 格式
SCNxPTRC99scanf 中用于输入 uintptr_t 的 x 格式
SCNxMAXC99scanf 中用于输入 uintmax_t 的 x 格式
SCNxFAST8C99scanf 中用于输入 uint_fast8_t 的 x 格式
SCNxFAST16C99scanf 中用于输入 uint_fast16_t 的 x 格式
SCNxFAST32C99scanf 中用于输入 uint_fast32_t 的 x 格式
SCNxFAST64C99scanf 中用于输入 uint_fast64_t 的 x 格式
SCNxLEAST8C99scanf 中用于输入 uint_least8_t 的 x 格式
SCNxLEAST16C99scanf 中用于输入 uint_least16_t 的 x 格式
SCNxLEAST32C99scanf 中用于输入 uint_least32_t 的 x 格式
SCNxLEAST64C99scanf 中用于输入 uint_least64_t 的 x 格式

#推荐阅读

#参考标准

  • C17 standard (ISO/IEC 9899:2018):
    • 7.21.6.4 The scanf function (p: 236-237)
  • C11 standard (ISO/IEC 9899:2011):
    • 7.21.6.4 The scanf function (p: 325)
  • C99 standard (ISO/IEC 9899:1999):
    • 7.19.6.4 The scanf function (p: 290)
  • C89/C90 standard (ISO/IEC 9899:1990):
    • 4.9.6.4 The scanf function

更新: 2025/10/25

作者: PlanC

创建: 2025/6/30