我的代码是这样的:
char k[1000];
while(1){
scanf("%s",&k);
if(k[0] == '\n'){
exit(0);}
/* Do some processing on k */
memset(k,0,1000);
}
我的目的是按正常方式处理用户输入,并在用户输入空字符串或新行时终止。这似乎不起作用。
你们可以帮忙解决问题吗?
相关说明,我也想终止,如果它是文件的结尾,我应该如何为EoF做?
提前感谢您的帮助。
答案 0 :(得分:3)
首先关闭 - 不要使用scanf
进行用户输入。这是一个微妙问题的雷区,等待咬新C程序员,而是使用面向行的输入函数,如fgets
或POSIX getline
。每次都读取(包括)尾随'\n'
(只要你为fgets
提供足够大小的缓冲区 - 否则它只是继续读取缓冲区大小的字符块,直到它遇到'\n'
或EOF
)
因此,要读取用户输入,直到遇到空字符串或EOF
,您可以执行以下操作:
#include <stdio.h>
#include <string.h>
#define MAXC 1000
int main (void) {
char k[MAXC] = "";
for (;;) { /* loop until empty-string of EOF */
printf ("input: "); /* prompt for input */
if (fgets (k, MAXC, stdin)) { /* read line (MAXC chars max) */
if (*k == '\n') { /* test for empty-string */
fprintf (stderr, "empty-string! bye.\n");
break;
}
size_t l = strlen (k); /* get length of string */
if (l && k[l - 1] == '\n') /* check if last char is '\n' */
k[--l] = 0; /* overwrite with nul-terminator */
printf ("got input: %s\n", k);
}
else { /* got EOF */
fprintf (stderr, "EOF -- bye.\n");
break;
}
}
return 0;
}
示例使用/输出
>bin\fgets_user_input.exe
input: this
got input: this
input: is some
got input: is some
input: input
got input: input
input:
empty-string! bye.
>bin\fgets_user_input.exe
input: this is more
got input: this is more
input: ^Z
EOF -- bye.
>bin\fgets_user_input_cl.exe
input: it works the same
got input: it works the same
input: compiled by gcc
got input: compiled by gcc
input: or by cl.exe (VS)
got input: or by cl.exe (VS)
input:
empty-string! bye.
(注意:对于Linux Ctrl + d 生成EOF
,我恰好在上面的windoze上)
答案 1 :(得分:1)
与往常一样,这里的问题是scanf()
的使用不当。 scanf()
不是读取输入,而是解析,而格式字符串告诉它如何解析。
在你的情况下,%s
正在寻找一系列非空白字符(IOW,一个单词),它会跳过任何前导空格。 \n
(换行符)只是一个空白字符,因此总是会被跳过 - 您的scanf()
只会等待更多输入,直到它可以解析%s
。
有关scanf()
陷阱的更多信息,我建议你beginners' guide away from scanf()
。根据经验,使用交互式输入(这是默认设置),scanf()
几乎总是错误的。
scanf("%s", ...)
还有一个很大的问题:只要输入包含非空白字符,就会像gets()
那样溢出你提供的任何缓冲区。因为这个原因,甚至从C中删除了:缓冲区溢出是非常危险的!因此,请始终使用字段宽度scanf("%999s", ...)
。这将解析最多999个字符,其中一个字符用于终止字符串的必要0
字节。
但现在关于如何正确地做到这一点:C中有几个功能确实用于读取输入,其中一个用于读取输入的行: fgets()
。在您的代码中,它看起来像这样:
char k[1000];
while(fgets(k, 1000, stdin)){
if(k[0] == '\n'){
exit(0);
}
/* Do some processing on k */
memset(k,0,1000);
}
我在这里使用了您的原始代码,还有一些进一步的评论:
最好定义一个宏而不是使用幻数1000
,例如#define INPUTSIZE 1000
并使用此代码,例如char k[INPUTSIZE];
,fgets(k, INPUTSIZE, stdin)
等。
不需要清除整个数组,因此为了避免不必要的工作,请将memset()
替换为k[0] = '\0';
或类似内容。 C字符串以第一个0
字节结束,因此这足以使k
保持空字符串。如果你的程序没有比这里显示的更多,你甚至可以完全摆脱这一点,因为下一个fgets()
调用会反正覆盖数组(或者在出错时返回NULL
,这将停止循环)。
另请注意,fgets()
会在结尾处读取整行包括换行符,因此在处理k
的内容时请记住这一点。
答案 2 :(得分:-1)
这个保证为你提供除换行(和EOF)之外的所有内容:
char k[1000];
scanf("%[^\n]", k);
当它返回时,保证下一个字符是换行符,或者根本不存在(达到EOF)。得到它:
int next_char = getcgar();
if (next_char == EOF){
your_eof_process();
}
else if (nexr_char == '\n'){
your_newline_process();
}
就个人而言,我只会使用getchar()
:
char k[1000];
int ind, tempc;
for (ind = 0; ind < sizeof k; ind ++){
tempc = getchar();
if (tempc == '\n'){
// Some stuff
}
else if (tempc == EOF){
// Other stuff
}
else {
k[ind] = tempc;
}
}
k[sizeof(k)-1] = '\0';