如何在C语言中使用printf()和scanf()函数而不换行?

5
我想在一行中获取出生日期:
#include <stdio.h>

int main()
{
    int BirthYear,BirthMonth,BirthDay;
    printf("Please enter your birth date: ");
    scanf("%d",&BirthYear);
    printf("/");
    scanf("%d",&BirthMonth);
    printf("/");
    scanf("%d",&BirthDay);
    return 0;
}

这是我的输出结果:

Please enter your birth date: YYYY
/MM
/DD

但我想获得类似这样的东西:

Please enter your birth date: YYYY/MM/DD

在输出中,每次使用scanf()时不使用\n换行。

我使用VS Code进行集成开发环境。


1
那么为什么不写成“请以Y/m/d格式输入您的出生日期”,然后使用fgets、sscanf读取呢? - Antti Haapala -- Слава Україні
2
你为什么需要那个?换行符有什么问题吗? - klutt
3
换行符来自于每次输入时您需要按回车键,使用纯C语言无法实现您想要的操作。 - John Bode
2
@ParsaSaberi 是的,你理解得没错。在标准 C 中是没有这个方法的。 - Jabberwocky
换句话说:echo 2011 01 07 | ./a.out 不会生成不必要的换行符。 - William Pursell
显示剩余7条评论
5个回答

5

这里有一个使用ansi控制字符的解决方法。我不会像这样做,但只是为了展示它是可能的。

#define PREVLINE "\033[F"
#define MSG "Please enter your birth date: "

int main(void) {
    int BirthYear,BirthMonth,BirthDay;
    
    printf(MSG);
    scanf("%d",&BirthYear);
    printf(PREVLINE MSG "%d/", BirthYear);
    scanf("%d",&BirthMonth);
    printf(PREVLINE MSG "%d/%d/", BirthYear, BirthMonth);
    scanf("%d",&BirthDay);
    printf("You entered: %d/%d/%d\n", BirthYear, BirthMonth, BirthDay);
}

请注意,这不是可移植的。终端需要支持才能工作。据我所知,没有100%可移植的方法来实现这一点。
如果您想真正做这件事,那么建议查看ncurses库
注意:
始终检查scanf的返回值以检测错误。
注意2:
每个printf语句后添加fflush(stdout);可能是个好主意。
我今天实际上写了另一个关于ASCII控制字符的答案。 非常有趣:https://dev59.com/dr3pa4cB1Zd3GeqPneba#64549313

1
@AdrianMole比使用ASCII控制字符更臭?我不这么认为... :D - klutt
1
@ParsaSaberi 说实话,我不知道这是否有帮助。但是我真的、真的会尽量避免这样的事情。 :D - klutt
"\033[F" 不是 ASCII 控制字符,除了转义字符之外,它还是 ANSI 转义码 - chux - Reinstate Monica
@chux-ReinstateMonica 尴尬。谢谢。 - klutt

3
您可以在scanf函数的格式说明符中添加'/'字符,显式指定这三个输入数字之间应该用该字符分隔。
然后,您可以通过检查scanf函数返回的值(即成功扫描和分配的项目数)来确保用户提供了有效的输入;如果该值不为3,则您可能需要使用getchar()循环清除输入缓冲区中的任何“剩余”字符,直到找到换行符(或文件结尾)。
#include <stdio.h>

int main()
{
    int BirthYear, BirthMonth, BirthDay;
    int nIns = 0, ch;
    while (nIns != 3) {
        printf("Enter D.O.B. (as YYYY/MM/DD): ");
        nIns = scanf("%d/%d/%d", &BirthYear, &BirthMonth, &BirthDay);
        while ((ch = getchar() != '\n') && (ch != EOF))
            ; // Clear remaining in-buffer on error
    }
    printf("Entered data were: %d %d %d!\n", BirthYear, BirthMonth, BirthDay);
    return 0;
}

这不完全是OP想要的,但使用标准C可能是最接近它的方法。 - Jabberwocky
1
建议一个更宽容的"%d /%d /%d" - chux - Reinstate Monica

2

针对我的评论进行补充说明...

你遇到的问题是每次输入都需要按下Enter键,这会在终端屏幕上写入一个换行符。你无法避免这一点。

而且不幸的是,你不能用'\b'覆盖屏幕上的换行符;你只能回退到当前行的开头,而不能回退到前一行。

基本上,你无法用原始的C语言来实现你想要的功能 - 该语言只看到字节流,没有“屏幕”的概念。

有一些终端控制序列可以用来重新定位光标,以便在发送换行符后重新定位光标位置。我不知道这些对你是否有帮助。

除此之外,你需要使用像ncurses这样的库来解决问题。


1
#include <stdio.h>

int main()
{
    int BirthYear,BirthMonth,BirthDay;
    printf("Please enter your birth date: ");
    scanf("%d/%d/%d",&BirthYear,&BirthMonth,&BirthDay);
    return 0;
}

你可以从 scanf 中获取多个值,这些值可以由任意文本(在此情况下为 /s)分隔。

如果用户只输入 1977[Enter] 呢? - Jabberwocky
1977 将被视为出生年份的值。月份和日期的值将是垃圾值。 - Miraz

-2

你可以像下面这样使用fflush(3)(特别是在所有scanf(3)调用之前):

printf("Please enter your birth date: ");
fflush(NULL);

但你应该阅读这个C参考网站,像现代C这样的关于C编程的好书,还有你的C编译器(也许是GCC)和调试器(也许是GDB)的文档。

考虑在编译器中启用所有警告和调试信息。对于gcc,这意味着使用gcc -Wall -Wextra -g进行编译。

请注意scanf(3)可能会失败。

你的代码和问题肯定是操作系统特定的。

在Linux上,考虑使用ncurses(用于终端界面)或GTK(用于图形界面)。还可以阅读the tty demystified,然后阅读Advanced Linux Programmingsyscalls(2)以及termios(3)

您还可以考虑使用ANSI转义码,但请注意,在2020年应该在任何地方都使用UTF-8编码


1
即使您链接的页面也有这个:但不包括管道或终端,适用于 fflush() - Adrian Mole

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