【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


相关推荐
胡桃夹夹子3 小时前
存档111111111
java·开发语言
不会编程的小寒3 小时前
C++ 中string的用法
java·开发语言
想搞艺术的程序员3 小时前
Go Error 全方位解析:原理、实践、扩展与封装
开发语言·后端·golang
闲人编程3 小时前
Python游戏开发入门:Pygame实战
开发语言·python·游戏·pygame·毕设·codecapsule
是苏浙4 小时前
零基础入门C语言之枚举和联合体
c语言·开发语言
报错小能手4 小时前
C++笔记(面向对象)静态联编和动态联编
开发语言·c++·算法
小肖爱笑不爱笑4 小时前
2025/11/5 IO流(字节流、字符流、字节缓冲流、字符缓冲流) 计算机存储规则(ASCII、GBK、Unicode)
java·开发语言·算法
手握风云-4 小时前
Java 数据结构第二十八期:反射、枚举以及 lambda 表达式
java·开发语言
ᐇ9594 小时前
Java Vector集合全面解析:线程安全的动态数组
java·开发语言