当前位置:首页 » 《随便一记》 » 正文

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

29 人参与  2024年12月09日 08:01  分类 : 《随便一记》  评论

点击全文阅读


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() 等安全函数,可以有效避免程序中的安全漏洞,确保程序的安全性和稳定性。


点击全文阅读


本文链接:http://zhangshiyu.com/post/198404.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1