我想输入带有空格的字符串,并将该字符串与另一个字符串一起打印在同一行上。
int i = 4;
double d = 4.0;
char s[] = "Apple ";
int x;
double y;
char z[105];
scanf("%d",&x);
scanf("%lf",&y);
scanf("%[^105\n]s",z);
printf("%d\n",i+x);
printf("%0.1lf\n",d+y);
printf("%s %s",s,z);
return 0;
scanf
函数的格式说明符"%[^105]s"
,其中[...]
是独立的说明符,不需要在末尾加上's'
。如果在末尾加上's'
,会强制scanf
查找一个紧随无数个(不包括1, 0, 5
)字符之后的字面值's'
。"%104[^\n]"
,它将读取多达104个不包括'\n'
的字符(保留空间给nul-character)。 if (scanf("%104[^\n]",z) == 1)
printf("%s %s\n",s,z);
注:始终通过至少检查返回值来验证所有用户输入。
还要注意:如果您不读取上面的'\n'
,它会留在您的输入缓冲区中(stdin
)未读取,并且如果您尝试的下一个输入是"%c"
或"%[...]"
,则您将将'\n'
作为输入的一部分,因为"%c"
和"%[...]"
都不会消耗前导空格。#include <stdio.h>
int main (void) {
char s[] = "Apple";
char z[105];
printf ("enter z: ");
if (scanf("%104[^\n]",z) == 1)
printf("%s %s\n",s,z);
else
fputs ("error: stream error or user canceled.\n", stderr);
return 0;
}
(注意: 读取行时,建议使用 fgets()
替代 scanf
,然后简单地修剪填充缓冲区中包含的 '\n'
)
示例用法/输出
$ ./bin/oneline
enter z: is a fruit
Apple is a fruit
使用 fgets()
代替
不要使用 scanf
进行行输入,而是使用一个面向行的输入函数,比如 fgets()
,它会读取整行(包括行尾符)。这样可以确保你的输入缓冲区保持一致的状态,不受之前格式说明符的影响,例如:
...
#include <string.h>
...
printf ("enter z: ");
if (fgets (z, sizeof z, stdin) != NULL) {
z[strcspn (z, "\n")] = 0; /* trim '\n' from end of z */
printf("%s %s\n",s,z);
}
在评论中编辑每个问题
你新代码的问题在于scanf("%lf",&y);
会将'\n'
留在stdin
中未读取,然后你尝试读取scanf("%[^105\n]",z);
,但由于你在反转字符类中排除了读取'\n'
,所以什么也没有被读取,接着你又从stdin
中读取输入,而第一个字符是'\n'
。"%[^105\n]"
的意思是:读取无限数量的字符,并且只有在遇到1, 0, 5
或'\n'
字符(或EOF
)时才停止读取。
使用scanf
进行混合输入对于新手C程序员来说充满了陷阱,因为它会在stdin
中留下什么,而如何处理前导的空格取决于所使用的格式说明符。这就是为什么推荐使用fgets()
(或POSIX getline()
)进行用户输入,然后使用sscanf
从填充的缓冲区中解析所需信息。使用基于行的输入函数,每次输入都会完全消耗一行(给定足够的缓冲区大小--不要吝啬),从而消除了scanf
的问题。
要使你当前的代码工作,你可以这样做:
#include <stdio.h>
/* simple function to empty remainder of line in stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
int i = 4, x;
double d = 4.0, y;
char s[] = "Apple ", z[105];
scanf("%d",&x);
scanf("%lf",&y); /* leaves '\n' as next char in stdin */
empty_stdin(); /* empty extraneous characters */
scanf("%104[^\n]",z); /* read up to 104 chars, \n, or EOF */
printf("%d\n",i+x);
printf("%0.1lf\n",d+y);
printf("%s %s\n",s,z);
return 0;
}
(请验证每次调用scanf
-- 这由您来完成)
如果您有更多问题,请告诉我。
fputs
放在末尾,而不是像 fprintf
一样放在前面。 - David C. Rankinfgets/fputs
函数将流参数放在末尾,而任何处理变长参数的 fprintf
的人喜欢把它放到开头——现在我们只能接受这种方式了 :)
通常情况下,除非需要转换,否则使用 puts
(或者如果需要控制行末尾,则使用 fputs
)是正确的选择。(在这种情况下,我应该使用 fputs ("enter z: ", stdout);
而不是 printf
——但是一个好的编译器实际上会进行优化并替换为 fputs
)。 - David C. Rankinchar z[105]; scanf("%[^105\n]s",z);
来获取预期的结果,因为它将整个输入(包括换行符和下一行的内容,但不包括1、0或5)读入z
中直到EOF
。如果你能给出准确的输入输出并编辑后展示给我,我可以更详细地解释问题所在。 - David C. Rankinscanf("%lf",&y);
会将 stdin
中的 '\n'
留在未读取状态,然后你尝试读取 scanf("%[^105\n]",z);
,但由于你在 反向字符类 中排除了读取 '\n'
,所以什么也没读取到,接着你将 stdin
作为输入传递,而第一个字符是 '\n'
。"%[^105\n]"
的意思是:读取无限数量的字符,并且只有在遇到 1, 0, 5
或 '\n'
字符(或 EOF
)时才停止读取。 - David C. Rankin我通过在scanf("%lf\n", &y); 中使用 \n 解决了问题。
%[^105]
会占用所有字符(包括'\n'
),适用于输入中不包含1, 0或5
的情况,直到发现一个s
或到达输入结束。您似乎打算使用"%104s"
作为格式字符串。 - David C. Rankin"%104[^\n]"
。 - David C. Rankin