【问题标题】:How to use printf() and scanf() in C without going to the next line?如何在 C 中使用 printf() 和 scanf() 而不转到下一行?
【发布时间】:2020-10-27 13:25:38
【问题描述】:

我想在一行中得到出生日期:

#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 用于 IDM。

【问题讨论】:

  • 那你为什么不写“请以 Y/m/d 格式输入你的出生日期”,然后用 fgets、sscanf 读取它?
  • 感谢您的帮助,但我需要在我写的时候得到日期。
  • 你为什么需要它?换行符有什么问题?
  • 换行来自你必须为每个输入按 Enter - 你不能用普通 C 做你想做的事。
  • @ParsaSaberi 是的,你知道了。在标准 C 中没有办法。

标签: c output scanf newline


【解决方案1】:

这是使用 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);
}

请注意,这是不可移植的。终端需要支持这一点才能工作。 AFAIK 没有 100% 可移植的方式来实现这一点。

如果你想真正做到这一点,那么我建议你看看the ncurses library

注意:

始终检查scanf 的返回值以检测错误。

注2:

在每个printf 语句之后添加fflush(stdout); 可能是个好主意。

我今天实际上写了另一个关于ascii控制字符的答案。可能会很有趣:https://stackoverflow.com/a/64549313/6699433

【讨论】:

  • @AdrianMole 比使用 ascii 控制字符更臭?不要这么认为......:D
  • @ParsaSaberi 不知道说实话是否有帮助。我真的,真的会尽量避免这样的事情。 :D
  • "\033[F" 不是 ascii 控制字符 - 除了转义,而是 ANSI escape code
  • @chux-ReinstateMonica 尴尬。谢谢。
【解决方案2】:

您可以通过在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 可以达到的最接近的。
  • 建议更宽容的"%d /%d /%d"
【解决方案3】:

扩展我的评论...

您遇到的问题是您必须为每个输入点击 Enter,这会在终端屏幕上写入一个换行符。这是你无法避免的。

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

你基本上不能用 vanilla C 做你想做的事 - 该语言只看到字节流,它没有“屏幕”的概念。

有一些terminal control sequences 可以在发送换行符后重新定位光标;我不知道这些对你有多好。

除此之外,您还需要使用像 ncurses 这样的库。

【讨论】:

    【解决方案4】:
    #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]呢?
    • 1977 将作为出生年份的值。而月份和日期的值将是垃圾值。
    【解决方案5】:

    您可以使用fflush(3)(尤其是在所有调用scanf(3) 之前),如

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

    但您应该阅读this C reference 网站、一本关于 C 编程的好书,例如 Modern C,以及您的 C 编译器(可能是 GCC)和调试器(可能是 GDB)的文档。

    考虑在编译器中启用所有警告和调试信息。使用gcc 表示使用gcc -Wall -Wextra -g 编译

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

    您的代码和问题肯定是 operating system 特定的。

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

    您也可以考虑使用ANSI escape codes,但请注意,在 2020 年,UTF-8 should be used everywhere

    【讨论】:

    • 即使您链接到的页面也有这个:但不是管道或终端 for fflush()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2016-05-20
    • 2015-08-02
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多