在C语言中读取带有空格的字符串

7

我正在尝试读取一个包含空格或不包含空格的字符串,例如 "hello world"。通过以下方式实现,使用由用户输入的数字选择菜单。这只是我试图做的事情的一个小型复制。

#include <stdio.h>
#include <string.h>

int main(void){
  char line[3][80];

  strcpy(line[0],"default line 1\n");
  strcpy(line[1],"default line 2\n");
  strcpy(line[2],"default line 3\n");

  for(int i = 0; i < 3; i++){
    printf("%s", line[i]);
  }

  int option = 0;
  printf("would you like to replace line 1? (1 for yes)\n");
  scanf("%d",&option);
  if(option==1){
   printf("what would you like to replace the line with?\n");
   fgets(line[0],strlen(line[0]),stdin);
  }

  for(int i = 0; i < 3; i++){
    printf("%s", line[i]);
  }
}

为什么我输入1换行后,它会打印出要替换成什么的语句,然后自动输入空值,接着将字符串打印出来,第一个字符串为空?

我已经尝试使用sscanf("%[^\n\t]s", line[0]);读取该行,但没有成功。有什么想法吗?


我猜测 fgets 将文件流的第一个字符读取为 eof(文件结尾)。 - user5455540
我相信这与询问用户是否要替换行之前的 scanf("%d", &option) 有关,但我不确定是否有修复的方法。 - TheBoxOkay
2
与您的问题无直接关系,但应该将strlen(line[0])替换为80。缓冲区的大小并不是它包含的字符串的长度,而是缓冲区的总长度,在这里是80 - Jabberwocky
3个回答

10

这是因为

scanf("%d",&option);

在标准输入stdin中,\n字符会留在那里并被第一次调用fgets()函数消耗掉。

这就是为什么最好完全避免在C语言中使用scanf()函数。

您可以通过以下方式进行修复:

  scanf("%d",&option);
  getchar(); /* consume the newline */

但我建议也使用fgets()来读取option,然后您可以使用strtol()将其转换为整数。

请注意,这个语句可能不是您想要的(它会限制您可以读入到line[0]的内容)。

   fgets(line[0],strlen(line[0]),stdin);

您可能想要使用:

   fgets(line[0],sizeof line[0],stdin);

这样你就可以读取到line[0]的实际大小。

请阅读C语言常见问题集的相关条目:http://c-faq.com/stdio/scanfprobs.html


3
我确认,scanf 很糟糕,这种问题很常见。要了解更多信息,请谷歌“_scanf is evil_”(不是开玩笑)。 - Jabberwocky

4

fgets() 通常比使用 scanf() 更不容易出错,但是如果用户输入的字符串长度等于或超过指定的最大字符数,那么多余的字符(包括换行符)将保留在输入流中。因此,我通常会编写自己的 gets() 版本来获取用户输入字符串,如果需要数字输入,则使用 strtol()。以下是这样一个函数的示例:

char * s_gets(char *st, int n)
{
    char *ret;
    int ch;

    ret = fgets(st, n, stdin);
    if (ret) {
        while (*st != '\n' && *st != '\0')
            ++st;
        if (*st)
            *st = '\0';
        else {
            while ((ch = getchar()) != '\n' && ch != EOF)
                continue;           // discard extra characters
        }
    }
    return ret;
}

针对 OP 的问题,我可能会这样做:

#include <stdlib.h>                // for strtol()

...

char buf[80];
int option = 0;

printf("would you like to replace line 1? (1 for yes)\n");
s_gets(buf, sizeof(buf));
option = strtol(buf, NULL, 10);

if(option==1){
    printf("what would you like to replace the line with?\n");
    s_gets(line[0],sizeof(line[0]));
}

3

你的问题是 '\n' 字符被留在了 stdin 中并被 fgets 消耗掉了。

我建议你始终使用 fgets 来读取输入,因此

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    char line[3][80];
    char temp[3];

    strcpy(line[0],"default line 1\n");
    strcpy(line[1],"default line 2\n");
    strcpy(line[2],"default line 3\n");

    for(int i = 0; i < 3; i++){
        printf("%s", line[i]);
    }

    int option = 0;
    printf("would you like to replace line 1? (1 for yes)\n");
    fgets(temp,sizeof(temp),stdin);
    option = atoi(temp);

    if(option==1){
        printf("what would you like to replace the line with?\n");
        fgets(line[0],sizeof(line[0]),stdin);
    }

    for(int i = 0; i < 3; i++){
    printf("%s", line[i]);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接