从一行中读取多个字符串。检测无效输入

Reading multiple strings from one line. Detecting invalid input

我正在尝试编写一个程序,在单个输入行中读取由单个 space 分隔的 2 个单词。

正常输入应如下所示:Apple Banana。 Apple 应写入 FirstWord,Banana 应写入 SecondWord

目前我正在使用 scanf 并用它读取字符串。 那是我的代码:

int main (void) {
  char FirstWord[10];
  char SecondWord[10];

  while (true) {
    printf("Enter two words: ");
    scanf("%s", FirstWord);  

    if(!strcmp(FirstWord, "quit")) {
      printf("Exit.");
      return 0;
    }
    scanf("%s", SecondWord);
    printf("First word is %s \nSecond word is %s\n", FirstWord, SecondWord);
  }
}

程序正常运行,一般来说,但存在一个问题,即检测到来自用户的无效输入。

如何检测用户是否只输入了一个单词或空行?现在第二个 scanf 等待第二个字符串,以防只输入一个单词。

是否可以用 scanf 来处理这个问题,或者我应该用 fgets 得到 1 个字符串,然后将它分成两个字符串?

当您希望用户输入两个词时,您还希望能够处理用户输入一个词的情况(可能认为他们会在下一行输入下一个词,等等... ) 将 scanf()"%s" 转换说明符一起使用的问题是它忽略前导 whitespace 并且 '\n' 字符是 whitespace。因此,如果只输入一个单词,您就没有机会提示输入第二个单词,因为 scanf() 会阻塞等待第二个输入。

任何时候接受用户输入时,我们都鼓励您使用 fgets() 填充缓冲区(字符数组),然后从缓冲区中解析(分离)所需的值。为什么? fgets() 将消耗整行输入(给定足够大的缓冲区)。这可以确定 stdin 中不会有任何内容未读 --- 只是等着在你的下一个输入中咬你。

然后您可以使用 sscanf() 解析缓冲区中的值,就像使用 scanf() 解析输入中的值一样。但是,您已经将输入和转换分离,因此如果 sscanf() 转换失败,它不会影响您下次尝试从 stdin.

读取

使用fgets() 还提供了一种结束输入的便捷方式。由于 fgets() 读取用户按 Enter 生成的 '\n' 字符,因此您只需要检查填充缓冲区中的第一个字符是否为 '\n' 字符知道用户只是在空白行上按了 Enter。这可以作为一种非常方便的方式来确定用户是否完成,而不需要额外的输入,例如 strcmp(FirstWord, "quit"),等等...

如果我理解你希望能够无缝地处理来自用户的一两个输入并在用户只提供一个的情况下进行提示,你可以这样做:

#include <stdio.h>

#define WORDSZ 32               /* if you need a constant, #define one (or more) */
#define MAXC 1024

int main (void) {
  
  char FirstWord[WORDSZ];                           /* declare arrays */
  char SecondWord[WORDSZ];
  char buf[MAXC];                                   /* buffer to hold entire line */
  
  puts ("press [Enter] on empty line when done.");
  
  while (1) {   /* loop continually until both filled or user cancels */
    fputs ("\nEnter two words: ", stdout);          /* prompt both */
    if (fgets (buf, MAXC, stdin) == NULL) {         /* read into buf, validate */
      puts ("(user canceled input)");
      return 0;
    }
    else if (*buf == '\n')                          /* if [Enter] on empty line */
      break;
    
    /* validate conversion, check if only one word read */
    if (sscanf (buf, "%31s %31s", FirstWord, SecondWord) == 1) {
        while (1) { /* if so, loop until second word read */
            fputs ("Enter second word: ", stdout);  /* prompt 2nd word */
            if (!fgets (buf, MAXC, stdin)) {        /* read into buf, validate */
              puts ("(user canceled input)");
              return 0;
            }
            
            if (sscanf (buf, "%31s", SecondWord) == 1)  /* validate word entered */
              break;
        }
    }
    
    printf ("\nFirst word is %s \nSecond word is %s\n", FirstWord, SecondWord);
  }
}

(注意: 您必须始终提供比数组大小小一的 field-width 修饰符,以保护所有字符串转换使用 scanf() 系列函数时您的数组边界。否则使用 scanf() 并不比使用 gets() 更安全,参见 Why gets() is so dangerous it should never be used!)

由于用户通过生成手册 EOF 取消输入是完全有效的,因此您需要在每次使用 fgets() 阅读后检查手册 EOF,方法是检查 return 是 NULL。用户按 Ctrl + dCtrl + z on windows)生成手册 EOF

例子Use/Output

$ ./bin/firstsecondword
press [Enter] on empty line when done.

Enter two words: hello
Enter second word: world

First word is hello
Second word is world

Enter two words: hello world

First word is hello
Second word is world

Enter two words:

检查一下,如果您还有其他问题,请告诉我。