【问题标题】:Why does getchar work like a buffer instead of working as expected in real-time为什么 getchar 像缓冲区一样工作,而不是像预期的那样实时工作
【发布时间】:2015-10-12 06:10:41
【问题描述】:

这是我关于 stackoverflow 的第一个问题。如果我没有正确搜索,请原谅我,但我似乎没有找到对此的解释。只是尝试从 Bjourne Stroustroup 的论文中举一个例子。添加我的位以查看数组在我键入文本时重新调整大小。

但它似乎并没有那样工作! getchar() 只是等到我输入完所有字符,然后它将执行循环。按照逻辑,它实际上并没有进入循环,获取一个角色,执行它的动作然后迭代。我想知道这是特定于实现还是打算这样?

我在 Ubuntu 14.04 LTS 上使用带有 gcc 4.8.2 的代码块。如果重要的话,源代码在 cpp 文件中。

while(true)
{
    int c = getchar();
    if(c=='\n' || c==EOF)
    {
        text[i] = 0;
        break;
    }
    text[i] = c;

    if(i == maxsize-1)
    {
        maxsize = maxsize+maxsize;
        text = (char*)realloc(text,maxsize);
        if(text == 0) exit(1);
        cout << "\n Increasing array size to " << maxsize << endl;
    }

    i++;
}

输出如下:

数组大小现在是:10 请输入一些文本:这是一些示例文本。我希望看到内存被重新分配在这里,但显然它不是这样工作的!

将数组大小增加到 20

将数组大小增加到 40

将数组大小增加到 80

将数组大小增加到 160

您已输入:这是一些示例文本。我希望看到内存被重新分配在这里,但显然它不是这样工作的!

数组大小现在是:160

【问题讨论】:

    标签: c++ ubuntu terminal getchar


    【解决方案1】:

    这与getchar 直接无关。 “问题”是底层终端,它将缓冲您的输入。按下回车后,输入将发送到程序。在 Linux 中(不知道在 Windows 中有没有办法)你可以通过调用来解决这个问题

    /bin/stty raw
    

    在终端中或通过调用

    system ("/bin/stty raw");
    

    在您的程序中。这将导致 getchar 立即将输入字符返回给您。

    不要忘记通过调用重置tty 行为

    /bin/stty cooked
    

    完成后!

    这是一个示例(适用于 Linux):

    #include <stdio.h>
    #include <stdlib.h>
    
    using namespace std;
    
    int main() {
        system ("/bin/stty raw");
        char c = getchar();
        system ("/bin/stty cooked");
        return 0;
    }
    

    还可以看看这个 SO 帖子:How to avoid press enter with any getchar()

    另外,正如 cmets 中所建议的,请看这里:http://linux.die.net/man/3/termios,尤其是命令 tcsetattr,它应该可以跨平台工作。

    【讨论】:

    • 你应该引用termios手册页和tcsetattr函数来帮助配置终端IO。
    • 非常好的建议。不幸的是我不熟悉termios。如果是,您可以将其发布为答案。我已将您的建议简要添加到答案中
    • 我尝试在程序的开头和结尾添加 sn-ps。有用!但是, (c=='\n') 部分不起作用。它永远卡在while循环中。我想这是我浏览 SO Post 链接时的预期行为。有什么方法可以检查输入的字符是否为换行符?
    • 滚动浏览链接的 SO 帖子。在其中一个子句中添加 (c=='\r') 以包含回车符。现在它按预期工作。谢谢你这么快的回答!花了几分钟才解决!
    【解决方案2】:

    实际上,tcsetattr 不适用于 Windows(这就是本网站通常所说的“跨平台”)。然而,这个问题是针对 Linux 的,所以“跨平台”是一个有争议的问题。

    默认情况下,标准输入、输出和错误流设置为

    • 行缓冲(输入)
    • 块缓冲(输出)
    • 行缓冲(错误)

    您可以使用setbuf 更改那个,但当然不会解决问题(答案需要单字符输入)。 POSIX 终端 I/O (termios) 允许您通过系统调用更改使用 stty 显示的任何标志。通常,您可以直接从脚本调用 stty,很少从 C 程序调用。

    阅读单个字符是一个常见问题,例如,

    您也可以使用 ncurses:filter 函数对于处理命令行(而不是全屏应用程序)的程序很有用。 ncurses-examples (filter.c) 中有一个示例程序可以做到这一点。

    【讨论】:

    • 这非常有用。我确实浏览了 tcsetattr 的文档,我想它是跨平台的,这意味着我认为它应该适用于所有版本的 linux。除非使用一些外部库,否则看起来没有真正的跨平台解决方案?或者我们可以有多个代码块来根据程序运行的操作系统来控制这种行为,并使用预处理器指令来控制根据程序运行的实现调用什么?正确的做法是什么?
    • 有多种方法,例如,使用更高级别的接口来隐藏实现细节。具有大量 ifdef 的程序很难维护(将完整的实现放在单独的源文件中,但使用通用头文件来强制接口一致性是解决该问题的一种方法)。
    猜你喜欢
    • 2017-06-09
    • 2014-05-16
    • 1970-01-01
    • 2021-09-07
    • 2012-06-13
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 2014-10-14
    相关资源
    最近更新 更多