当前位置: 首页 > news >正文

I/O 函数/缓存和字节流、占位符、getchar(),putchar()

I/O 函数

C 语言提供了一些函数,用于与外部设备通信,称为输入输出函数,简称 I/O 函数。输入(import)指的是获取外部数据,输出(export)指的是向外部传递数据。

缓存和字节流

严格地说,输入输出函数并不是直接与外部设备通信,而是通过缓存(buffer)进行间接通信。这个小节介绍缓存是什么。

普通文件一般都保存在磁盘上面,跟 CPU 相比,磁盘读取或写入数据是一个很慢的操作。所以,程序直接读写磁盘是不可行的,可能每执行一行命令,都必须等半天。C 语言的解决方案,就是只要打开一个文件,就在内存里面为这个文件设置一个缓存区。

程序向文件写入数据时,程序先把数据放入缓存,等到缓存满了,再把里面的数据会一次性写入磁盘文件。这时,缓存区就空了,程序再把新的数据放入缓存,重复整个过程。

程序从文件读取数据时,文件先把一部分数据放到缓存里面,然后程序从缓存获取数据,等到缓存空了,磁盘文件再把新的数据放入缓存,重复整个过程。

内存的读写速度比磁盘快得多,缓存的设计减少了读写磁盘的次数,大大提高了程序的执行效率。另外,一次性移动大块数据,要比多次移动小块数据快得多。

这种读写模式,对于程序来说,就有点像水流(stream),不是一次性读取或写入所有数据,而是一个持续不断的过程。先操作一部分数据,等到缓存吞吐完这部分数据,再操作下一部分数据。这个过程就叫做字节流操作。

由于缓存读完就空了,所以字节流读取都是只能读一次,第二次就读不到了。这跟读取文件很不一样。

C 语言的输入输出函数,凡是涉及读写文件,都是属于字节流操作。输入函数从文件获取数据,操作的是输入流;输出函数向文件写入数据,操作的是输出流。

printf()

printf()是最常用的输出函数,用于屏幕输出,原型定义在头文件stdio.h,详见《基本语法》一章。

scanf()

基本用法

scanf()函数用于读取用户的键盘输入。程序运行到这个语句时,会停下来,等待用户从键盘输入。用户输入数据、按下回车键后,scanf()就会处理用户的输入,将其存入变量。它的原型定义在头文件stdio.h

scanf()的语法跟printf()类似。

scanf("%d", &i);

它的第一个参数是一个格式字符串,里面会放置占位符(与printf()的占位符基本一致),告诉编译器如何解读用户的输入,需要提取的数据是什么类型。这是因为 C 语言的数据都是有类型的,scanf()必须提前知道用户输入的数据类型,才能处理数据。它的其余参数就是存放用户输入的变量,格式字符串里面有多少个占位符,就有多少个变量。

上面示例中,scanf()的第一个参数%d,表示用户输入的应该是一个整数。%d就是一个占位符,%是占位符的标志,d表示整数。第二个参数&i表示,将用户从键盘输入的整数存入变量i

注意,变量前面必须加上&运算符(指针变量除外),因为scanf()传递的不是值,而是地址,即将变量i的地址指向用户输入的值。如果这里的变量是指针变量(比如字符串变量),那就不用加&运算符。

下面是一次将键盘输入读入多个变量的例子。

scanf("%d%d%f%f", &i, &j, &x, &y);

上面示例中,格式字符串%d%d%f%f,表示用户输入的前两个是整数,后两个是浮点数,比如1 -20 3.4 -4.0e3。这四个值依次放入ijxy四个变量。

scanf()处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。所以,用户输入的数据之间,有一个或多个空格不影响scanf()解读数据。另外,用户使用回车键,将输入分成几行,也不影响解读。

1
-20
3.4
-4.0e3

上面示例中,用户分成四行输入,得到的结果与一行输入是完全一样的。每次按下回车键以后,scanf()就会开始解读,如果第一行匹配第一个占位符,那么下次按下回车键时,就会从第二个占位符开始解读。

scanf()处理用户输入的原理是,用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读。解读用户输入时,会从上一次解读遗留的第一个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止。

int x;
float y;// 用户输入 "    -13.45e12# 0"
scanf("%d", &x);
scanf("%f", &y);

上面示例中,scanf()读取用户输入时,%d占位符会忽略起首的空格,从-处开始获取数据,读取到-13停下来,因为后面的.不属于整数的有效字符。这就是说,占位符%d会读到-13

第二次调用scanf()时,就会从上一次停止解读的地方,继续往下读取。这一次读取的首字符是.,由于对应的占位符是%f,会读取到.45e12,这是采用科学计数法的浮点数格式。后面的#不属于浮点数的有效字符,所以会停在这里。

由于scanf()可以连续处理多个占位符,所以上面的例子也可以写成下面这样。

scanf("%d%f", &x, &y);

scanf()的返回值是一个整数,表示成功读取的变量个数。如果没有读取任何项,或者匹配失败,则返回0。如果读取到文件结尾,则返回常量 EOF。

占位符

scanf()常用的占位符如下,与printf()的占位符基本一致。

  • %c:字符。
  • %d:整数。
  • %ffloat类型浮点数。
  • %lfdouble类型浮点数。
  • %Lflong double类型浮点数。
  • %s:字符串。
  • %[]:在方括号中指定一组匹配的字符(比如%[0-9]),遇到不在集合之中的字符,匹配将会停止。

上面所有占位符之中,除了%c以外,都会自动忽略起首的空白字符。%c不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格。如果要强制跳过字符前的空白字符,可以写成scanf(" %c", &ch),即%c前加上一个空格,表示跳过零个或多个空白字符。

下面要特别说一下占位符%s,它其实不能简单地等同于字符串。它的规则是,从当前第一个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。因为%s不会包含空白字符,所以无法用来读取多个单词,除非多个%s一起使用。这也意味着,scanf()不适合读取可能包含空格的字符串,比如书名或歌曲名。另外,scanf()遇到%s占位符,会在字符串变量末尾存储一个空字符\0

scanf()将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,使用%s占位符时,应该指定读入字符串的最长长度,即写成%[m]s,其中的[m]是一个整数,表示读取字符串的最大长度,后面的字符将被丢弃。

char name[11];
scanf("%10s", name);

上面示例中,name是一个长度为11的字符数组,scanf()的占位符%10s表示最多读取用户输入的10个字符,后面的字符将被丢弃,这样就不会有数组溢出的风险了。

赋值忽略符

有时,用户的输入可能不符合预定的格式。

scanf("%d-%d-%d", &year, &month, &day);

上面示例中,如果用户输入2020-01-01,就会正确解读出年、月、日。问题是用户可能输入其他格式,比如2020/01/01,这种情况下,scanf()解析数据就会失败。

为了避免这种情况,scanf()提供了一个赋值忽略符(assignment suppression character)*。只要把*加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。

scanf("%d%*c%d%*c%d", &year, &month, &day);

上面示例中,%*c就是在占位符的百分号后面,加入了赋值忽略符*,表示这个占位符没有对应的变量,解读后不必返回。

sscanf()

sscanf()函数与scanf()很类似,不同之处是sscanf()从字符串里面,而不是从用户输入获取数据。它的原型定义在头文件stdio.h里面。

int sscanf(const char* s, const char* format, ...);

sscanf()的第一个参数是一个字符串指针,用来从其中获取数据。其他参数都与scanf()相同。

sscanf()主要用来处理其他输入函数读入的字符串,从其中提取数据。

fgets(str, sizeof(str), stdin);
sscanf(str, "%d%d", &i, &j);

上面示例中,fgets()先从标准输入获取了一行数据(fgets()的介绍详见下一章),存入字符数组str。然后,sscanf()再从字符串str里面提取两个整数,放入变量ij

sscanf()的一个好处是,它的数据来源不是流数据,所以可以反复使用,不像scanf()的数据来源是流数据,只能读取一次。

sscanf()的返回值是成功赋值的变量的数量,如果提取失败,返回常量 EOF。

getchar(),putchar()

(1)getchar()

getchar()函数返回用户从键盘输入的一个字符,使用时不带有任何参数。程序运行到这个命令就会暂停,等待用户从键盘输入,等同于使用scanf()方法读取一个字符。它的原型定义在头文件stdio.h

char ch;
ch = getchar();// 等同于
scanf("%c", &ch);

getchar()不会忽略起首的空白字符,总是返回当前读取的第一个字符,无论是否为空格。如果读取失败,返回常量 EOF,由于 EOF 通常是-1,所以返回值的类型要设为 int,而不是 char。

由于getchar()返回读取的字符,所以可以用在循环条件之中。

while (getchar() != '\n');

上面示例中,只有读到的字符等于换行符(\n),才会退出循环,常用来跳过某行。while循环的循环体没有任何语句,表示对该行不执行任何操作。

下面的例子是计算某一行的字符长度。

int len = 0;
while(getchar() != '\n')len++;

上面示例中,getchar()每读取一个字符,长度变量len就会加1,直到读取到换行符为止,这时len就是该行的字符长度。

下面的例子是跳过空格字符。

while ((ch = getchar()) == ' ');

上面示例中,结束循环后,变量ch等于第一个非空格字符。

(2)putchar()

putchar()函数将它的参数字符输出到屏幕,等同于使用printf()输出一个字符。它的原型定义在头文件stdio.h

putchar(ch);
// 等同于
printf("%c", ch);

操作成功时,putchar()返回输出的字符,否则返回常量 EOF。

(3)小结

由于getchar()putchar()这两个函数的用法,要比scanf()printf()更简单,而且通常是用宏来实现,所以要比scanf()printf()更快。如果操作单个字符,建议优先使用这两个函数。

puts()

puts()函数用于将参数字符串显示在屏幕(stdout)上,并且自动在字符串末尾添加换行符。它的原型定义在头文件stdio.h

puts("Here are some messages:");
puts("Hello World");

上面示例中,puts()在屏幕上输出两行内容。

写入成功时,puts()返回一个非负整数,否则返回常量 EOF。

gets()

gets()函数以前用于从stdin读取整行输入,现在已经被废除了,仍然放在这里介绍一下。

该函数读取用户的一行输入,不会跳过起始处的空白字符,直到遇到换行符为止。这个函数会丢弃换行符,将其余字符放入参数变量,并在这些字符的末尾添加一个空字符\0,使其成为一个字符串。

它经常与puts()配合使用。

char words[81];puts("Enter a string, please");
gets(words);

上面示例使用puts()在屏幕上输出提示,然后使用gets()获取用户的输入。

由于gets()获取的字符串,可能超过字符数组变量的最大长度,有安全风险,建议不要使用,改为使用fgets()

相关文章:

I/O 函数/缓存和字节流、占位符、getchar(),putchar()

I/O 函数 C 语言提供了一些函数,用于与外部设备通信,称为输入输出函数,简称 I/O 函数。输入(import)指的是获取外部数据,输出(export)指的是向外部传递数据。 缓存和字节流 严格地…...

MySQL日期常见的函数

-- 获取当天日期 -- 2023-06-20 select curdate();-- 获取当天年月日时分秒 select now();-- 日期运算 -- 2024-06-20 17:04:17 select date_add(now(),interval 1 year);-- 日期比较 -- 0 select datediff(now(),now());-- 日期MySQL对于日期类型数据如何查询 -- 获取指定日期…...

Python获取CPU温度

本文的主要目的是演示如何借助 Python 中的 pythonnet 库读取和显示 CPU 温度。 Python获取CPU温度 根据您正在设计的应用程序类型,您可能希望监视运行该程序的机器的资源。 由于多种原因,可能会出现这种情况。 也许您需要您的程序在系统资源达到特定阈…...

后端整理(MySql)

1 事务 1.1 事务ACID原则 原子性(Atomicity) 事务的原子性指的是事务的操作,要么全部成功,要么全部失败回滚 一致性(Consistency) 事务的一致性是指事务必须使数据库从一个一致状态转变成另一个一致性…...

HashSet的详细介绍

一、HashSet整体介绍 HashSet 是 Java 中的一个集合类,它实现了 Set 接口,用于存储不重复的元素。它是基于哈希表的数据结构实现的。 HashSet 的特点如下: 不允许存储重复的元素:HashSet 中的元素是唯一的,如果尝试…...

【SCI征稿】JCR1区,中科院2区,有关大数据、人工智能、机器学习的应用研究均可

期刊简介: 【出版社】Elsevier 【影响因子】IF(2022):6.5-7.0 【期刊分区】JCR1区,中科院2区 【检索情况】SCIE 在检,正刊 【参考周期】期刊部系统内提交,预计3-5个月左右录用,…...

【UE】AI导航,多个导航物体无法走到同一终点问题

如不需要开启导航物体的碰撞,则需要关闭Use RVOAvoidance 不然会导致多个导航物体无法到达同一个目标点,都在附近晃。无法结束寻路。 ue小白,判定导航终点的半径,没有找到。如果有大佬知道怎么设置请在评论区指出,谢…...

途游游戏 x 极狐GitLab “通关” DevOps :单元测试从无到优,覆盖率 0→80%

目录 4 个工具孤岛 → 极狐GitLab 全家桶, 被动的「人找进度」 → 高效的「进度找人」 把 Code Review 做扎实 代码质量「向左移」,修复成本「往下降」 从无到「优」 自动执行单元测试,覆盖率 0→80% 你喜欢玩游戏吗? 最近…...

【云原生】Docker-Compose全方面学习

目录 1.compose简介 Compose V2 2.compose安装与下载 二进制包 PIP 安装 bash 补全命令 卸载 3.docker compose管理命令 命令对象与格式 命令选项 命令使用说明 1.compose简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可…...

基于 Redux + TypeScript 实现强类型检查和对 Json 的数据清理

基于 Redux TypeScript 实现强类型检查和对 Json 的数据清理 突然像是打通了任督二脉一样就用了 generics 搞定了之前一直用 any 实现的类型…… 关于 Redux 的部分,这里不多赘述,基本的实现都在这里:Redux Toolkit 调用 API 的四种方式 和…...

HIVE语法优化之Join优化

桶用两表关联字段,MapJoin时需要将小表填入内存,这时候,分桶就起到了作用 一个stage阶段代表一个mr执行,好几个MR,会吧每一个MR的结果都压缩 Mysql 慢查询 如果sql语句执行超过指定时间,定义该sql为慢查询,存储日志, 查问题: SQL日志,模拟慢SQL 然后查询执行计划 分组聚合 就…...

如何申请境内金融信息服务报备

依据《金融信息服务管理规定》等要求,开展境内金融信息服务报备工作事项如下: 一、报备对象及要求 金融信息服务,是指向从事金融分析、金融交易、金融决策或者其他金融活动的用户提供可能影响金融市场的信息和(或者)…...

VS code:Task

Task 微软官方连接: https://code.visualstudio.com/docs/editor/tasks what is Task 我们知道,vscode可以支持许多编程语言,很多语言是需要进行编译的,打包,测试… 有许多已有的工具支持这些流程,例如A…...

《Java-SE-第三十章》之哲学家就餐问题

前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页:KC老衲爱尼姑的博客主页 博主的github,平常所写代码皆在于此 共勉:talk is cheap, show me the code 作者是爪哇岛的新手,水平很有限&…...

关于接口测试用例设计的一些思考

接口测试发现的典型问题 传入参数处理不当,引起程序错误类型溢出,导致数据读取和写入不一致对象权限校验出错,可获取其他角色信息状态出错,导致逻辑处理出现问题逻辑校验不完善定时任务执行出错 接口测试用例设计 接口测试用例…...

gin和gorm框架安装

理论上只要这两句命令 go get -u gorm.io/gorm go get -u github.com/gin-gonic/gin然而却出现了问题 貌似是代理问题,加上一条命令 go env -w GOPROXYhttps://goproxy.cn,direct 可以成功安装 安装gorm的数据库驱动程序 go get -u gorm.io/driver/mysql...

今天小编继续给大家分享五款高效的电脑宝藏软件

目录 1、keytweak 2、ScreenToGif 3、Greenshot截屏工具 4、GIMP 5、HandBrake 1、keytweak keytweak 简单来说就是一个键盘按键修改器,说白了就是一个键盘按键重映射的软件。比如你键盘上的Q不好用了,你可以更换成一个不常见的按键来代替Q键&#x…...

SQL Server数据库如何添加mysql链接服务器(Windows系统)

SQL Server数据库如何添加mysql链接服务器(Windows系统) 一、说明二、下载mysql的odbc驱动三、安装mysql odbc四、配置ODBC4.1 控制面板→ODBC数据源(64位)→双击打开4.2 添加msql odbc数据源 五、测试添加是否成功六、打开SSMS&a…...

scala连接mysql数据库

scala中通常是通过JDBC组件来连接Mysql。JDBC, 全称为Java DataBase Connectivity standard。 加载依赖 其中包含 JDBC driver <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29&l…...

datax-web登陆时出现账号密码错误

在查找问题时&#xff0c;在admin里面查看日志时&#xff1a; 目录的位置&#xff1a;datax-web-2.1.2/modules/datax-admin/bin/console.out 发现了java程序没有跑起来&#xff0c;解决对应的bug问题即可&#xff0c;一般都是数据库连接的问题&#xff0c;可能和使用的数据库版…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...

Vue 实例的数据对象详解

Vue 实例的数据对象详解 在 Vue 中,数据对象是响应式系统的核心,也是组件状态的载体。理解数据对象的原理和使用方式是成为 Vue 专家的关键一步。我将从多个维度深入剖析 Vue 实例的数据对象。 一、数据对象的定义方式 1. Options API 中的定义 在 Options API 中,使用 …...

旋量理论:刚体运动的几何描述与机器人应用

旋量理论为描述刚体在三维空间中的运动提供了强大而优雅的数学框架。与传统的欧拉角或方向余弦矩阵相比&#xff0c;旋量理论通过螺旋运动的概念统一了旋转和平移&#xff0c;在机器人学、计算机图形学和多体动力学领域具有显著优势。这种描述不仅几何直观&#xff0c;而且计算…...

JS的传统写法 vs 简写形式

一、条件判断与逻辑操作 三元运算符简化条件判断 // 传统写法 let result; if (someCondition) {result yes; } else {result no; }// 简写方式 const result someCondition ? yes : no;短路求值 // 传统写法 if (condition) {doSomething(); }// 简写方式 condition &…...

Spring Boot + Thymeleaf 防重复提交

在 Spring Boot 与 Thymeleaf 结合的 Web 应用中&#xff0c;防止重复提交可以采用token 机制 客户端禁用按钮的方式实现&#xff0c;在高并发场景下&#xff0c;考虑使用 Redis 存储 token 而非 Session。 第一步&#xff1a;后端实现 Controller public class FormControl…...