C知识扫盲------scanf() 和 scanf_s()与缓冲区

1. 简介

scanf() 和 scanf_s() 是 C 语言中用于从标准输入读取格式化数据的函数。它们通过指定格式说明符,从输入流中读取并解析数据,然后存储在对应的变量中。

2.scanf() 函数

1.函数原型

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

2.基本用法

scanf() 函数从标准输入(通常是键盘)中读取数据,并根据提供的格式说明符解析数据。它将读取到的数据存储到相应的变量地址中。

1.常见格式说明符

%d: 读取十进制整数
%f: 读取浮点数
%c: 读取单个字符
%s: 读取字符串(以空白字符结束)
%lf: 读取双精度浮点数
%p: 读取指针
%x: 读取十六进制整数
%o: 读取八进制整数

2.返回值

scanf() 函数的返回值是成功读取并赋值的输入项数量。返回值为 0 或 EOF(通常为 -1)表示输入失败或遇到文件结束。

3.注意事项
  • 地址传递: 对于非数组类型,必须传递变量的地址,如 &variable。
  • 缓冲区溢出: 读取字符串时,需要确保目标数组有足够的空间存储输入数据及终止符 \0。
  • 格式说明符匹配: 提供的格式说明符必须与变量类型匹配,否则可能导致未定义行为。
  • 空格处理: scanf() 默认会跳过空白字符,但 %c 除外。读取字符时,可以在 %c 前加一个空格来跳过空白字符。
  • 未处理的输入: scanf() 遇到不符合格式说明符的数据时,会将其留在输入缓冲区中,可能会影响后续的输入读取。
#include <stdio.h>

int main() {
    int num;
    float fnum;
    char ch;
    char str[100];

    printf("请输入一个整数: ");
    scanf("%d", &num);

    printf("请输入一个浮点数: ");
    scanf("%f", &fnum);

    printf("请输入一个字符: ");
    scanf(" %c", &ch); // 注意前面的空格

    printf("请输入一个字符串: ");
    scanf("%s", str);

    printf("整数: %d, 浮点数: %.2f, 字符: %c, 字符串: %s\n", num, fnum, ch, str);

    return 0;
}

以上代码可能在Visual Studio 编译器中出现以下警告和报错:
在这里插入图片描述
这个时候就需要scanf_s()函数了

2.scanf_s() 函数

1.函数原型

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

2.基本用法

scanf_s() 是 scanf() 的安全版本,用于避免常见的安全问题(如缓冲区溢出)。与 scanf() 类似,它从标准输入中读取数据并根据格式说明符解析数据。

1.与 scanf() 的区别
  • 安全性: scanf_s() 要求额外提供缓冲区大小信息,以防止缓冲区溢出。这主要适用于字符串和字符数组的读取
  • 附加参数: 读取字符串和字符时,scanf_s() 需要提供附加参数,指定目标缓冲区的大小
2.返回值

scanf_s() 的返回值和 scanf() 相同,返回成功读取并赋值的输入项数量。遇到输入失败或文件结束时,返回 0 或 EOF。

#include <stdio.h>

int main() {
    int num;
    float fnum;
    char ch;
    char str[100];

    printf("请输入一个整数: ");
    scanf_s("%d", &num);

    printf("请输入一个浮点数: ");
    scanf_s("%f", &fnum);

    printf("请输入一个字符: ");
    scanf_s(" %c", &ch, 1); // 需要提供字符的缓冲区大小

    printf("请输入一个字符串: ");
    scanf_s("%s", str, (unsigned)sizeof(str)); // 需要提供字符串的缓冲区大小

    printf("整数: %d, 浮点数: %.2f, 字符: %c, 字符串: %s\n", num, fnum, ch, str);

    return 0;
}

在这里插入图片描述

3.缓冲区及其安全性

1.缓冲区是什么?

缓冲区(Buffer)是用于临时存储数据的内存区域。在 C 语言中,缓冲区通常用于存储字符串或字符数组。在 scanf() 和 scanf_s() 函数中,缓冲区是用来存放从输入中读取的数据的区域。

2.缓冲区溢出

缓冲区溢出(Buffer Overflow)是指当输入数据的长度超过了缓冲区的容量时,多余的数据会覆盖在内存中相邻的其他数据上。缓冲区溢出是一种常见的安全漏洞,可能导致程序崩溃或被恶意利用执行任意代码。

#include <stdio.h>

int main() {
    char str[5];
    scanf("%s", str); // 如果输入超过5个字符,将会导致缓冲区溢出
    printf("You entered: %s\n", str);
    return 0;
}

在上例中,如果用户输入超过 4 个字符(第五个字符是终止符 \0),将会导致 str 缓冲区溢出,覆盖其他内存区域,可能引发未定义行为。

当然,上述程序同样在Visual Studio 编译器中出现以下警告和报错:在这里插入图片描述

3.避免缓冲区溢出的方法

  • 使用 scanf_s(): scanf_s() 要求提供缓冲区大小参数,有助于防止溢出。
  • 限制输入长度: 使用格式说明符限制读取的字符数,例如 %99s 限制最多读取 99 个字符到一个 100 字节的缓冲区。
  • 检查输入长度: 在处理输入之前,确保输入的长度在缓冲区的容量范围内。

示例1(使用 scanf_s)

#include <stdio.h>

int main() {
    char str[5];
    scanf_s("%s", str,(unsigned)sizeof(str));  // 指定缓冲区大小为 5
    printf("You entered: %s\n", str);
    return 0;
}

4字符及4字符以下:
在这里插入图片描述
5字符及5字符以上:
在这里插入图片描述
示例2:(使用 scanf_s的同时 使用格式说明符限制读取的字符数)

#include <stdio.h>

int main() {
    char str[5];
    scanf_s("%4s", str, (unsigned)sizeof(str)); // 指定缓冲区大小为 5 并限制最多读取4个字符
    printf("You entered: %s\n", str);
    return 0;
}

4字符及4字符以下:
在这里插入图片描述

5字符及5字符以上:
在这里插入图片描述

%4s 限制最多读取 4 个字符,
scanf_s 的第三个参数 (unsigned)sizeof(str) 提供了缓冲区的实际大小

4.缓冲区操作中的常见错误

  • 忽略输入长度: 忽略输入长度可能导致缓冲区溢出,尤其是处理字符串时。
  • 未处理换行符: 使用 %c 读取字符时,未处理输入流中的换行符可能导致读取预期之外的数据。
  • 未清空缓冲区: 当 scanf() 读取的数据不符合格式说明符时,未清空缓冲区可能影响后续的输入操作。

4.总结

scanf() 和 scanf_s() 是用于读取标准输入的函数,但在使用时需要特别注意安全性。缓冲区溢出是常见的安全问题,scanf_s() 通过要求指定缓冲区大小来防止这种问题。 了解缓冲区的作用和常见错误,以及使用 scanf_s() 等安全函数,可以有效避免程序中的安全漏洞,确保程序的安全性和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值