22. C语言 输入与输出详解

news2025/1/22 13:20:52

本章目录:

    • 前言
    • 1. 输入输出的基础概念
      • 1.1 标准输入输出流
      • 1.2 输入输出函数
    • 2. 格式化输出与输入
      • 2.1 使用 `printf()` 进行输出
        • 示例 1: 输出字符串
        • 示例 2: 输出整数
        • 示例 3: 输出浮点数
      • 2.2 使用 `scanf()` 进行输入
        • 示例 4: 读取整数和字符
        • 改进方案:使用`getchar()`清理缓冲区
        • 使用 `scanf()` 读取字符串
    • 3. 其他输入输出函数
      • 3.1 `getchar()` 和 `putchar()`
        • 示例 5: 使用 `getchar()` 和 `putchar()`
      • 3.2 `gets()` 和 `puts()`
        • 示例 6: 使用 `gets()` 和 `puts()`
      • 3.3 更安全的替代方法:`fgets()`
    • 总结


前言

在编程中,输入与输出(I/O)是与用户交互的最基本方式之一。C语言作为一种面向过程的语言,其标准库提供了一系列的函数来帮助我们从键盘读取数据和将数据输出到屏幕或文件中。理解这些输入输出操作的机制对于编写高效、健壮的程序至关重要。本文将详细探讨C语言中的输入输出函数,并给出一些实际的代码示例及技巧,帮助你深入理解输入输出的工作原理。


1. 输入输出的基础概念

1.1 标准输入输出流

C语言将所有的外部设备(包括键盘、屏幕、文件等)都看作文件。因此,C语言的输入输出操作实际上是通过文件流(file streams)来实现的。标准库中为我们提供了三个标准流,这些流在程序启动时自动打开:

  • 标准输入(stdin):通常连接到键盘,接受用户输入。
  • 标准输出(stdout):通常连接到屏幕,用于输出程序结果。
  • 标准错误(stderr):通常连接到屏幕,专门用于输出错误信息。

在C语言中,文件指针是访问这些流的句柄。程序通过这些文件指针与外部设备进行交互。

1.2 输入输出函数

C语言提供了多个函数来实现输入输出操作,其中最常用的两个函数是 printf()scanf()

  • printf():用于格式化输出,将数据打印到屏幕。
  • scanf():用于格式化输入,从键盘读取数据。

这两个函数都支持格式化操作,允许程序员指定数据的显示或读取方式。

2. 格式化输出与输入

2.1 使用 printf() 进行输出

printf() 函数是C语言中最常用的输出函数。它允许你以多种格式将数据输出到标准输出流(通常是屏幕)。它的基本语法如下:

int printf(const char *format, ...);

其中,format 是一个包含格式控制的字符串,可以包括普通文本和格式占位符(例如 %d%f 等),这些占位符用于指定输出的变量类型。

示例 1: 输出字符串
#include <stdio.h>

int main() {
    printf("Hello, C World!\n");
    return 0;
}

输出

Hello, C World!
示例 2: 输出整数
#include <stdio.h>

int main() {
    int number = 42;
    printf("The number is: %d\n", number);
    return 0;
}

输出

The number is: 42

在这个例子中,%d 是格式说明符,用来输出一个整数类型的变量。

示例 3: 输出浮点数
#include <stdio.h>

int main() {
    float pi = 3.14159;
    printf("Pi is approximately: %.2f\n", pi);
    return 0;
}

输出

Pi is approximately: 3.14

2.2 使用 scanf() 进行输入

scanf() 函数用于从标准输入流(通常是键盘)读取数据,并将其存储到变量中。它的基本语法如下:

int scanf(const char *format, ...);
示例 4: 读取整数和字符
#include <stdio.h>

int main() {
    int number;
    char character;
    printf("Enter an integer and a character: ");
    scanf("%d%c", &number, &character);
    printf("You entered: %d and %c\n", number, character);
    return 0;
}

问题:为什么读取字符时会有问题?

当你运行上述代码时,输入格式如 5a 可能会导致不符合预期的结果。问题出在scanf()函数中,读取整数后,scanf()并不会清空输入缓冲区,换行符或空格可能会被意外读取为字符。因此,字符变量character会接收到一个额外的换行符(\n)。

改进方案:使用getchar()清理缓冲区

为了解决这个问题,可以使用getchar()来读取并清除输入缓冲区中的换行符或空格:

#include <stdio.h>

int main() {
    int number;
    char character;
    printf("Enter an integer and a character: ");
    scanf("%d", &number);
    while ((character = getchar()) == ' ' || character == '\n');  // 清理缓冲区
    scanf("%c", &character);  // 正常读取字符
    printf("You entered: %d and %c\n", number, character);
    return 0;
}

这样做可以确保在读取字符时没有意外的换行符或空格。

使用 scanf() 读取字符串
#include <stdio.h>

int main() {
    char name[50];
    printf("Enter your name: ");
    scanf("%s", name);  // 不会读取空格后的部分
    printf("Hello, %s!\n", name);
    return 0;
}

输出

Enter your name: Alice
Hello, Alice!

需要注意的是,scanf("%s", name) 会在遇到空格时停止读取,因此只能读取一个单词。如果你需要读取包含空格的整行文本,可以使用 fgets()

3. 其他输入输出函数

3.1 getchar()putchar()

  • getchar():从标准输入流中读取下一个字符,并返回该字符的ASCII值。
  • putchar():将一个字符输出到标准输出流。
示例 5: 使用 getchar()putchar()
#include <stdio.h>

int main() {
    char c;
    printf("Enter a character: ");
    c = getchar();
    printf("You entered: ");
    putchar(c);
    printf("\n");
    return 0;
}

输出

Enter a character: A
You entered: A

3.2 gets()puts()

  • gets():读取一行文本(包括空格)直到遇到换行符为止。(已废弃)
  • puts():输出一个字符串并自动添加换行符。
示例 6: 使用 gets()puts()
#include <stdio.h>

int main() {
    char str[100];
    printf("Enter a string: ");
    gets(str);  // 注意:此函数已被废弃,不推荐使用
    puts("You entered:");
    puts(str);
    return 0;
}

输出

Enter a string: Hello World
You entered:
Hello World

3.3 更安全的替代方法:fgets()

由于 gets() 存在安全隐患(无法防止缓冲区溢出),建议使用 fgets() 替代它。

#include <stdio.h>

int main() {
    char str[100];
    printf("Enter a string: ");
    fgets(str, sizeof(str), stdin);  // 安全读取一行输入
    printf("You entered: ");
    puts(str);
    return 0;
}

总结

  • 使用 scanf() 时要小心缓冲区问题,例如处理换行符和空格时。可以通过使用 getchar()scanf() 格式控制来避免这些问题。
  • 避免使用 gets(),因为它无法防止缓冲区溢出。推荐使用 fgets() 作为替代方案。
  • 理解格式化输入输出的工作原理,如 %d%f%s 等格式符,能帮助你更精确地控制输入输出。

通过掌握这些输入输出的技巧,你可以编写更加健壮、易用的程序,避免一些常见的错误和安全隐患。希望本文能为你提供清晰的理解,并帮助你在C语言的学习旅程中走得更远。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280380.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux-FTP服务配置与应用

也许你对FTP不陌生&#xff0c;但是你是否了解FTP到底是个什么玩意&#xff1f; FTP 是File Transfer Protocol&#xff08;文件传输协议&#xff09;的英文简称&#xff0c;而中文简称为 “文传协议” 用于Internet上的控制文件的双向传输。同时&#xff0c;它也是一个应用程序…

linux-NFS网络共享存储服务配置

1.NFS服务原理 NFS会经常用到&#xff0c;用于在网络上共享存储&#xff0c;这样讲&#xff0c;你对NFS可能不太了解&#xff0c;举一个例子&#xff0c; 加入有三台机器A,B,C&#xff0c;它们需要访问同一个目录&#xff0c;目录中都是图片&#xff0c;传统的做法是把这些 图…

Jenkins 启动

废话 这一阵子感觉空虚&#xff0c;心里空捞捞的&#xff0c;总想找点事情做&#xff0c;即使这是一件微小的事情&#xff0c;空余时间除了骑车、打球&#xff0c;偶尔朋友聚会 … 还能干什么呢&#xff1f; 当独自一人时&#xff0c;究竟可以做点什么&#xff0c;填补这空虚…

消息队列篇--原理篇--Pulsar(Namespace,BookKeeper,类似Kafka甚至更好的消息队列)

Apache Pulusar是一个分布式、多租户、高性能的发布/订阅&#xff08;Pub/Sub&#xff09;消息系统&#xff0c;最初由Yahoo开发并开源。它结合了Kafka和传统消息队列的优点&#xff0c;提供高吞吐量、低延迟、强一致性和可扩展的消息传递能力&#xff0c;适用于大规模分布式系…

Python配置MITMPROXY中间人监听配置

1、安装python 环境&#xff0c;此处可以使用conda安装:conda create --name my_new_env python3.12 2、pip安装mitmproxy&#xff1a;pip install mitmproxy&#xff0c;安装后如果使用mitmproxy --version 成功返回结果&#xff0c;说明已经在环境变量路径中&#xff0c;如果…

Java-数据结构-二叉树习题(2)

第一题、平衡二叉树 ① 暴力求解法 &#x1f4da; 思路提示&#xff1a; 该题要求我们判断给定的二叉树是否为"平衡二叉树"。 平衡二叉树指&#xff1a;该树所有节点的左右子树的高度相差不超过 1。 也就是说需要我们会求二叉树的高&#xff0c;并且要对节点内所…

【网络原理】万字详解 HTTP 协议

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. HTTP 前置知识1.1 HTTP 是什么1.2 HTPP 协议应用场景1.3 HTTP 协议工作过程 2. HTTP 协议格式2.1 fiddler…

基于STM32的智能寝室控制系统设计(论文+源码)

1 .系统整体设计 通过需求分析&#xff0c;本设计基于STM32的智能寝室控制系统整体架构如图2.1所示&#xff0c;整系统利用DHT11温湿度传感器获取室内环境数据&#xff0c;并通过OLED显示&#xff0c;提供用户实时信息&#xff0c;火焰传感器和烟雾传感器用于监测火灾情况&…

日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件

日历热力图&#xff0c;月度数据可视化图表&#xff0c;vue组件 先看效果&#x1f447; 在线体验https://www.guetzjb.cn/calanderViewGraph/ 日历图简单划分为近一年时间&#xff0c;开始时间是 上一年的今天&#xff0c;例如2024/01/01 —— 2025/01/01&#xff0c;跨度刚…

铁电存储器FM25CL64B简介及其驱动编写(基于STM32 hal库)

铁电存储器FM25CL64B简介及其驱动编写&#xff08;基于STM32 hal库&#xff09; 文章目录 铁电存储器FM25CL64B简介及其驱动编写&#xff08;基于STM32 hal库&#xff09;前言一、FM25CL64B简介二、驱动代码1.头文件2.c文件 总结 前言 FM25CL64B是赛普拉斯cypress出品的一款铁…

基于微信小程序的科创微应用平台设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

HarmonyOS Next 最强AI智能辅助编程工具 CodeGenie介绍

随着大模型的兴起&#xff0c;在智能编码领域首先获得了应用。 市面上从Microsoft Copilot到国内阿里通义&#xff0c;字节marscode等&#xff0c;都提供了copilot方式的智能编码工具。HarmonyOS Next作为诞生一年的新事物&#xff0c;由于代码量和文档迭代原因&#xff0c;在智…

WPF2-1在xaml为对象的属性赋值.md

1. AttributeValue方式 1.1. 简单属性赋值1.2. 对象属性赋值 2. 属性标签的方式给属性赋值3. 标签扩展 (Markup Extensions) 3.1. StaticResource3.2. Binding 3.2.1. 普通 Binding3.2.2. ElementName Binding3.2.3. RelativeSource Binding3.2.4. StaticResource Binding (带参…

Appium(四)

一、app页面元素定位 1、通过id定位元素: resrouce-id2、通过ClassName定位&#xff1a;classname3、通过AccessibilityId定位&#xff1a;content-desc4、通过AndroidUiAutomator定位5、通过xpath定位xpath、id、class、accessibility id、android uiautomatorUI AutomatorUI自…

Windows图形界面(GUI)-QT-C/C++ - Qt List Widget详解与应用

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 QListWidget概述 使用场景 常见样式 QListWidget属性设置 显示方式 (Display) 交互行为 (Interaction) 高级功能 (Advanced) QListWidget常见操作 内容处理 增加项目 删除项目…

Oracle 创建并使用外部表

目录 一. 什么是外部表二. 创建外部表所在的文件夹对象三. 授予访问外部表文件夹的权限3.1 DBA用户授予普通用户访问外部表文件夹的权限3.2 授予Win10上的Oracle用户访问桌面文件夹的权限 四. 普通用户创建外部表五. 查询六. 删除 一. 什么是外部表 在 Oracle 数据库中&#x…

靠右行驶数学建模分析(2014MCM美赛A题)

笔记 题目 要求分析&#xff1a; 比较规则的性能&#xff0c;分为light和heavy两种情况&#xff0c;性能指的是 a.流量与安全 b. 速度限制等分析左侧驾驶分析智能系统 论文 参考论文 两类规则分析 靠右行驶&#xff08;第一条&#xff09;2. 无限制&#xff08;去掉了第一条…

Kafka 源码分析(一) 日志段

首先我们的 kafka 的消息本身是存储在日志段中的, 对应的源码是下面这段代码: class LogSegment private[log] (val log: FileRecords,val lazyOffsetIndex: LazyIndex[OffsetIndex],val lazyTimeIndex: LazyIndex[TimeIndex],val txnIndex: TransactionIndex,val baseOffset:…

【番外篇】实现排列组合算法(Java版)

一、说明 在牛客网的很多算法试题中&#xff0c;很多试题底层都是基于排列组合算法实现的&#xff0c;比如最优解、最大值等常见问题。排列组合算法有一定的难度&#xff0c;并不能用一般的多重嵌套循环解决&#xff0c;没有提前做针对性的学习和研究&#xff0c;考试时候肯定…

Linux - 线程池

线程池 什么是池? 池化技术的核心就是"提前准备并重复利用资源". 减少资源创建和销毁的成本. 那么线程池就是提前准备好一些线程, 当有任务来临时, 就可以直接交给这些线程运行, 当线程完成这些任务后, 并不会被销毁, 而是继续等待任务. 那么这些线程在程序运行过程…