ZetCode

C scanf 函数

最后修改日期:2025 年 4 月 6 日

输入处理是 C 编程中的一项基本技能,它使您能够高效地读取用户输入。scanf 函数是您从标准输入读取格式化输入的主要工具。本教程将深入探讨 scanf 的基础知识,解释其格式说明符,并提供实践示例。虽然 scanf 功能强大,但我们还将讨论更安全的替代方案,以用于输入验证至关重要的生产代码。

什么是 scanf?

C 中的 scanf 函数从标准输入(通常是键盘)读取格式化输入。它需要一个格式字符串来指定预期的输入类型以及应存储值的内存地址。常见的格式说明符包括整数的 %d 和字符串的 %s。请务必检查返回值以验证输入读取是否成功。出于安全考虑,请考虑使用 fgets 结合 sscanf 等替代方案。

基本整数输入

让我们从使用 scanf 读取整数的简单示例开始。

read_int.c
#include <stdio.h>

int main() {
    int number;

    printf("Enter an integer: ");
    int result = scanf("%d", &number);  // Read integer input

    if (result != 1) {  // Check if reading succeeded
        printf("Invalid input!\n");
        return 1;
    }

    printf("You entered: %d\n", number);
    return 0;
}

在这里,scanf 等待用户输入,并尝试使用 %d 格式说明符读取一个整数。& 运算符提供 number 的内存地址。我们检查返回值以确保成功读取了一个项目。这种基本模式适用于所有具有相应格式说明符的原始数据类型。

读取多个值

scanf 可以通过适当的格式说明符一次读取多个值。

read_multiple.c
#include <stdio.h>

int main() {
    int age;
    float height;
    char initial;

    printf("Enter age, height, and initial: ");
    int count = scanf("%d %f %c", &age, &height, &initial);

    if (count != 3) {
        printf("Expected 3 values, got %d\n", count);
        return 1;
    }

    printf("Age: %d, Height: %.2f, Initial: %c\n", 
           age, height, initial);
    return 0;
}

此示例演示了一次 scanf 调用中读取整数、浮点数和字符。格式字符串包含由空格分隔的三个说明符,与预期的输入格式匹配。返回值指示成功读取了多少个项目。请注意,格式字符串中的空格会匹配输入中的任何空白字符。

安全读取字符串

使用 scanf 读取字符串需要谨慎,以防止缓冲区溢出。

read_string.c
#include <stdio.h>

int main() {
    char name[50];  // Buffer for name

    printf("Enter your name (max 49 chars): ");
    int result = scanf("%49s", name);  // Limit input length

    if (result != 1) {
        printf("Failed to read name\n");
        return 1;
    }

    printf("Hello, %s!\n", name);
    return 0;
}

%49s 格式说明符将输入限制为 49 个字符(加上空终止符),以防止溢出。对于生产代码,fgets 更安全,因为它提供了对输入长度的更好控制。在使用 %sscanf 时,请务必指定最大宽度,以避免安全漏洞。

高级格式

scanf 支持复杂的格式字符串以进行精确的输入解析。

advanced_format.c
#include <stdio.h>

int main() {
    int day, month, year;
    char separator;

    printf("Enter date (dd-mm-yyyy): ");
    int count = scanf("%2d%c%2d%c%4d", 
                      &day, &separator, 
                      &month, &separator, 
                      &year);

    if (count != 5) {
        printf("Invalid date format\n");
        return 1;
    }

    printf("Day: %d, Month: %d, Year: %d\n", 
           day, month, year);
    return 0;
}

此示例以严格的格式解析日期。%2d 读取日和月的两个数字,而 %4d 读取年的四个数字。相同的分隔符字符被读取两次。这展示了 scanf 在格式得到严格控制时解析结构化输入的能力。

处理输入错误

适当的错误处理可以使 scanf 在实际应用程序中更加健壮。

error_handling.c
#include <stdio.h>
#include <stdlib.h>

int main() {
    int number;
    char input[100];

    while (1) {
        printf("Enter a number (0 to exit): ");
        
        if (fgets(input, sizeof(input), stdin) == NULL) {
            printf("Input error\n");
            return 1;
        }

        if (sscanf(input, "%d", &number) != 1) {
            printf("Invalid number, try again\n");
            continue;
        }

        if (number == 0) break;

        printf("You entered: %d\n", number);
    }

    return 0;
}

此示例展示了一种使用 fgetssscanf 的更安全方法。它首先读取整行,然后对其进行解析。此方法可防止许多常见的 scanf 问题,例如缓冲区中遗留的字符。循环继续,直到收到有效输入或用户输入 0。建议使用此模式进行健壮的输入处理。

使用 scanf 的最佳实践

来源

C scanf 文档

本教程探讨了 C 中的 scanf 函数,从基本用法到高级格式。虽然功能强大,但请记住 scanf 有其局限性和安全注意事项。对于生产代码,请考虑使用 fgets 和解析函数等更安全的方法。

作者

我叫 Jan Bodnar,是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享我的专业知识。凭借十多年的教学经验,我致力于让编程变得易于理解且引人入胜。

列表 C 标准库