如何在C语言中将两个字符串打印在同一行

4

我想输入带有空格的字符串,并将该字符串与另一个字符串一起打印在同一行上。

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;

%[^105]会占用所有字符(包括'\n'),适用于输入中不包含1, 0或5的情况,直到发现一个s或到达输入结束。您似乎打算使用"%104s"作为格式字符串。 - David C. Rankin
对不起,那是一个错误。 - Dasun Aroshana
应该是苹果 - Dasun Aroshana
1
更正一下,您打算使用 "%104[^\n]" - David C. Rankin
实际上我没有输入确切的104个字符。 - Dasun Aroshana
2个回答

2
你使用了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. Rankin
1
我确信这是在标准化之前的 C 开发者按照他们自己的意愿安排函数参数的时代遗留问题。fgets/fputs 函数将流参数放在末尾,而任何处理变长参数的 fprintf 的人喜欢把它放到开头——现在我们只能接受这种方式了 :) 通常情况下,除非需要转换,否则使用 puts(或者如果需要控制行末尾,则使用 fputs)是正确的选择。(在这种情况下,我应该使用 fputs ("enter z: ", stdout); 而不是 printf——但是一个好的编译器实际上会进行优化并替换为 fputs)。 - David C. Rankin
1
你可以使用char z[105]; scanf("%[^105\n]s",z);来获取预期的结果,因为它将整个输入(包括换行符和下一行的内容,但不包括1、0或5)读入z中直到EOF。如果你能给出准确的输入输出并编辑后展示给我,我可以更详细地解释问题所在。 - David C. Rankin
1
让我看看,然后我会添加到答案中。另外,请不要更改您的问题。而是在原始帖子下方添加新信息。这样可以确保原始评论和答案继续有意义。 - David C. Rankin
1
你的问题是 scanf("%lf",&y); 会将 stdin 中的 '\n' 留在未读取状态,然后你尝试读取 scanf("%[^105\n]",z);,但由于你在 反向字符类 中排除了读取 '\n',所以什么也没读取到,接着你将 stdin 作为输入传递,而第一个字符是 '\n'"%[^105\n]" 的意思是:读取无限数量的字符,并且只有在遇到 1, 0, 5'\n' 字符(或 EOF)时才停止读取。 - David C. Rankin
显示剩余12条评论

0

我通过在scanf("%lf\n", &y); 中使用 \n 解决了问题。


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