gets()的结构性缺陷和补救措施

本文探讨了C语言中gets函数的安全问题,由于可能导致缓冲区溢出,它已被视为不安全。建议使用fgets和gets_s作为替代。fgets允许指定最大读取字符数以防止溢出,而gets_s是C11标准引入的更安全选项,限制读取长度并丢弃超出的字符。然而,gets_s在字符过长时会丢弃早期数据,可能不适用于所有情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

gets与系统安全问题

gets函数的存在意义在于取代scanf,因scanf和转换说明%s只能读取一个单词,遇到空符读取就会终止,如要读取一整行输入scanf就显得捉襟见肘。而gets可以解决这个问题:gets可以读取整行输入直至读取到换行符,后丢弃换行符,存储字符,在末位加一个空符形成字符串。

gets的局限在于其无法检查数组是否装得下输入行,因此gets只能查出数组的初始地址却查不出数组元素数。若输入字符超出字符串定义的容量会导致缓冲区溢出,可能危害系统安全,尤其是在内存被占满的情况下。

此时输入的字符数已经超出了定义时所规定的元素数,但dev没有发出警告。

替代方案

fgets()

fgets通常用于替代gets。

char *__cdecl fgets(char * __restrict__ _Buf,int _MaxCount,FILE * __restrict__ _File);
fgets(目标字符串变量,字符数,来源(文件));

fgets通过添加第二个参数限制字符数来处理溢出问题。该函数专门用于处理文件输入。

与fgets的区别:

·fgets比起gets多了两个参数,其中一个参数决定了读入字符的最大量。若参数值为n,fgets将最多读入n-1个字符(第n个位换行符)或者在之前读到一个换行符就终止读取。

·fgets同比gets会把换行符保留在字符串中,gets会丢弃换行符。

fgets的第三个参数指明要读入的文件。

fgets() 函数会在遇到换行符时停止,并且其保存到内存中的数据会包含该换行符,而 gets() 函数会排除换行符。因此,就简单的这么重写代码无法实现完全同等的功能。而为了保证代码安全,又实现完全相同的功能,我们就需要检查内存地址中的字符,如果在结尾有换行符,需要将其删除。

char *last = input strlen(input) – 1;
if (*last == 'n')
    *last = '';

可是,虽然代码变复杂了,但是还是存在一个隐藏问题,该问题会导致程序崩溃,或者有安全隐患。当程序执行时,如果标准输入流已经得到了所有可用的字符,但是还没有遇到文件结束符( EOF), fgets() 函数将会通过将 input[0] 标记为 NULL 字符的形式,直接返回一个 NULL 字符串。此时, strlen(intput) 的返回值为0, 因此导致 last 指针指向 input 数组之前的那个字符。因为不能确定这个字符到底是什么,这段代码的行为将因此无法判断 。

gets_s()

gets_s为C11新增,与fgets类似,用一个参数限制读入字符数。

与fgets的区别如下:

*gets_s只从标准输入中读取数据,不需要第三个参数

*丢弃而不是存储换行符

*若gets_s读取至最大字符数都没有读取至换行符,会把最早读取的字符数据丢弃,读入接下来的数据直至读到换行符或文件结尾,后返回NULL。

因此若输入行未超过最大字符数则可用gets_s取代fgets。

gets_s安全性也高于gets,但如果字符过长,gets_s会丢弃早期读取的字符,无论是否需要。这意味着gets_s的指令不方便也不够灵活。

### getchar gets 函数的区别及用法 #### getchar函数 `getchar()` 是标准输入流 `stdin` 的一种简单形式,用于读取单个字符。每次调用此函数会从输入缓冲区中获取下一个可用字符并返回其 ASCII 值;如果到达文件结束或发生错误,则返回 EOF[^1]。 ```c #include <stdio.h> int main() { int ch; printf("Enter characters (type 'q' to quit):\n"); while ((ch = getchar()) != 'q') { putchar(ch); } } ``` 这段代码展示了如何利用 `getchar()` 来逐字节读入数据直到遇到特定终止符 `'q'` 为止,在这个过程中每一个被读到的字符都会立即显示出来。 #### gets函数 相比之下,`gets(s)` 则是从标准输入设备读一串字符串(不包括换行符),一直读到遇见第一个换行符或者EOF,并将其存储于指定位置 s 中。需要注意的是,由于无法控制最大长度,这可能导致缓冲溢出漏洞,因此在现代编程实践中已被认为是危险的做法并且不再推荐使用。 ```c #include <stdio.h> #define MAX_LINE_LENGTH 100 int main(){ char str[MAX_LINE_LENGTH]; printf("Please enter a string:\n"); if(fgets(str, sizeof(str), stdin)){ // Process input... puts(str); } else{ fprintf(stderr,"Error reading from standard input.\n"); } } ``` 这里采用更安全的方式通过 `fgets()` 替代了过时且存在风险的 `gets()` 方法来处理多字符输入操作。这样可以有效防止潜在的安全隐患同时保持原有功能特性不变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值