输入间隔,直到CTRL + D.

时间:2017-11-09 12:53:30

标签: c scanf stdin eof feof

我的间隔写为<a;b>我用scanf("<%d;%d>", &a, &b);阅读,但问题是我需要使用我的函数多次这样的间隔,直到我按CTRL + Z或{{1}在Unix上。

到目前为止,我尝试过这样的事情,但它没有用。

CTRL + D

2 个答案:

答案 0 :(得分:2)

你的问题并不简洁。这样:

int main( void ) { 
    int a=0, b=0;

    printf("Intervaly: \n");
    while(scanf("<%d;%d>",&a,&b) == 2){ 
        printf("Ruznych kvadru: %d\n", capacity(a, b));
    }   
    return 0;  
}

实际上你想要的是,用<%d;%d>的长行或逐行 - 两者都可以。你的问题,隐藏在评论中,EOF不会立即终止 - 而是你需要两次CTRL-D来阻止它。原因也在于评论中。

按照您的方式扫描后,您将在输入流中留下\n(因为您必须按回车键才能发送输入而不会终止)。有两种方法可以解决这个问题 - 将其添加到scanf中,这不太灵活,有一些问题,或者在while中清除它:

while(scanf("<%d;%d>",&a,&b) == 2){ 
    printf("Ruznych kvadru: %d\n", capacity(a, b));
    getchar();
}   

您现在需要按CTRL-D一次。如果您尝试从文件输入重定向,您会看到此问题也不存在。为什么会这样?您在输入流中有\n。你按下EOF,所以scanf得到一个换行符并忽略它 - 等待新的输入。只有现在新的EOF才能杀死scanf

我建议在此网站上搜索scanf个问题,看看为什么不使用它,以及其他不错的选择。

<强>附录

评论中给出的一个更优雅的解决方案,由@BluePixy向我指出并由@DavidBowling向我指出是用于scanf

scanf("<%d;%d>%*c", &a, &b);

这将自然地吞噬额外的角色,包括新的空间,而不需要额外的getchar。我认为这是scanf用法的最优雅解决方案。

更多

按照OP的评论和David的再次评论(再次感谢!)以便占用0或更多空格,您只需要格式化空格指令:

scanf("< %d ; %d >%*c", &a, &b);

现在可以(或不可以)在每个整数周围添加空格。

答案 1 :(得分:0)

关于循环条件,while( scanf(" <%d;%d>", &a, &b)) == 2 ) 应该足够了,但您可能还应该跟踪错误诊断的数量:

int nread=2;
while( (nread=scanf(" <%d;%d>", &a, &b)) == 2){ //...

Ctrl-Z部分更复杂。 Ctrl-Z导致规范设置终端驱动程序以生成SIGTSTP信号。

此信号的默认配置是将进程置于睡眠状态,这意味着您 不能简单地使用ISO C&#39; signal函数来注册信号处理程序,因为 如果这些信号处理程序可能会无意中恢复原始信号处理 收到多个信号实例,这会使你的过程停止。

您需要访问POSIX并使用sigaction

然后,sigaction处理程序可以设置一个易失性标志,这将是一个终止循环的信号。 由于在scanf内部接收信号会导致scanf失败 EINTR,对此进行强大的错误处理有点令人费解:

#include <stdio.h>
#include <signal.h>
#include <errno.h>

static int volatile ctrl_z;
void SignalHandler( int Signum )
{
    (void)Signum;
    ctrl_z=1;
}

int main( void ) {
    // ctrl + z
    sigaction(SIGTSTP, &(struct sigaction){ .sa_handler=SignalHandler }, 0);

    int a=0, b=0, nread=2;

    /*...*/
    while( (nread=scanf(" <%d;%d>", &a, &b)) == 2){

       /*...*/

        if(ctrl_z)
            return 0;
        errno=0; /*so we know if scanf failed because of the signal*/
    }
    if ( (!ferror(stdin) && feof(stdin)) ||
           (ferror(stdin) && errno==EINTR && ctrl_z) )
        return 0;
    return 1;
}