默认情况下,读取输入缓冲区中的哪个字符会使scanf()停止读取字符串?

时间:2017-01-21 18:43:13

标签: c string input scanf

当我不使用任何扫描集或否定扫描集时,遇到缓冲区中的哪个字符会使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,情况并非如此。

如果有人能够回答如何更改我的代码以使其在按下返回键时终止,同时一次存储一个单词,那就太棒了。

3 个答案:

答案 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分别返回EOFn

如果转换失败,您应该更改代码以避免将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}}