**getchar()和putchar()**每次只处理一个字符。
/********************************************************************************
* @author: Mr.Y
* @date: 2022/5/2 17:35
* @description: 获取从键盘输入的字符,并把这些字符发送到屏幕上。
* 程序使用while循环,当读到#字符时停止。
* 存在的问题:如果用一个特殊字符(如:#)来结束输入,就无法在文本中使用这个字符,如何解决。
********************************************************************************/
#include
int main(void)
{
char ch;
while ((ch = getchar()) != '#')
putchar(ch);
return 0;
}
/***
* output
* Hello, there. I would
* Hello, there. I would
* like a #3 bag of potatoes.
* like a
*/
在老式系统运行上面程序可能显示如下:
HHeelllloo,, tthheerree.. II wwoouulldd[enter]
lliikkee aa #
像这样回显用户输入的字符后立即重复打印该字符是属于无缓冲输入,即正在等待的程序可立即使用输入的字符。
大部分系统在用户按下Enter键之前不会重复打印刚输入的字符,这种输入形式属于缓冲输入。用户输入的字符被收集并存储在一个被称为缓冲区(buffer)的临时存储区,按下Enter键后,程序才可使用用户输入的字符。
为什么需要缓冲区?
缓冲分类
使用缓冲输入还是无缓冲输入?
检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。
如今,操作系统可以使用内嵌的Ctrl+Z字符来标记文件结尾。这曾经是操作系统使用的唯一标记,不过现在有一些其他的选择,如记录文件的大小。所以现代的文本文件不一定有嵌入的Ctrl+Z,但是如果有,该操作系统会将其视为一个文件结尾标记。
操作系统使用的另一种方法是存储文件大小的信息。如果文件有3000字节,程序在读到3000字节时便达到文件的末尾。
在C语言中,用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF。scanf()函数检测到文件结尾时也返回EOF。通常,EOF定义在stdio.h文件中:
#define EOF (-1)
为什么是**-1**?因为getchar()函数的返回值通常介于0—127,这些值对应标准字符集。但是,如果系统能够识别扩展字符集,该函数的返回值可能在0—255。无论哪种情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。
某些系统也许把EOF定义为**-1以外的值,但是定义的值一定与输入字符所产生的返回值不同。如果包含stdio.h文件,并使用EOF符号,就不必担心EOF**值不同的问题。
如果正在读取的是键盘输入不是文件会怎样?绝大多数系统都有办法通过键盘模拟文件结尾条件。如下代码:
/********************************************************************************
* echo_eof.c
* @author: Mr.Y
* @date: 2022/5/3 18:54
* @description: 重复输入,直到文件结尾
********************************************************************************/
#include
int main(void)
{
int ch;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
以上程序注意事项
将文件内容使用程序输入至控制台。
假设已经编译了上面程序中的echo_eof.c程序,并生成一个名为echo_eof(在windows系统中名为echo_eof.exe)的可执行文件。运行程序,输入可执行文件名称。
程序运行与前面描述一样,获取用户从键盘输入的输入,假设现在要处理名为xxx的文本文件。只需使用下面的命令代替上面的命令。
可执行文件名 < 文本文件名
<符号是UNIX和DOS/Windows的重定向运算符。该运算符使words文件与stdio流相关联,把文件中的内容导入echo_eof程序。
将控制台内容输出至文件。
假设要用echo_eof.exe程序将键盘输入的内容发送到名为myworlds的文件中。使用以下命令并开始键盘输入。
可执行文件名 > 文本文件名
符号**>是第二个重定向运算符。它创建一个名为xxx的文件,然后把可执行文件的输出重定向至该文件中。重定向把stdout从显示设备赋给xxx文件。如果已经有一个名为xxx**的文件,通常会擦除该文件的内容,然后替换新的内容。
使用下面的命令也可以,因为命令与重定向运算符的顺序无关。
echo_eof.exe > savewords < myworlds
在一条命令中,输入文件名和输出文件名不能相同。
在系统中使用两个重定向运算符(<和>)时,需要遵守以下原则。
UNIX,Linux或Windows/DOS还有**>>运算符,该运算符可以把数据添加到现有文件的末尾,而|**运算符能把一个文件的输出连接到另一个文件的输入。
缓冲输入用起来比较方便,因为在把输入发送给程序之前,用户可以编辑输入。但是在使用输入的字符时,也会带来麻烦,缓冲输入要求用户按下Enter键发送输入。这一动作也传送了换行符,程序必须妥善处理这个麻烦的换行符。
/********************************************************************************
* @author: Mr.Y
* @date: 2022/7/19 15:21
* @description: 用户选择一个数字,程序猜用户选择的数字是几。
* 用户只能输入'n'或'y'
********************************************************************************/
#include
int main(void)
{
int guess = 1;
char response;
printf("Pick an integer from 1 to 100. I will try to guess ");
printf("it.\nRespond with a y if my guess is right and with");
printf("\nan n if it is wrong.\n");
printf("Uh...is your number %d?\n",guess);
while ((response = getchar()) != 'y') /*获取响应*/
{
if (response == 'n')
printf("Well, then, is it %d\n",++guess);
else
printf("Sorry, I understand only y or n.\n");
while (getchar() != '\n')
continue; /*跳过剩余的输入行*/
}
return 0;
}
/**
*output
* D:\code\CLion\C_Primer_Plus\cmake-build-debug\guess.exe
* Pick an integer from 1 to 100. I will try to guess it.
* Respond with a y if my guess is right and with
* an n if it is wrong.
* Uh...is your number 1?
* 1
* Sorry, I understand only y or n.
* n
* Well, then, is it 2
* q
* Sorry, I understand only y or n.
* y
Process finished with exit code 0
**/
假设程序要求用**getchar()处理字符输入,用scanf()处理数值输入,这两个函数都能很好地完成任务,但是不能把它们混用。因为getchar()读取每个字符,包括空格,制表符和换行符;而scanf()**在读取数字时则会跳过空格,制表符和换行符。
/********************************************************************************
* @author: Mr.Y
* @date: 2022/7/20 18:23
* @description: 程序读入一个字符和两个数字,然后根据输入的两个数字指定的行数和列数打印该字符
********************************************************************************/
#include
void display(char cr,int lines,int width);
int main(void)
{
int ch; /*待打印字符*/
int rows,cols; /*行数和列数*/
printf("Enter a character and two integers:\n");
while ((ch = getchar())!='\n')
{
if(scanf("%d %d",&rows,&cols) != 2)
break;
display(ch,rows,cols);
while (getchar()!='\n')
continue;
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\n");
return 0;
}
void display(char cr,int lines,int width)
{
int row,col;
for (row = 1; row <= lines ; row++)
{
for(col = 1;col <= width;col++)
putchar(cr);
putchar('\n');
}
}
/*
* output
* Enter a character and two integers:
* w 3 4
* wwww
* wwww
* wwww
* Enter another character and two integers;
* Enter a newline to quit.
* t 3 6
* tttttt
* tttttt
* tttttt
* Enter another character and two integers;
* Enter a newline to quit.
* Bye.
* */