【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


相关推荐
多多*2 分钟前
Java复习 操作系统原理 计算机网络相关 2025年11月23日
java·开发语言·网络·算法·spring·microsoft·maven
p***434815 分钟前
Rust网络编程模型
开发语言·网络·rust
ᐇ95927 分钟前
Java集合框架深度实战:构建智能教育管理与娱乐系统
java·开发语言·娱乐
梁正雄1 小时前
1、python基础语法
开发语言·python
强化学习与机器人控制仿真1 小时前
RSL-RL:开源人形机器人强化学习控制研究库
开发语言·人工智能·stm32·神经网络·机器人·强化学习·模仿学习
百***48071 小时前
【Golang】slice切片
开发语言·算法·golang
q***92512 小时前
Windows上安装Go并配置环境变量(图文步骤)
开发语言·windows·golang
仟濹2 小时前
【Java 基础】面向对象 - 继承
java·开发语言
郝学胜-神的一滴2 小时前
Linux命名管道:创建与原理详解
linux·运维·服务器·开发语言·c++·程序人生·个人开发
智者知已应修善业2 小时前
【51单片机普通延时奇偶灯切换】2023-4-4
c语言·经验分享·笔记·嵌入式硬件·51单片机