c - %(limit)[^\n] 在 scanf 中的行为是什么?溢出安全吗?

标签 c buffer scanf buffer-overflow

scanf 函数的格式 %(limit)[^\n] 不安全? (其中(limit)是字符串的长度-1)

如果不安全,为什么?

是否有一种安全的方法来实现仅使用 scanf() 捕获字符串的函数?

在 Linux 程序员手册中,(在终端上键入 man scanf),s 格式表示:

Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'),which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

输入字符串总是在最大字段宽度处停止?或者只是在 GCC 上?

谢谢。

最佳答案

%(limit)[^\n]对于 scanf"通常是安全的。

在下面的示例中,最多 99 char将被读取并保存到 buf .如果有char被保存,一个'\0'将附加和cnt将是 1。

char buf[100];
int cnt = scanf("%99[^\n]", buf);

功能当然安全,但其他功能呢?


当输入是单独的时会出现问题 "\n" .

在这种情况下,buf 中没有保存任何内容并返回 0。如果下一行代码如下,则输出为 Undefined Behavior作为buf未初始化为任何内容。

puts(buf);

更好的下一行是

if (cnt == 1) puts(buf);
else printf("Return count = %d\n", cnt);

问题是因为 '\n'没有被消耗掉。

'\n'仍在等待阅读和另一个调用 scanf("%99[^\n]", buf);不会读 '\n' .


问:仅使用 scanf() 即可安全地实现捕获字符串的函数
A:迂腐地:不容易。

scanf() , fgets()等最适合阅读文本,而不是字符串。在 C 中,字符串是 char 的数组以 '\0' 结尾.通过 scanf() 输入, fgets()等通常有阅读问题 '\0'通常是 char无论如何都不在输入中。通常输入被认为是一组 char终止于 '\n'或其他空白。

如果代码正在读取以 '\n' 终止的输入, 使用 fgets()运行良好且便于携带。 fgets()它也有以各种方式处理的弱点。 getline()是一个不错的选择。

近似值是 scanf(" %99[^\n]", buf) (注意添加的 " " ),但仅此并不能解决处理过多的长行、读取多个空行、嵌入 '\0' 的问题检测、报告长度读取的能力丧失(strlen() 由于嵌入 '\0' 而不起作用)并留下尾随 '\n ' 在 stdin .

缺少使用scanf("%c", &ch)有很多周围的代码(这很愚蠢,只需使用 fgetc() ),我看不出使用单个 scanf() 的方法读取一行用户输入时绝对安全。


问:输入字符串总是停在最大字段宽度处?
答:用scanf("%99[^\n]" , 输入停止 1) 当 '\n'遇到-'\n'未保存并保留在文件输入缓冲区中 2) 99 char已读取 3) 发生 EOF 或 4) 发生 IO 错误(很少见)。

关于c - %(limit)[^\n] 在 scanf 中的行为是什么?溢出安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26887125/

相关文章:

c - 退出应用程序时如何删除 UNIX 域套接字文件?

c++: 将 vector<char> 转换为 double

javascript - XMLHttpRequest 分块下载大型 HTML5 视频?

c - sscanf 和正确的格式文件

c - 在没有初始化的情况下使用带有指针的 scanf 有什么问题?

在 C 中使用 AES-256 和 openssl 计算 CBC-MAC

c - 如何修复 "assignment makes integer without a cast"**更新**

c - 带有可变长度尾部的普通 "C"静态初始化程序宏。

c# - MemoryStream.Read 不会将字节复制到缓冲区 - c#

c - Scanf 似乎无法在带有 GDB 的 Eclipse CDT 中以 Debug模式工作