C primer plus 学习笔记 第8章 字符输入/输出 和输入验证

简介: C primer plus 学习笔记 第8章 字符输入/输出 和输入验证

     第8章 字符输入/输出 和输入验证

 

8.1 单字符IO: getchar() 和 putchar()

getchar()每次读入一个字符,putchar()每次输出一个字符。

利用这两个函数,可以写出一个“复读机”。

/* echo */
#include<stdio.h>
int main(void)
{
  char ch;
  while ((ch = getchar()) != '#')  //当读入的字符不是'#' 就一直复读下去
    putchar(ch);
 
  return 0;
}

8.2 缓冲区

缓冲区(buffer):缓冲区是一个临时存储区。输入的字符被储存在缓冲区,按下Enter时,程序才使用你输入的字符。

使用缓冲区可以把若干字符作为一个块进行传输,比逐个发送字符节约时间。

但有些情况下,也需要无缓冲输入。(如游戏中,希望按下按键就执行指令)

缓冲分为两类:完全缓冲I/O和行缓冲I/O。

完全缓冲输入:缓冲区被填满时才刷新缓冲区(内容送到目的地),通常在文件输入中,

行缓冲I/O:在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入,按下Enter时刷新缓冲区。

8.3 结束键盘输入

8.3.1 文件、流和键盘输入

文件(file)是存储器中存储信息的区域。文件一般保持在硬盘、U盘中。

C可以通过调用底层I/O或调用标准I/O来处理文件。

 

流(stream):C语言处理的是流而不直接处理文件。流是一个实际输入或输出映射的理想化数据流。这意味着不同类型的输入可以用统一的流表示。


于是,打开文件的过程就是将文件和流相关联,然后通过流进行读写文件。

8.3.2 文件结尾

Ctrl+Z标记文件结尾

在C语言中,用getchar()读取文件结尾时返回一个特殊的值:EOF. (end of file)

scanf读到文件结尾也返回EOF。

可以使用下面的表达式:

while ( (ch == getchar()) != EOF)  来判断是否到达末尾。

借助上面这句,可以改进8.1中的复读机。

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

注:在window中,可以按下Ctrl+z可以模拟文件结尾来结束程序。

8.4 重定向和文件

8.4.1 UNIX、Linux和DOS重定向

重定向输入 让程序使用文件而不是键盘来输入,

重定向输出 让程序输出至文件而不是屏幕。

1.重定向输入:

编译我们上面的复读机程序(代码见8.3.2),得到一个.exe文件。(如果你用的是VS2017或类似的IDE,可以在运行代码后在相应工程文件夹的Debug文件夹里找到这个.exe文件)

(图:.exe 文件的位置)

运行CMD,(windows,cmd,回车)cd 路径 进入.exe文件所在文件夹,输入exe的文件名即可执行该程序。

如果想使用程序处理文本文件(text file),比如一个名为words的txt文件,可以使用如下命令:

cPrimerPlusTest < words.txt  

注1:cPrimerPlusTest是我的.exe文件名,根据自己的.exe文件名替换。

注2:words.txt文件和.exe文件要放在同一个文件夹里。(或者加上绝对路径也行。注意路径\要写成\\)

 

2.重定向输出

用程序将键盘输入的内容发送到mywords.txt中:(和1.重定向输入类似,只是改变箭头方向)

cPrimerPlusTest > mywords.txt  

运行后执行程序,按下Ctrl+z程序结束后,会将输出的内容送到mywords.txt文件中。

 

3. 组合重定向


如果你希望制作一份mywords.txt的副本,并命名为savewords。只要使用下面命令:

echo_eof < mywords.txt > savewords

echo_eof > savewords < mywords.txt

>>运算符 可以将数据添加到现有文件的末尾

| 运算符  可以将一个文件的输出 连接到另一个文件的输入。

 

8.5 创建更友好的用户界面

8.5.1 使用缓冲输入

缓冲输入要求用户按下Enter键发送输入,按下Enter时也产生了换行符,程序须考虑这个换行符。//这是很多人容易忽略的地方

8.5.2 混合数值和字符输入

假设程序用getchar()处理字符输入,scanf()处理数值输入。但是尽量不要混用这两个,因为getchar()读取每个字符,包括空格、制表符和换行符;而scanf()读取数字时会跳过空格、制表符和换行符。

8.6输入验证

实际应用中,用户可能会输入一些非法值,导致程序异常。

编程时应该检测处理这个问题(非法输入)。

下面是一个对非法输入进行判断的程序:

#define   _CRT_SECURE_NO_WARNINGS
//checking.c --输入验证
#include<stdio.h>
#include<stdbool.h>
//验证输入时一个整数
long get_long(void);
//验证范围的上下限是否有数
bool bad_limits(long begin, long end, long low, long high);
//计算a~b之间的整数平方和
double sum_squares(long a, long b);
int main(void)
{
  const long MIN = -1000000L;
  const long MAX = +1000000L;
  long start;
  long stop;
  double answer;
  printf("程序计算上下限之间的整数的平方和(输入两个0退出)\n");
  printf("lower limit: ");
  start = get_long();
  printf("upper limit: ");
  stop = get_long();
  while(start!=0 || stop!=0)
  {
    if (bad_limits(start, stop, MIN, MAX))
      printf("try again\n");
    else
    {
      answer = sum_squares(start, stop);
      printf("The sum of the squares of the integers ");
      printf("from %ld to %ld is %g\n", start, stop, answer);
    }
    printf("lower limit: ");
    start = get_long();
    printf("upper limit: ");
    stop = get_long();
  }
  printf("Done.\n");
 
  return 0;
}
long get_long(void)
{
  long input;
  char ch;
  while (scanf("%ld", &input) != 1)  //这里对输入进行了判断
  {
    while ((ch = getchar()) != '\n')
      putchar(ch);
    printf("非整数,请输入整数:");
  }
  return input;
}
double sum_squares(long a, long b)
{
  double total = 0;
  long i;
  for (i = a; i <= b; i++)
    total += (double)i* (double)i;
  return total;
}
bool bad_limits(long begin, long end, long low, long high)
{
  bool not_good = false;
  if (begin > end)
  {
    printf("%ld 比 %ld大.\n", begin, end);
    not_good = true;
  }
  if (begin < low || end < low)
  {
    printf("输入应该比%ld大\n", low);
    not_good = true;
  }
  if (begin > high || end> high)
  {
    printf("输入应该比%ld小\n", high);
    not_good = true;
  }
  return not_good;
}


8.6.2 输入流和数字

输入流由字符组成,但是scanf()可以把字符转成整数等类型。

 

 

8.7 菜单浏览

在图形化程序中,可以通过按钮来限制用户的操作,但是我们的命令行程序中,无法预知用户的行为。

例如在选择菜单选项时,用户可能会输入一些意外的选项。通常用一个while循环来处理输入。

 

 

另一个问题是,用户正常输入时由于按下Enter会产生一个多余的换行符,这会使程序认为用户进行非法输入,产生提示。可以用类似下面这样的方法将多余的字符跳过。

注:get_first(void)函数将读取一行的第一个字符,然后跳过这一行。

相关文章
|
Linux 网络安全 Docker
docker centos7 安装ssh
docker centos7 安装ssh 原文链接:http://blog.csdn.net/mergerly/article/details/54709919 一.
4842 0
|
8月前
|
Web App开发 Linux 数据库
Omnissa Horizon 8 2503 (ESB Release) - 虚拟桌面基础架构 (VDI) 和应用软件
Omnissa Horizon 8 2503 (ESB Release) - 虚拟桌面基础架构 (VDI) 和应用软件
610 8
Omnissa Horizon 8 2503 (ESB Release) - 虚拟桌面基础架构 (VDI) 和应用软件
|
5月前
|
弹性计算 关系型数据库 API
自建Dify平台与PAI EAS LLM大模型
本文介绍了如何使用阿里云计算巢(ECS)一键部署Dify,并在PAI EAS上搭建LLM、Embedding及重排序模型,实现知识库支持的RAG应用。内容涵盖Dify初始化、PAI模型部署、API配置及RAG知识检索设置。
自建Dify平台与PAI EAS LLM大模型
|
5月前
|
JSON 监控 前端开发
快手引流到微信的六种方法
快手引流至微信的6大技术实现方案(2025版) 一、API自动化交互方案
|
Java 关系型数据库 MySQL
|
数据采集 数据挖掘 数据处理
探索“数据菜谱”无限可能:首届Data-Juicer大模型数据竞赛
数据是LLaMA、Alpaca等大语言模型(LLM) 的“食物” ,你心中的大模型米其林菜单会是什么样呢?
|
存储 关系型数据库 MySQL
【阿里规约】阿里开发手册解读——数据库和ORM篇
从命名规范、建表规范、查询规范、索引规范、操作规范等角度出发,详细阐述MySQL数据库使用过程中所需要遵循的各种规范。
【阿里规约】阿里开发手册解读——数据库和ORM篇
|
存储 算法 Java
超全面!阿里巴巴最新发布23年秋招200道Java面试题(含答案)
马上过34岁生日了,和大家聊聊最近的情况 半年前还在迷茫该学什么,怎样才能走出现在的困境,半年后已经成功上岸阿里,感谢在这期间帮助我的每一个人。 面试中总结了200道经典的Java面试题,里面包含面试要回答的知识重点,并且我根据知识类型进行了分类,可以说非常全面了~ 因为篇幅原因,大部分的内容就不给大家一一展示了,需要获取的小伙伴可以直接点击此处取到! Java平台相关 1、JDK、JRE、JVM 分别是什么关系? 2、为什么 Java 被称作是“平台无关的编程语言”? 3、Java 和 C++ 的区别? 4、什么是字节码?采用字节码的最大好处是什么? 5、Java运行的过程? 6、
596 4
|
存储 SQL 缓存
【阿里巴巴Java编程规范学习 五】MySQL数据库规约
【阿里巴巴Java编程规范学习 五】MySQL数据库规约
2329 1
|
BI API 数据安全/隐私保护
自建API接口管理平台的产品脑图和解决方案
自建API接口管理平台的产品脑图和解决方案