【17】C语言-gets() 与 fgets() 函数

【17】C语言-gets() 与 fgets() 函数

文章目录

  • [1. **gets() 函数**](#1. gets() 函数)
  • [2. **fgets() 函数**(推荐使用)](#2. fgets() 函数(推荐使用))
  • [3. 重要区别对比](#3. 重要区别对比)
  • [4. **fgets() 的换行符问题**](#4. fgets() 的换行符问题)
  • [5. 实际使用示例](#5. 实际使用示例)
    • [5.1 安全输入示例:](#5.1 安全输入示例:)
    • [5.2 处理长输入:](#5.2 处理长输入:)

在现代C程序设计中,应该始终使用fgets()来替代不安全的gets()函数。


使用要点:

  1. 永远不要使用 gets()
  2. 总是使用 fgets() 替代 gets()
  3. 记得处理换行符
  4. 检查返回值确保读取成功
  5. 考虑输入缓冲区清理

1. gets() 函数

基本用法:

c 复制代码
char *gets(char *str);
  • 从标准输入读取一行字符串
  • 遇到换行符或文件结束符停止
  • 不检查数组边界,存在安全隐患

示例:

c 复制代码
#include <stdio.h>

int main() {
    char name[20];
    printf("请输入姓名:");
    gets(name);  // 危险!可能发生缓冲区溢出
    printf("你好,%s!\n", name);
    return 0;
}

⚠️ gets() 的问题

  • 缓冲区溢出风险:如果输入超过数组大小,会导致内存破坏
  • C11标准已弃用 ,C17标准中完全移除
  • 现代编译器会给出警告

2. fgets() 函数(推荐使用)

基本用法:

c 复制代码
char *fgets(char *str, int n, FILE *stream);
  • str:存储字符串的缓冲区
  • n:最大读取字符数(包括结尾的\0
  • stream:输入流(stdin 表示标准输入)

示例:

c 复制代码
#include <stdio.h>

int main() {
    char name[20];
    
    printf("请输入姓名:");
    fgets(name, sizeof(name), stdin);  // 安全!
    printf("你好,%s!\n", name);
    
    return 0;
}

3. 重要区别对比

特性 gets() fgets()
安全性 不安全,已弃用 安全,推荐使用
边界检查 有,指定最大长度
换行符处理 丢弃换行符 保留换行符在字符串中
返回值 成功返回str,失败返回NULL 成功返回str,失败返回NULL

4. fgets() 的换行符问题

fgets() 会保留换行符,需要手动处理:

c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char input[100];
    
    printf("输入字符串:");
    fgets(input, sizeof(input), stdin);
    
    printf("处理前的字符串:%s\n",input);
    printf("===========\n");
    
    // 去除换行符
    size_t len = strlen(input);
    if (len > 0 && input[len-1] == '\n') {
        input[len-1] = '\0';
    }
    
    printf("处理后的字符串:'%s'\n", input);
    return 0;
}

执行效果:

复制代码
输入字符串:abcd efgh ijklmn
处理前的字符串:abcd efgh ijklmn  

===========
处理后的字符串:'abcd efgh ijklmn'

(可以看到,处理前的字符串自带有换行符。)


5. 实际使用示例

5.1 安全输入示例:

c 复制代码
#include <stdio.h>
#include <string.h>

void safe_input() {
    char buffer[50];
    
    printf("请输入文本(最多%d字符):", sizeof(buffer)-1);
    
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // 去除换行符
        buffer[strcspn(buffer, "\n")] = '\0';
        
        printf("你输入的是:%s\n", buffer);
        printf("字符串长度:%zu\n", strlen(buffer));
    } else {
        printf("读取失败!\n");
    }
}

int main() {
    safe_input();
    return 0;
}

执行效果:

请输入文本(最多49字符):hello,world!

你输入的是:hello,world!

字符串长度:12

5.2 处理长输入:

c 复制代码
#include <stdio.h>

void clear_input_buffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

int main() {
    char line[10];
    
    printf("输入字符串:");
    fgets(line, sizeof(line), stdin);
    
    // 检查是否读取了完整行
    if (line[strlen(line)-1] != '\n') {
        printf("警告:输入被截断!\n");
        clear_input_buffer();  // 清空输入缓冲区
    }
    
    printf("结果:%s\n", line);
    return 0;
}

输入字符串:hello, hello, hello, world!!!

警告:输入被截断!

结果:hello, he


相关推荐
Chester_19998 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
EXI-小洲9 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
会周易的程序员9 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
机器视觉知识推荐、就业指导9 小时前
为什么老说“纯 Qt 没啥就业市场”?
开发语言·qt
telepan9 小时前
Qt 开发避坑与性能指南:如何优雅、安全地定义全局常量字符串?
开发语言·qt
m0_6952514910 小时前
Qt MaintenanceTool 使用国内镜像加速下载(超详细教程)
开发语言·qt
是隼人10 小时前
buuctf-pwn xdctf2015_pwn200题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
大衛說11 小时前
《Python 从入门到精通》系列总览与学习路线
开发语言·python·学习
可乐鸡翅yeah_12 小时前
hls.js 内存泄漏实战排查,直播 M3U8 长时间播放异常定位方案
开发语言·javascript·python·django·ecmascript·m3u8·m3u8在线
2601_9622035112 小时前
Java进阶07集合(续)
java·开发语言