首页 > C语言笔记

C语言gets_s()和gets()有什么区别?

C语言中的 gets_s()gets() 函数都用于从标准输入读取字符串,但它们在安全性和使用方式上有显著的区别。

gets() 函数

gets() 是一个传统的 C 语言函数,用于从标准输入读取一行文本。gets() 会一直读取直到遇到换行符或文件结束符。然而,gets() 函数存在严重的安全隐患,因为它不会检查输入的长度是否超过目标缓冲区的大小。


使用 gets() 的示例代码:

#include <stdio.h>

int main() {
    char buffer[10];
    printf("请输入一个字符串:");
    gets(buffer);
    printf("你输入的是:%s\n", buffer);
    return 0;
}

这段代码看似简单,但存在严重的缓冲区溢出风险。如果用户输入的字符串超过 9 个字符(不包括结尾的空字符),就会导致缓冲区溢出,可能会覆盖栈中的其他数据,造成程序崩溃或安全漏洞。


正是由于这个原因,gets() 函数在 C11 标准中被废弃,并在后续的标准中被移除,现代编译器通常会对使用 gets() 的代码发出警告。

gets_s() 函数

gets_s() 是 C11 标准引入的一个更安全的替代函数,它要求指定缓冲区的大小,从而可以防止缓冲区溢出。

注意:gets_s() 只是 C11 标准的扩展部分,或者可选部分,并不是所有的编译器都必须实现 gets_s(),使用之前请亲自测试,以确保该函数有效。

使用 gets_s() 的示例代码:

#include <stdio.h>

int main() {
    char buffer[10];
    printf("请输入一个字符串:");
    if (gets_s(buffer, sizeof(buffer)) == NULL) {
        printf("输入错误或缓冲区溢出\n");
        return 1;
    }
    printf("你输入的是:%s\n", buffer);
    return 0;
}

在这个例子中,gets_s() 函数接受两个参数:缓冲区指针和缓冲区的大小。如果输入的字符串长度超过了指定的缓冲区大小减 1(为空字符留出空间),gets_s() 会停止读取,丢弃多余的输入,并返回 NULL。

gets_s() 和 gets() 的主要区别

总起来说,两个函数的区别主要有以下几点:
  1. 安全性: gets_s() 通过指定缓冲区大小来防止缓冲区溢出,而 gets() 没有这种保护机制。
  2. 参数: gets_s() 需要两个参数(缓冲区指针和大小),而 gets() 只需要一个参数(缓冲区指针)。
  3. 错误处理: 当发生错误时,gets_s() 会返回 NULL 并设置 errno,而 gets() 没有有效的错误检查机制。
  4. 可移植性: 并非所有的编译器都支持 gets_s(),这可能会影响代码的可移植性。


尽管 gets_s() 比 gets() 安全得多,但并不是所有的编译器都支持,所以在实际编程中,我们通常会选择其他更灵活和可移植的函数来读取输入。例如,fgets() 函数是一个很好的选择:

#include <stdio.h>
#include <string.h>

int main() {
    char buffer[10];
    printf("请输入一个字符串:");
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // 移除换行符(如果存在)
        buffer[strcspn(buffer, "\n")] = 0;
        printf("你输入的是:%s\n", buffer);
    } else {
        printf("输入错误\n");
    }
    return 0;
}

fgets() 函数不仅安全,而且更加灵活,因为它允许你指定从哪个输入流读取数据。


总结来说,gets_s() 虽然比 gets() 安全,但由于可移植性问题和使用限制,在非 Windows 编程中并不常用。对于安全且可移植的字符串输入,推荐使用 fgets() 函数。

相关文章