首页 > C语言笔记

C语言gets()、fgets()和gets_s()读取字符串

在C语言中,读取字符串是一个常见的操作,有几种不同的函数可以用来完成这个任务,其中包括 gets()、fgets() 和 gets_s()。这些函数虽然都用于读取字符串,但它们在安全性和使用方式上有着显著的差异。

gets() 函数

gets() 函数是最简单的字符串输入函数,但也是最不安全的。gets() 会从标准输入(通常是键盘)读取字符,直到遇到换行符或文件结束符。然而,gets() 不会检查输入的长度是否超过目标数组的大小,这可能导致缓冲区溢出,是一个严重的安全隐患。


以下是 gets() 的使用示例:

#include <stdio.h>

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

输出结果可能如下:

请输入一个字符串:Hello, World!
你输入的是:Hello, World!

在这个例子中,如果用户输入的字符串超过 9 个字符(不包括空字符),就会发生缓冲区溢出。由于这个安全问题,gets() 函数在 C11 标准中已被废弃,现代 C 编译器通常会对其使用发出警告。

fgets() 函数

fgets() 是一个更安全的替代方案,它允许指定要读取的最大字符数,从而防止缓冲区溢出。fgets() 函数的原型如下:

char *fgets(char *str, int n, FILE *stream);

这里,str 是目标字符数组,n 是要读取的最大字符数(包括空字符),stream 是输入流(如果从标准输入读取,使用 stdin)。


以下是 fgets() 的使用示例:

#include <stdio.h>

int main() {
    char str[10];
    printf("请输入一个字符串:");
    fgets(str, sizeof(str), stdin);
    printf("你输入的是:%s", str);
    return 0;
}

输出结果可能如下:

请输入一个字符串:Hello, World!
你输入的是:Hello, Wo

注意,fgets() 会保留输入中的换行符(如果读取到的话)。如果输入超过指定的长度,fgets() 会截断输入,确保不会发生缓冲区溢出。

gets_s() 函数

gets_s() 是 C11 标准引入的一个安全版本的 gets(),它的行为类似于 fgets(),但专门用于从标准输入读取。gets_s() 的原型如下:

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

这里,str 是目标字符数组,n 是数组的大小。gets_s() 会读取直到遇到换行符、文件结束符或达到 n-1 个字符。另外,gets_s() 总是在字符串末尾添加结束符\0

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

以下是 gets_s() 的使用示例:

#include <stdio.h>

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

输出结果可能如下:

请输入一个字符串:Hello, World!
输入错误

如果输入超过指定长度,gets_s() 会清空输入缓冲区,将 str 的第一个字符设置为空字符,并返回 NULL。这提供了一种错误处理机制,使程序能够对输入错误做出响应。

对比和总结

让我们比较这三个函数的主要特点:


考虑到安全性和可移植性,fgets() 通常是最佳选择,它既安全又被广泛支持。如果你的编译器支持 gets_s(),并且只需要从标准输入读取,gets_s() 也是一个很好的选择。无论如何,都应该避免使用 gets(),因为它存在严重的安全隐患。

相关文章