如何使用scanf()从输入中读取直到找到换行符?

29

我被要求用C语言编写一个程序,在程序中需要从输入流中读取内容,读到空格后停止读取,然后再读取一直到用户按下回车键为止。 如果我这样做:

scanf("%2000s %2000s", a, b);

它将遵循第一条规则,但不会遵循第二条规则。
如果我写:

I am smart

我得到的等同于:
a = "I";
b = "am";
但应该是:
a = "I";
b = "am smart";

我已经尝试过:

scanf("%2000s %2000[^\n]\n", a, b);

并且

scanf("%2000s %2000[^\0]\0", a, b);
在第一个示例中,它等待用户按下Ctrl+D(发送EOF),这不是我想要的。
在第二个示例中,它无法编译。根据编译器:
警告:格式字符串“% [”没有关闭‘]’符号。
有什么好的解决方法吗?
7个回答

52

scanf(以及相关函数)有一个稍微奇怪的特性:格式字符串中的空格(在大多数情况下)会匹配输入中任意数量的空格。恰好在默认的“C”语言环境中,换行符被归类为空格。

这意味着尾随的'\n'不仅要匹配一个换行符,还要匹配任何后续的空格。只有当您标志着输入的结束或输入了一些非空格字符时,它才会被视为已匹配。

应对这种情况的一种方法是像这样:

scanf("%2000s %2000[^\n]%c", a, b, &c);

if (c=='\n')
    // we read the whole line
else
    // the rest of the line was more than 2000 characters long. `c` contains a 
    // character from the input, and there's potentially more after that as well.

根据情况,您可能还想检查scanf的返回值,该值告诉您成功转换的数量。在这种情况下,您将寻找3,以指示所有转换都成功。


太好了!现在我明白了。我不知道规范中关于空格字符的那一部分。谢谢,这正是我需要的。另外,感谢%c提示,它对其他用途也很有用。 - brunoais
“outside of a scanset” 不足以描述所有情况: %c 和 %n 也是例外。 - user411313
难道不应该是 scanf(..., &c) 吗? - ScriptKidd
@HaxAddict1337:哎呀,非常正确。谢谢你。 - Jerry Coffin

13
scanf("%2000s %2000[^\n]", a, b);

5
使用getchar和while,代码应该类似于:
while(x = getchar())
{   
    if(x == '\n'||x == '\0')
       do what you need when space or return is detected
    else
        mystring.append(x)
}

很抱歉,如果我写了伪代码,因为我已经有一段时间没有使用C语言了。


1
现在我明白你的意思了。不过...我认为这有点复杂化了可以更简单地解决的问题。尽管如此,那也是可行的。 - brunoais

3

虽然我晚了,但您也可以尝试这种方法。

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

int main() {
    int i=0, j=0, arr[100];
    char temp;
    while(scanf("%d%c", &arr[i], &temp)){
        i++;
        if(temp=='\n'){
            break;
        }
    }
    for(j=0; j<i; j++) {
        printf("%d ", arr[j]);
    }

    return 0;
}

3
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int main(void)
{
  int i = 0;
  char *a = (char *) malloc(sizeof(char) * 1024);
  while (1) {
    scanf("%c", &a[i]);
    if (a[i] == '\n') {
      break;
    }
    else {
      i++;
    }
  }
  a[i] = '\0';
  i = 0;
  printf("\n");
  while (a[i] != '\0') {
    printf("%c", a[i]);
    i++;
  }
  free(a);
  getch();
  return 0;
}

为什么解决方案这么复杂?为什么要执行那么多不必要的操作? - brunoais
2
是的,brunoais,你说得很对!在我的代码中,我正在逐个字符地读取,这解释了“until”的问题,也有一些优化的方法。但对于刚开始编码的人来说,我的解决方案将是一个很好的例子,可以说明事情是如何工作的。 - Bharadwaj_Turlapati
1
@Bharadwaj_Turlapati 包含 <conio.h> 并使用 getch() 不是一个好的做法。也许有人不是在 Windows 上开发或学习。 - Paul Stelian

-1
#include <stdio.h>
int main()
{
    char a[5],b[10];
    scanf("%2000s %2000[^\n]s",a,b);
    printf("a=%s b=%s",a,b);
}

只需在 \n 的位置写入 s :)


此处的s没有意义。%[^\n]已经要求所有字符但不包括换行符。 - alk

-2

//如果你想输入更多的字符,增加字符数组的大小。

#include <stdio.h>
int main()
{
    char s[10],s1[10];
    scanf("\n");//imp for below statement to work
    scanf("%[^\n]%c",s);//to take input till the you click enter
    scanf("%s",s1);//to take input till a space
    printf("%s",s);
    printf("%s",s1);
    return 0;
}

在你的例子中,你忽略了输入直到新行,你没有进行安全检查,s 将始终为 \n。请参考被接受的答案获取一个示例答案。 - brunoais

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