当我不使用任何扫描集或否定扫描集时,遇到缓冲区中的哪个字符会使scanf()
停止从缓冲区读取数据(假设字符数组足够大)?似乎答案是空白的,因为如果我们在输出中输入一个多措辞的句子,那么默认scanf()
只存储第一个单词,但是当我运行此代码时:
int main(void) {
char n[20];
int status;
do {
status = scanf("%[^ ]", n);
//status = scanf("%s", n);
printf("%d %s\n", status, n);
} while (status);
return 0;
}
并输入hello world
作为输入并按返回键,输出为:
1 hello
0 hello
当我将do
- while
更改为:
do {
//status = scanf("%[^ ]", n);
status = scanf("%s", n);
printf("%d %s\n", status, n);
} while (status);
我将此作为输出(对于相同的输入):
1 hello
1 world
并且程序无法自行终止
同样,对于第一个do
- while
,如果我输入hello
并按回车键,我就不会得到任何输出,程序也不会终止(显然是因为它读不到空间)。但对于第二个do
- while
,情况并非如此。
如果有人能够回答如何更改我的代码以使其在按下返回键时终止,同时一次存储一个单词,那就太棒了。
答案 0 :(得分:3)
默认情况下,读取输入缓冲区中的哪个字符会使scanf()停止读取字符串?
没有默认值
何时/如何scanf()
停止取决于格式。遇到文件结束或输入错误时,读取也将停止。
// format "%c"
// Reads 1 character, then stops, no special value stops it early.
char ch;
scan("%c", &ch);
// format "%9[^ ]"
// Reads up to 9 non-space characters, then stops. Even reads a null character.
char buf[10];
scan("%9[^ ]", buf);
// format "%9s"
// Reads and discards leading white-space characters,
// then reads/saves up to 9 non-white-space characters, then stops.
// Even reads a null character.
char buf[10];
scan("%9s", buf);
// format "xyz"
// Reads up to 3 characters that match the pattern "xyz", then stops.
scan("xyz");
答案 1 :(得分:2)
使用scanf捕获输入很困难。使用fgets
可以通过检查索引[0]轻松查看是否输入了空白行。使用sscanf解析每个单词。 %n
说明符将告诉您扫描中使用了多少个字符。可以将该值添加到指针temp
以解析每个单词。
#include <stdio.h>
#include <stdlib.h>
int main() {
char n[256] = { '\0'};
char word[256] = { '\0'};
char *temp = NULL;
int result = 0;
int chs = 0;
while ( 1) {
printf("\nEnter text(enter only to exit)\n");
fgets ( n, sizeof n, stdin);
if ( n[0] == '\n') {
break;
}
temp = n;
while ( 1 == ( result = sscanf ( temp, "%255s%n", word, &chs))) {
temp += chs;
printf ( "%s\n", word);
}
}
return 0;
}
另一种方法是使用getchar
读取每个字符。检查要退出的换行符,检查空格以打印每个单词并检查可打印字符是否累积到每个单词中。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LIMIT 79
int main( void) {
char n[LIMIT + 1] = { '\0'};
int at = 0;
int ch = 0;
printf ( "type the text and press enter\n");
while ( ( ch = getchar ( )) != EOF) {
if ( ch == '\n') {
if ( at) {
fputs ( n, stdout);
fputc ( '\n', stdout);
}
at = 0;
break;
}
if ( at >= LIMIT || isspace ( ch)) {
if ( at) {
fputs ( n, stdout);
fputc ( '\n', stdout);
}
at = 0;
}
if ( isgraph ( ch)) {
n[at] = ch;
at++;
n[at] = '\0';
}
}
if ( at) {
fputs ( n, stdout);
fputc ( '\n', stdout);
}
return 0;
}
答案 2 :(得分:1)
对于否定的扫描集,当scanf()
从stdin
获取与扫描集匹配的字节(%[^ ]
格式的空格)或到达文件末尾时,scanf()
将停止读取
请注意,如果它立即读取匹配字节或文件末尾,则转换失败,0
分别返回EOF
或n
。
如果转换失败,您应该更改代码以避免将printf()
数组传递给printf()
,因为它未初始化且n
中的行为未定义。
您还应该通过在null终结符之前将最大字符数存储到#include <stdio.h>
int main(void) {
char n[20];
int status;
while ((status = scanf("%19[^ ]", n)) == 1) {
printf("%d %s\n", status, n);
}
printf("stop with status=%d\n", status);
return 0;
}
来防止潜在的缓冲区溢出。
这是一个更安全的版本:
stdin
上述循环的问题是第二次迭代将失败,因为scanf(" %19[^ ]", n)
中的空格仍处于暂挂状态。
scanf
,但这会跳过其他空格,例如换行符。#include <stdio.h>
int main(void) {
char n[20];
int status;
while ((status = scanf("%19[^ \n]", n)) == 1) {
printf("%d %s\n", status, n);
scanf("%*[ \n]"); // skip spaces
}
printf("stop with status=%d\n", status);
return 0;
}
更严格的解决方案是在每次成功转换后跳过待处理的空格:
#include <stdio.h>
int main(void) {
char n[20];
int c, status;
for (;;) {
if ((c = getchar()) == EOF || c == '\n')
break;
ungetc(c, stdin);
if ((status = scanf("%19[^ \n]", n)) == 1) {
printf("%d %s\n", status, n);
scanf("%*c"); // skip the space or newline that stopped the scanf
} else {
printf("stop with status=%d\n", status);
break;
}
}
return 0;
}
如果你想在空行上按Enter键退出循环,你可以先测试这个,如果不是换行符,则取消该字节:
{{1}}