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

2023-12-26 05:45

本文主要是介绍“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'){;}
//以下两种写法都okscanf("%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的正常使用(擦屁股)。

这篇关于“C语言“——scanf()、getchar() 、putchar()、之间的关系的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/538309

相关文章

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

C语言中%zu的用法解读

《C语言中%zu的用法解读》size_t是无符号整数类型,用于表示对象大小或内存操作结果,%zu是C99标准中专为size_t设计的printf占位符,避免因类型不匹配导致错误,使用%u或%d可能引发... 目录size_t 类型与 %zu 占位符%zu 的用途替代占位符的风险兼容性说明其他相关占位符验证示

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin