C 语言11:输入方法全解析

目录

一:为什么要谈及输入方法

二、缓冲区(Buffer)是什么?

1:定义

[2. 为什么要有缓冲区?](#2. 为什么要有缓冲区?)

[3. 缓冲区的类型](#3. 缓冲区的类型)

三、常见输入函数详解

[1. scanf()](#1. scanf())

[2. getchar()](#2. getchar())

[3. gets()(已废弃,不推荐使用)](#3. gets()(已废弃,不推荐使用))

[4. fgets()](#4. fgets())

[5. putchar()](#5. putchar())

四、缓冲区的影响与常见问题

[问题 1:scanf 连续读取](#问题 1:scanf 连续读取)

[问题 2:循环读取时残留数据](#问题 2:循环读取时残留数据)

五、各种输入方法对比

六、实用技巧

1:清空缓冲区:

2:安全读取字符串:

[3:混合使用 scanf 和 fgets 时,先清空缓冲区:](#3:混合使用 scanf 和 fgets 时,先清空缓冲区:)

七、总结


一:为什么要谈及输入方法

在 C 语言中,我们经常需要从键盘读取数据,比如:

cpp 复制代码
int a;
scanf("%d", &a);

但很多初学者会遇到 "程序好像卡住了"、"输入一次却输出两次"、"跳过了输入步骤" 等奇怪问题。

这些现象大多与输入缓冲区(Buffer) 的工作机制有关。


二、缓冲区(Buffer)是什么?

1:定义

缓冲区是一块临时存储数据的内存区域。当你从键盘输入时,数据并不会立刻被程序读取,而是先存到缓冲区里,等满足一定条件时,程序才会去读取。

2. 为什么要有缓冲区?

  • 减少 I/O 次数:直接每次读取键盘会很慢,缓冲区可以攒一批数据一次性给程序。
  • 方便用户编辑:在按回车前,你可以用退格键修改输入。

3. 缓冲区的类型

  1. **全缓冲(Full Buffering)**缓冲区满了才会被刷新(交给程序)。常见于文件操作。
  2. 行缓冲(Line Buffering) 遇到换行符 \n 才会刷新。键盘输入通常是行缓冲。
  3. 无缓冲(No Buffering) 输入立即被读取,不经过缓冲区。如 getch()(非标准 C)。

三、常见输入函数详解

1. scanf()

功能:格式化输入函数,按指定格式读取数据。

cpp 复制代码
int a;
scanf("%d", &a);

特点

  • 跳过前导空白字符(空格、制表符、换行符)。
  • 读到不符合格式的字符时停止。
  • 未读取的字符会留在缓冲区

陷阱

cpp 复制代码
int a;
char c;
scanf("%d", &a);  // 输入: 123abc
scanf("%c", &c);  // 会直接读取到 'a',而不是等待新输入

2. getchar()

功能:读取单个字符(包括空格、换行符)。

cpp 复制代码
char c = getchar();

特点

  • 每次只读取一个字符。
  • 会读取任何字符 ,包括 \n
  • 常用来 "吃掉" 缓冲区里的多余字符。

示例:清空缓冲区

cpp 复制代码
while (getchar() != '\n');

3.gets()(已废弃,不推荐使用)

功能:读取一整行字符串,直到遇到换行符

cpp 复制代码
char str[100];
gets(str);  // 危险!

问题

  • 不检查缓冲区大小,容易导致缓冲区溢出
  • C11 标准已正式移除 gets()
  • 建议用 fgets() 代替。

4. fgets()

功能:从文件流读取字符串,可以指定最大长度。

cpp 复制代码
char str[100];
fgets(str, 100, stdin);  // 从标准输入读取

优点

  • 安全,因为限制了读取长度。
  • 会保留换行符 \n 在字符串末尾。
cpp 复制代码
// 去掉末尾的换行符
str[strcspn(str, "\n")] = '\0';

5. putchar()

功能:输出单个字符。

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

int main() 
{
    putchar('A');  // 输出字符 'A'
    putchar('\n'); // 输出换行符
    return 0;
}
cpp 复制代码
//循环输出字符串

/*putchar 输出的字符通常会先进入输出缓冲区,并不是立即显示在屏幕上。常见情况:
行缓冲模式(大多数终端是行缓冲)
遇到 \n 会立即刷新缓冲区,把内容显示出来。
如果没有 \n,程序可能在结束或缓冲区满时才显示。*/

#include <stdio.h>

int main() 
{
    char str[] = "Hello";
    for (int i = 0; str[i] != '\0'; i++) 
    {
        putchar(str[i]);   
    }
    putchar('\n');
    return 0;
}

四、缓冲区的影响与常见问题

问题 1:scanf 连续读取

cpp 复制代码
int a;
char c;
scanf("%d", &a);
scanf("%c", &c);  // 会直接读取缓冲区中的 '\n'

解决方法:

cpp 复制代码
scanf("%d", &a);
getchar();  // 吃掉换行符
scanf("%c", &c);

问题 2:循环读取时残留数据

cpp 复制代码
char str[10];
while (1) 
{
    printf("输入: ");
    scanf("%s", str);  // 如果输入过长,多余字符会留在缓冲区
}

解决方法:

cpp 复制代码
while (getchar() != '\n');  // 清空缓冲区

五、各种输入方法对比


六、实用技巧

1:清空缓冲区

cpp 复制代码
while (getchar() != '\n');

2:安全读取字符串

cpp 复制代码
char str[100];
fgets(str, 100, stdin);
str[strcspn(str, "\n")] = '\0';  // 去掉换行符

3:混合使用 scanffgets,先清空缓冲区:

cpp 复制代码
int a;
scanf("%d", &a);
while (getchar() != '\n');  // 清空
fgets(str, 100, stdin);

七、总结

  • 缓冲区是关键:理解缓冲区的工作原理能帮你避免 90% 的输入问题。
  • 选择合适的函数 :数值用 scanf,整行字符串用 fgets,单个字符用 getchar
  • 注意安全 :永远不要使用 gets(),它是危险的。
  • 处理好换行符:混合输入时,记得清空缓冲区。
相关推荐
执尺量北斗10 小时前
[特殊字符] 基于 Qt + OpenGL 实现的入门级打砖块游戏
开发语言·qt·游戏
夏子曦10 小时前
C#内存管理深度解析:从栈堆原理到高性能编程实践
开发语言·c#
jiajixi12 小时前
Go 异步编程
开发语言·后端·golang
QX_hao12 小时前
【Go】--strings包
开发语言·后端·golang
计算机毕业设计木哥12 小时前
计算机毕设选题推荐:基于Hadoop和Python的游戏销售大数据可视化分析系统
大数据·开发语言·hadoop·python·信息可视化·spark·课程设计
秦禹辰12 小时前
venv与conda:Python虚拟环境深度解析助力构建稳定高效的开发工作流
开发语言·后端·golang
cooldream200912 小时前
深入解析 Conda、Anaconda 与 Miniconda:Python 环境管理的完整指南
开发语言·python·conda
·心猿意码·12 小时前
C++Lambda 表达式与函数对象
开发语言·c++