字符串的输入是很基础的问题,不过其中的陷阱也不少。最关键的规避陷阱的方法就是心里清楚输入缓冲(stdio)里还有什么?
以下是十分常见的代码之一,其中scanf("%c", &ch);也经常用getchar(&ch);来写,
它们是一样的。它们有一个优秀之处是,所有的符号,甚至EOF都能获取并返回。
while(ch != '\n')
{
scanf("%c", &ch);
putchar(ch);
}
如果需要跳过所有的空格符号,就在%c之前加上‘ ’(空格)就好了。
while(ch != '#')
{
scanf(" %c", &ch);//格式里的空格表示可以跳过所有空格符号
putchar(ch);
}
其中需要值得注意的有一点,此时再也无法使用'\n'作为结束接收的界定符号,
因为'\n'会被scanf函数跳过,因而无法返回一个ch = '\n'。
在下面的代码里,我将'#'作为接收的结束界定符号,但是,这样还是会有一个问题!
因为文件是按照行存取的,所以scanf函数被设计成遇到回车'\n'才执行完。
因而你在输入一个串之后不免要按回车,例如你输入“I am a dog.#”之后不免要按下回车结束。
正因为如此,当上述代码运行到ch = '#'为真而跳出循环的时候,在输入缓冲里还留着一个'\n'。
下面贴出一个综合性质的例子。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch ;
printf("------输入以#结尾------\n") ;
while(ch != '#')
{
scanf(" %c", &ch);//格式里的空格表示可以跳过所有空格符号
putchar(ch);
}
fflush(stdin) ;
printf("\n-----输入以回车结尾-------\n") ;
while(ch != '\n') //如果注释了fflush,从上面会留下一个回车至此才被处理
{ //因此这一段只getchar一次,就退出循环
ch = getchar();
putchar(ch);
}
printf("-----输入带空格串-------\n") ;
char str[100] ;
gets(str);//允许输入带空格串
puts(str);
printf("-----输入带空格串(淫技)-------\n") ;
scanf("%[^\n]",str);//允许输入带空格串
puts(str);
if(getchar() == '\n') puts("That is a '\\n' stay here.");
printf("-----输入串不允许带空格-------\n") ;
while(1)
{
scanf("%s", str);
puts(str);
}
return 0;
}
下面介绍几个输入一行字符串到buffer的方法,其中的优劣都写在注释里了。
#include<stdio.h>
//3个行输入方案
int readLine(char str[], int n)//周立功新书《程序设计与数据结构》的例子
{
int ch, i = 0;
while((ch = getchar()) != '\n')//这样的好处是可以把stdin清除
{
if(i < n)
str[i++] = ch;
}
str[i] = '\0';
return 0;
}
int main(int argc, char *argv[])
{
int ch ;
char str[5] ;
readLine(str,5);//行输入的方法1,我觉得最优秀的方法,不用担心输入缓冲还滞留着字符的问题
puts(str);
//memset(str,'\0',5);
fgets(str, 5, stdin);//遇到\n会结束输入,缺点是没能把sedin清除,优点是把末尾补充'\0',还有缺点就是输入长度不足5的串,会把\n也放进buffer。
puts(str);
fread(str,5,1,stdin);//装满buf才结束,没能把sedin清除,末尾不补充'\0'
puts(str);
while((ch = fgetchar()) != EOF){
putchar(ch);
printf(".");
}
return 0 ;
}