“C语言“——scanf()、getchar() 、putchar()、之间的关系

scanf函数说明

scanf函数是对来自于标准输入流的输入数据作格式转换,并将转换结果保存至format后面的实参所指向的对象。

而const char*format 指向的字符串为格式控制字符串,它指定了可输入的字符串以及赋值时转换方法。

简单来说给一个打印格式(输入数据格式),scanf函数会将打印数据格式的结果转换放到后面的实参变量当中。

比如下面的代码

#include<stdio.h>
int main()
{
	int a = 0;
	char ch = 0;
	double b = 0.0;
	scanf("%d %c %lf", &a, &ch, &b);
	printf("%d %c %lf", a, ch, b);

	return 0;
}

但scanf函数有一个缺点,就是scanf读取不了空格和回车等字符,当scanf读到这两个字符时,scanf会读取失败返回EOF,如果匹配错误也会读取失败返回EOF(比如应该是%d的数据转换到了char实参变量当中)。

EOF

EOF全名是:End of File 在<stdio.h>头文件中被定义为负值,即-1。

EOF的值不同编译器下值不同,在VS2019是-1 

如果没有将头文件<stdio.h>包含到程序中,那么EOF就没有定义,程序不能编译和运行。

getchar和putchar

putchar的返回值是int,因为字符在程序存储的是ASCII码值,而且putchar只能打印字符,不能打印字符串,就是配合getchar()使用的。如果putchar成功获取了字符就返回所写字符,失败就返回EOF。

#include<stdio.h>
int main()
{
	putchar('a');
	putchar('b');
	putchar('c');
	return 0;
}

getchar返回也是int,参数是void,可有可无,getchar是从标准输入流读取字符(空格 回车都可以读取)并将其返回,如果读取失败就返回EOF。 

比如

#include<stdio.h>
int main()
{
	int ch;
	while ((ch = getchar()) != EOF)
	{
		putchar(ch);
	}
	return 0;
}

getchar如果缓冲区没有字符,getchar会等待我们的输入且摁下回车键才会打印在屏幕上。

配合putchar使用。

 按下回车键后才在屏幕上输出对应字符。

 ctrl+Z是将程序结束掉,退出了程序终止了代码循环。

crtl+Z相当于EOF。

 为什么按回车键才会将字符输出到屏幕上呢?

 C语言的输入输出一般会将读入的字符以及待输出的字符暂时保存在缓存中(缓冲区),当达到以下条件才进行实际的输入输出操作。

1.缓存已满 2.输入换行符(\n)  3.立即输出

对应方式称为1.全缓冲 2.行缓冲 3,无缓冲

键盘输入的内容不会直接给cpu处理打印在屏幕上 而是交给缓存 提高cpu运行效率。

getchar与scanf的关系

我们根据下图代码来分析getchar和scanf之间的关系

#include<stdio.h>
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", password);
	printf("请确认密码正确Y/N:>");
	char ch = 0;
	scanf("%c", &ch);
	if ('Y' == ch)
	{
		printf("密码正确\n");
	}
	else
	{
		printf("密码错误\n");
	}
	return 0;
}

 当程序运行时,我们刚输入完密码程序直接结束了,都没有确定密码的正确性,这是为什么呢?

当我们输入密码摁下回车键时,在缓冲区输入了1234\n,回车键相当于换行等于转义字符\n

第一个scanf读取了1234 第二个scanf读取了\n 直接填满了两个scanf的嘴巴,因此直接程序结束

并且结果为密码错误,当我们输入完1234摁下回车键那刻\n也被载入到了缓冲区,第二个scanf

定睛一看缓冲区有内容直接就读取走了。

解决办法 

 这时我们就要请出getchar给scanf擦屁股了,因为getchar能读取回车 空格等字符。

#include<stdio.h>
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", password);
	printf("请确认密码正确Y/N:>");
	char ch = 0;
	getchar();
	scanf("%c", &ch);
	if ('Y' == ch)
	{
		printf("密码正确\n");
	}
	else
	{
		printf("密码错误\n");
	}
	return 0;
}

但如果有人在设置密码时写入了空格,而且scanf读取不了空格和回车字符,这时还是会出现代码判断错误导致运行结果错误。

我们直接用while循环搞一个一劳永逸的解决方案

直接使用循环清空缓冲区的空格 回车等字符

#include<stdio.h>
int main()
{
	char password[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", password);
	printf("请确认密码正确Y/N:>");
	char ch = 0;
	while ((getchar()) != '\n')
	{
		;
	}
//以下两种写法都ok
	scanf("%c",&ch);
    //ch=getchar();
	if ('Y' == ch)
	{
		printf("密码正确\n");
	}
	else
	{
		printf("密码错误\n");
	}
	return 0;
}

 关系

输入b后摁下回车键形成\n

缓冲区载入的就是b\n

第一个scanf读取b 第二个scanf读取\n  因此程序结束语在第三行

输入a\n

scanf读取a getchar读取\n putchar输出a 

 输入a\n 第一个scanf读走a  getchar读走\n

第二个scanf正常使用再次输入b\n  putchar在下一行输出b

scanf读走as \nbxx是putchar读取的   a是第二个scanf读取的后面还有个\n

所以程序结束语在第4行。

总结

如果scanf输入过程中遇到空格 回车键等字符,scanf自己处理不了的读取字符时,就用getchar来解决,如果有多个处理不了的特殊字符就用while循环来处理(scanf处理不了的空格 回车键等特殊字符),配合getchar和putchar来给scanf的正常使用(擦屁股)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

css radial-gradient 径向渐变基本语法与使用

在之前的文章《深入理解Css linear-gradient线性渐变》我们了解了CSS中的线性渐变&#xff0c;本文将介绍CSS中的另一种渐变———径向渐变&#xff08;Radial Gradient&#xff09;&#xff1a; CSS中的径向渐变&#xff08;Radial Gradient&#xff09;允许你创建从一个颜色…

基于Java SSM框架实现交通事故档案管理系统项目【项目源码+论文说明】

基于java的SSM框架实现交通事故档案管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于交通事故档案管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0…

企业知识库:从信息管理到知识创新的转变

在当今这个信息爆炸的时代&#xff0c;企业知识库的建设已经成为了企业持续发展的重要基石。从传统的信息管理到现代的知识创新&#xff0c;企业知识库的角色和功能也在不断地演变和升级。本文将探讨企业知识库的发展历程&#xff0c;以及如何实现从信息管理到知识创新的转变。…

谷歌Gemini演示视频解析

在刚刚过去的前两天 谷歌发布了号称最强的多模态大模型Gemini 不仅提供了Ultra、Pro 和 Nano版本 而且在32项学术基准中 Gemini Ultra都达到了SOTA水平 甚至在MMLU测试中 Gemini Ultra 的得分率高达 90.0%&#xff0c; 是第一个超过人类专家的模型 应该说&#xff0c;G…

【vtkWidgetRepresentation】第十八期 vtkHoverWidget

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享vtkHoverWidget,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. vtkHoverWidget vtkHoverWidget用于在呈现窗口中…

如何在飞书自建项目中接入ChatGPT打造智能问答助手并远程访问

文章目录 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 前言 在飞书中创建chatGPT机器人并且对话&#xff0c;在下面操作步骤中…

10.3 uinput

uinput 简介 uinput 是一个内核驱动&#xff0c;应用程序通过它可以在内核中模拟一个输入设备&#xff0c;其设备文件名是 /dev/uinput 或 /dev/input/uinput。 uinput 使用 使用 uinput 时遵循以下步骤&#xff1a; 通过 open 打开 uinput 设备通过 ioctl 设置属性位图通过…

Windows基础知识:一站式整理指南

目录 学习目标&#xff1a; 学习内容&#xff1a; 学习产出&#xff1a; Windows操作系统的发展历史和版本特点 Windows界面和桌面元素的基本介绍 文件和文件夹管理&#xff1a;创建、复制、移动、删除等操作 系统设置和个性化&#xff1a;调整屏幕分辨率、更改桌面背景、设置…

Python之classmethod和staticmethod的区别

python中3种方式定义类方法&#xff0c;常规方式、classmethod修饰方式、staticmethod修饰方式。 class A(object):def foo(self, x):print(调用foo函数 (%s, %s)%(self, x))print(self:, self)classmethoddef class_foo(cls, x):print(调用class_foo函数 (%s, %s) % (cls, x))…

Azure Machine Learning - 如何使用 GPT-4 Turbo with Vision

介绍如何在Azure中使用GPT-4 Turbo with Vision 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认证的资深架构师&#xff0c;项目管理…

Plantuml之对象图语法介绍(十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

MySQL undo日志精讲3-从回滚段中申请 Undo 页面链表

回滚段-Rollback Segment Header 页面 回滚段的概念 我们现在知道一个事务在执行过程中最多可以分配4个 Undo 页面链表&#xff0c;在同一时刻不同事务拥有的 Undo 页面链表是不一样的&#xff0c;所以在同一时刻系统里其实可以有许许多多个 Undo 页面链表存在。为了更好的管…

qt项目-《图像标注软件》源码阅读笔记-Shape类绘图及其子类

目录 1. Shape 概览 2. Shape 基类 2.1 字段 2.2 方法 2.3 嵌套类型 3. Shape2D 2d形状纯虚基类 3.1 字段 3.2 方法 4. Shape3D 3d形状纯虚基类 5. Shape2D子类 5.1 Rectangle 矩形类 1. Shape 概览 功能&#xff1a;Shape类及其子类负责形状的绘制及形状的存储。…

【SpringBoot】Spring data JPA整合ShardingSphere-JDBC静态读写分离实现

大佬栽树&#xff0c;我乘凉 许大仙老师&#xff1a;【yuque.com/fairy-era/yg511q/ud9uli67b6gxgdh7】 开整 数据库准备 一主两从 数据库脚本 CREATE DATABASE IF NOT EXISTS dbtest CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE dbtest; -- 创建表 CREATE TA…

【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. Java的注释方式二. 标识符三. 关键字四. 全篇总结 &#x1f4d1;前言 在Java编程…

《面试专题-----经典高频面试题收集三》解锁 Java 面试的关键:深度解析并发编程基础篇高频经典面试题(第三篇)

目录 并发编程面试题1.什么是进程、线程、协程&#xff0c;他们之间的关系是怎样的2.协程对于多线程有什么优缺点吗 并发编程面试题 1.什么是进程、线程、协程&#xff0c;他们之间的关系是怎样的 进程: 本质上是⼀个独⽴执⾏的程序&#xff0c;进程是操作系统进⾏资源分配和…

C# float/double 减 float/double 等 (X.xxxxxxxxxxxxxE-07)(黑盒测试)

问题 因为没有深究原理&#xff0c;所有只进行了“黑盒测试” 黑盒测试结论&#xff1a; 问题操作结论float/double运算进过一系列的运算后大概率 &#xff01; 0.0 &#xff0c; 而是等于0.00000000000xxxx等于X.xxxxxxxx一串数字的时候不影响下一步继续使用当需要显示fl…

Linux基本数据库mysql了解

关系型数据库与非关系型数据库的区别 什么是关系型数据库 关系型数据库是依据关系模型来创建的数据库。 所谓关系模型就是“一对一、一对多、多对多”等关系模型&#xff0c;关系模型就是指二维表格模型,因而一个关系型数据库就是由二维表及其之间的联系组成的一个数据组织。 关…

06_树的入门

二叉树入门 树的基本定义树的相关术语二叉树的基本定义二叉查找树的创建二叉树的结点类二叉查找树API设计二叉查找树实现二叉查找树其他便捷方法查找二叉树中最小的键查找二叉树中最大的键 二叉树的基础遍历前序遍历中序遍历后序遍历 二叉树的层序遍历二叉树的最大深度问题折纸…

顺序结构复习

复习一些易错知识点还有习题 目录 可能不熟悉的知识点 逻辑表达式的求解 if,else的配队 条件运算符 运算符优先级的问题 switch的使用 goto和if构成的循环 例题讲解 1 2 3 4 ​编辑 5 ​编辑 6赋值 ​编辑 7 可能不熟悉的知识点 逻辑表达式的求解 如果…