【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


相关推荐
小罗和阿泽39 分钟前
接口测试系列 接口自动化测试 pytest框架(三)
开发语言·python·pytest
毕设源码-邱学长7 小时前
【开题答辩全过程】以 基于Java的学校住宿管理系统的设计与实现为例,包含答辩的问题和答案
java·开发语言
rookieﻬ°8 小时前
PHP框架漏洞
开发语言·php
busideyang9 小时前
为什么推挽输出不能接收串口数据,而准双向口可以?
c语言·stm32·单片机·嵌入式硬件·嵌入式
炸膛坦客9 小时前
单片机/C/C++八股:(二十)指针常量和常量指针
c语言·开发语言·c++
爱编码的小八嘎9 小时前
C语言完美演绎4-8
c语言
兑生9 小时前
【灵神题单·贪心】1481. 不同整数的最少数目 | 频率排序贪心 | Java
java·开发语言
炸膛坦客10 小时前
单片机/C/C++八股:(十九)栈和堆的区别?
c语言·开发语言·c++
零雲10 小时前
java面试:了解抽象类与接口么?讲一讲它们的区别
java·开发语言·面试
Jay_Franklin10 小时前
Quarto与Python集成使用
开发语言·python·markdown