C 语言中,scanf 函数如果没有适当限制输入的长度,可能会导致缓冲区溢出。这是因为 scanf 会将用户输入直接存储到指定的缓冲区中,如果用户输入超过了缓冲区的大小,就会覆盖相邻内存区域,导致未定义的行为。

1、使用宽度限定符限制读取字符数量

在使用 scanf 时,始终指定可以读取到缓冲区的最大字符数。这样可以确保 scanf 不会读取超过缓冲区容纳量的数据,防止溢出。

#include <stdio.h>

int main() {
    char buf[10];  // 定义一个字符数组,大小为 10
    printf("请输入一个字符串(最多9个字符):");
    
    // 使用 %9s 限制最多读取 9 个字符
    scanf("%9s", buf);
    
    printf("你输入的字符串是:%s\n", buf);  // 输出读取的字符串
    return 0;
}

2、使用 fgets 替代 scanf

fgets 通常是读取字符串时比 scanf 更安全的选择。与 scanf 不同,fgets 允许你指定最大读取字符数,包括空字符(null terminator),并且不会导致缓冲区溢出。

#include <stdio.h>

int main() {
    char buf[10];

    // 提示用户输入
    printf("请输入一个字符串(最多9个字符):");

    // 使用 fgets 从标准输入读取最多 9 个字符(包括空字符)
    fgets(buf, sizeof(buf), stdin);

    // 输出读取的内容
    printf("你输入的字符串是:%s\n", buf);

    return 0;
}

3、使用 scanf 时进行适当的验证

在某些情况下,你可能需要在读取用户输入后进行验证。这有助于确保输入符合预期的范围和格式,从而减少缓冲区溢出的风险。

#include <stdio.h>

int main() {
    char buf[10];

    printf("请输入一个字符串(最多9个字符):\n");
    if (scanf("%9s", buf) != 1) {  // 安全读取字符串
        printf("输入错误,请重试。\n");
        return 1;  // 返回错误代码
    }

    printf("您输入的字符串是:%s\n", buf);

    return 0;
}

4、避免不加检查的 scanf 调用

另一个防止缓冲区溢出的方法是避免在不安全的输入情况下使用 scanf。始终确保你知道缓冲区的确切大小,并使用适当的输入验证。

#include <stdio.h>

int main() {
    int x;

    // 提示用户输入一个整数
    printf("请输入一个整数:");
    
    // 使用 scanf 读取整数并存储到 x 中
    if (scanf("%d", &x) == 1) {
        // 如果成功读取整数,输出结果
        printf("您输入的整数是:%d\n", x);
    } else {
        // 如果输入不是有效的整数,给出提示
        printf("无效的输入,请输入一个整数。\n");
    }

    return 0;
}

推荐文档