计算机CPU的处理速度是很快的,我们用键盘输入速度比不上CPU的处理速度,CPU就得等键盘输入完,很浪费资源,所以,当键盘输入完了,让CPU一次性处理,可以大大提高效率。
getchar:
函数声明:int getchar(void);
字符输入函数,程序第一次遇到getchar函数,会让用户输入,当输入回车时结束,此时输入的内容存入到缓冲区中(包括回车符号\n)。并且返回缓冲区里读取一个字符对应的ASCII编码(通过调用putchar(n)或者printf("%c", temp1)的方式输入第一个字符)。
下面看个例子:
#include <stdio.h>
int main()
{
int temp1;
temp1 = getchar();
putchar(temp1);
temp1 = getchar();
putchar(temp1);
printf("\n");
return 0;
}
运行结果:
输入asd,会输出as。当执行第一次getchar方法时,获取到的是第一个字符"a",下次在执行getchar方法时可以获取到第2个字符"s"。说明getchar方法内部实现了i的自增。
如果希望将输入的每一个字符都打印出来可以用while循环:
如果希望另一个变量temp2使用getchar方法,并且是temp2另起一行重新输入,那么需要先清空缓冲区,这样输入的内容才是temp2的内容。实际上temp2只要不是程序检测到的第一个输入函数,都需要清理。
清理缓冲区代码:
int temp = 0;
while ((temp = getchar()) != '\n')
{
;
}
下面看一个例子:
#include <stdio.h>
int main()
{
char* temp1;
printf("学号:");
scanf("%s", temp1);
int temp2 = 0;
printf("姓名:");
temp2 = getchar();
printf("您的学号:%s\n", temp1);
printf("您的姓名:%c\n", temp2);
return 0;
}
使用scanf时, 会将\n存入输入缓冲区。所以getchar不会触发二次输入姓名,直接将\n赋值给了temp2,清空缓冲区即可:
同样地,如果使用fgets输入函数一样需要清理缓存区否则会出现非预期的效果。
代码:
#include <stdio.h>
int main()
{
char sc[100];
scanf("%s", sc);// 只能获得单词
printf("先使用scanf:%s\n", sc);
int temp = 0;
// while ((temp = getchar()) != '\n')
// {
// ;
// }
char words[10];
fgets(words, 10, stdin);
fputs(words, stdout);
fgets(words, 20, stdin);
fputs(words, stdout);
printf("%c:", *words);
puts("Done");
}
执行结果:
可以发现,使用scanf方法输入的回车会被第一个fgets获取到,此时words里只有一个\n字符。当第二次调用fgets方法时,又可以正常让我们输入了。所以需要在scanf函数之后就开始遍历执行getchar方法,来清空scanf方法输入的剩余字符(包括最后一个回车字符),当然这里只有一个\n字符的情况下,调用一次getchar()而不使用while循环也能达到预期效果。
实际上两个fgets之间往往需要删除缓冲区多余的字符,fgets函数用于读取一整行输入数据。第2个参数限制读入的字符来解决溢出的问题,如果参数是n,则读取n-1个字符或者遇到第一个换行符为止,换行符存入到字符串中。第3个参数指明要读入的文件,如果读入从键盘输入的数据,要以stdin为参数。如果输入了大于等于n个字符,第1个参数只获取n-1个字符,最后一个字符为\0,结果值为aa...\0,并且剩余部分还在缓冲区里。如果输入n-1个字符换行,最后的值为aa...\n,小于n-1个字符,最后的值为aa...\n\0,长度为输入的字符数在加2个字符。如输入一个字符,长度就是3。
所以当实际输入内容大于限制的字符数时,使用fgets读取完指定长度字符以后需要将剩余部分读取完:
#include <stdio.h>
int main()
{
char words[10];
int i;
// 当第一个字符输入换行符时退出程序
while (fgets(words, 10, stdin) != NULL && words[0] != '\n')
{
i = 0;
while (words[i] != '\n' && words[i] != '\0')
i++; // 匹配换行符\n或者空字符\0
if (words[i] == '\n')
words[i] = '\0'; // 换行符替换成空字符
else while (getchar() != '\n') {
continue; // 遇到空字符\0,这是因为输入的超过10个字符了但是还没换行,
// 此时words中的最后一个字符赋值为空字符\0,前面9个是输入的合法内容,
// 我们需要丢弃剩下的字符所以需要清空缓冲区剩余字段,否则下个输入函数不会另起一行输入而是从缓冲区直接取
}
puts(words);
}
puts("Done");
}
如果先遇到换行符,换行符替换成空白符(如果不替换,下一个fgets会获取这个换行符)。如果先遇到空字符,说明输入的内容超过限制的内容然后while循环将剩余部分读取完,当然最后一个换行符也会被getchar获取到,只不过不会执行continue罢了。这样就可以保证我们每次调用fgets方法,都会另起一行重新计数,当输入第一个字符为换行符时,整个程序退出第一个while循环:
如果使用scanf函数,也需要及时清除:
scanf("%d", ¤t->rating);
while (getchar() != '\n')
{
continue;
}
将fgets封装成一个函数:
char *s_gets(char *st, int n)
{
char *ret_val;
char *find;
ret_val = fgets(st, n, stdin);
printf("%s\n", ret_val);
if (ret_val)
{
find = strchr(st, '\n');
if (find)
{
*find = '\0';
}
else
{
while (getchar() != '\n')
{
continue;
}
}
}
return ret_val;
}
strchr函数(char *strchr(const char *str, int c))返回一个指向该字符串中第一次出现的字符的指针,如果字符串中不包含该字符则返回NULL空指针。需要引入string.h,这里的执行结果是在参数 st 所指向的字符串中搜索第一次出现字符'\n'的位置。如果是换行符,说明输入的内容没有超过限制,只需将换行符换成空字符:*find = '\0',否则输入的内容超过了n个字符,需要将缓冲区全部读取。
s_gets函数使用:while (s_gets(input, TSIZE) != NULL && input[0] != '\0') { // 内部实现 }