关于 gets 函数

gets 由于具有缓冲区溢出的安全性问题(具体是输入的字符串长度超过传入的字符数组长度),自 C11 标准开始已被移除[1],需要使用 fgets 或者 gets_s 代替。以下是解决方案

使用 fgets

fgets 用于从文件流中读取字符串,其原型如下[2]

char* fgets(char* restrict str, int count, FILE* restrict stream);

其中 str 为第一个参数,表示目标字符数组;count 为第二个参数,表示字符数组的长度(读取到该长度时读取将会终止);stream 为要读取的文件流,若要从控制台(标准输入流)读取则应当使用 stdin

使用 fgets 代替 gets 读取一行字符串至字符数组 str 示例:

gets

gets(str);

fgets

fgets(str, sizeof(str), stdin);

相关参数可以根据实际情况调整。

使用 gets_s

gets_s 起源于 Microsoft Secure-enhanced CRT,于 C11 正式加入[1:1]。要在除 MSVC 以外的平台上启用必须在代码的开头加入

#define __STDC_WANT_LIB_EXT1__ 1

其原型如下[1:2]

char* gets_s(char* str, rsize_t n);

其中 str 为第一个参数,表示目标字符数组;count 为第二个参数,表示字符数组的长度(读取到该长度时读取将会终止)。相比 fgets 少了文件流参数。

使用 fgets 代替 gets 读取一行字符串至字符数组 str 示例:

gets

gets(str);

gets_s

gets_s(str, sizeof(str));

相关参数可以根据实际情况调整。

关于 scanf

scanf 在输入字符串等时与 gets 同样由于具有缓冲区溢出的安全性问题,在 Microsoft Visual C++ 平台上会被要求使用 scanf_s 代替,以下是解决方案

仍然使用 scanf

在代码第一行加入

#define _CRT_SECURE_NO_WARNINGS

即可在 Microsoft Visual C++ 平台上忽略安全性问题并继续

切换到 scanf_s

scanfs_s 亦起源于 Microsoft Secure-enhanced CRT,于 C11 正式加入[3]。要在除 Microsoft Visual C++ 以外的平台上启用必须在代码的开头加入

#define __STDC_WANT_LIB_EXT1__ 1

在使用时若要读取字符或字符串,则需要在相应参数后应附带缓冲区大小。


  1. cppreference::c::io::gets ↩︎ ↩︎ ↩︎

  2. cppreference::c::io::fgets ↩︎

  3. cppreference::c::io::fscanf ↩︎