while((ch = getchar()) != EOF && ch !=‘\n‘) | 作用 | 清空缓存区 | C和指针

题目

使程序先读取一段列标号,该列标号成对出现,表示输入行的列范围。这串列标号以一个负值结尾,作为结束标志。剩余输入行被程序读入并打印,然后输入行中被选中范围的字符串被提取出来并打印。

源代码

#include <stdio.h>
#include <stdlib.h>										/*定义EXIT_SUCCESSandEXIT_FAILURE符号*/ 
#include <string.h>
#define  MAX_COLS  20         							/*最大列号*/ 
#define  MAX_INPUT 1000       							/*输入的最大长度*/ 
/*提前声明自定义函数*/ 
int  read_column_numbers( int columns[], int max );
void rearrange( char *output, char const *input,int n_columns, int const columns[]);
/*主函数*/ 
int main(void)                							/*不接受参数的整型main*/ 
{
	int   n_columns;									/*进行处理的列标号*/ 
	int   columns[MAX_COLS];							/*需要处理的列数,即输入的范围以及-1,成对出现*/ 
	char  input[MAX_INPUT];								/*容纳输入*/ 
	char  output[MAX_INPUT];							/*容纳输出*/ 
	/*读取需要处理的列标号*/ 
	n_columns=read_column_numbers(columns,MAX_COLS);	/*调用read_column_numbers读取列号#26*/ 
	while(gets(input)!=NULL){							/*循环打印,直到文章末尾*/ 
		printf("Original input : %s\n", input );		
		rearrange( output, input, n_columns,columns );	/*处理输入行#46*/ 
		printf("Rearranged line:%s\n", output );
	}
	return EXIT_SUCCESS;
}
/*读取范围列标号,超出规定范围不予理会*/ 
int read_column_numbers( int columns[], int max )
{
	int num = 0;										/*列标号*/ 
	int ch;												/*字符型为小整型数,用int定义防止将输入字符意外定义成EOF(整型),还保证了ch空间足够大*/ 
	/*读取输入需要处理列标号即范围,限制条件*/ 
	while(num<max&&scanf("%d",&columns[num]) ==1&&columns[num]>= 0 )
	num+=1;
	/*判断范围输入列数是否为双数*/ 
	if(num%2!=0){
		puts("Last column number is not paired.");		/*打印错误信息*/ 
		exit(EXIT_FAILURE);								/*终止程序运行,向系统报错*/ 
	}
	/*丢弃该行中-1后面的所有字符清空缓冲区*/ 
	
	while((ch = getchar()) != EOF && ch !='\n')			/*读取字符为空或换行符时结束循环*/ 
	;

	return num;
}
/*处理输入行,将指定列的字符连接*/ 
void rearrange (char *output, char const *input,int n_columns, int const columns[])		/*const防止实参中的值被改动*/ 
{
	int  col;											/*范围数组的下标*/ 
	int  output_col;									/*输出列的计数器*/ 
	int  len;											/*输入行长度*/ 
	
	len = strlen(input);								/*获得输入字符串长度*/ 
	output_col = 0;										/*输出列计数器初始为0*/ 
	/*处理每对列标号*/ 
	for(col=0;col<n_columns;col+=2){
		int nchars =columns[col+1]-columns[col]+1;		/*每对列标号之间的空间*/ 
		/*当输入行结束或输出行数组已满时,结束任务*/ 
		if(columns[col]>= len||output_col == MAX_INPUT-1)
		break;
		/*判断输出行数据空间是否足够*/ 
		if(output_col+nchars>MAX_INPUT-1)
		nchars=MAX_INPUT-output_col-1;
		/*复制可容纳的相关数据*/ 
		strncpy(output+output_col,input+columns[col],nchars);
		output_col+=nchars;
	}
	output[output_col]='\0';
}

问题代码 while((ch = getchar()) != EOF && ch !=’\n’)

int ch;												/*字符型就是小整型数,用int定义防止将输入字符意外定义成EOF(整型),还保证了ch空间足够大*/ 
while((ch = getchar()) != EOF && ch !='\n')			/*读取字符为空或换行符时结束循环*/ 
	;

过一遍程序执行过程:
当输入流输入范围列标号如:2 9 12 20 -1并回车后,缓存区便存在 2 9 12 20 -1 ‘\n’ 这6个字符。其中包括-1的5个数字都被scanf函数读取,于是缓存区便留下了’\n’这一个字符,而这个字符便处于待读取状态,如果没有进行清空操作(即去掉while((ch = getchar()) != EOF && ch !=’\n’))该字符就会被下一个gets(input)函数识别,执行时便出现这样的结果:
输入4 9 12 20 -1后按一次回车
即按下第一个回车后直接执行到打印结果,输入输出显示都为空。
为了更直观的表现我们在命令窗口输入的范围结尾再加上几个数字,即输入:4 9 12 20 -1 2333 然后回车,这时候缓冲区就有了4 9 12 20 -1 2333 ‘\n’ 这7个字符,而scanf函数仍然读取包括-1前的5个字符,后面的两个字符仍然在缓存区待读取。此时回车后gets(input)就会直接读取剩下的字符:
输入4 9 12 20 -1 2333 后按一次回车
显然这并不是我们想要的效果,我们要去除-1后任何因为手抖或其他干扰因数造成的无用字符,以及用于scanf识别的’\n’。
于是就需要一个“垃圾桶”来装这些“垃圾”使gets(input)只读到我们想要处理的一串字符。
而在这一个程序里的“垃圾桶”就是变量ch,清空操作就是getchar读取这些无用字符放到ch里,直到’\n’被ch读取后ch!=’\n’的值就为0,跳出循环,此时“地板”上就干干净净的,而gets(input)没的“吃”只能等你再“投食”他才做出反应,而得到的结果也没了干扰。

同样的输入,我们加上while((ch = getchar()) != EOF && ch !=‘\n‘)后执行的结果:
输入4 9 12 20 -1 2333后回车再输入字符串再回车
此时在第一个回车后程序并不会打印结果,说明缓冲区没有供gets(input)识别的’\n’,而输入新字符串后回车的结果也没有2333的干扰,因为2333和第一个’\n’已被ch依次读取了。

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Weskiey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值