为什么该程序的输出中有一个额外的“ *”?

时间:2018-07-21 10:05:57

标签: c io output getchar putchar

#include <stdio.h>

int main () 
{ 
  int c; 
  while ((c = getchar ()) != EOF) 
    { 
      putchar (c); 
      printf ("*"); 
    }


  return 0; 
}

当我运行该程序时,得到的输出为

qwerty                                          

q * w * e * r * t * y *
* 

#我不知道最后一个“ *”的打印方式。

这与putchar()的返回有关。那么putchar()函数实际上是如何返回的。我知道到达EOF后它会返回,因此在那种情况下,它不会打印任何内容,并且printf("*")将被执行。但问题是,为什么最后一个*在下一行打印。就像putchar()返回并将打印指针移到新行一样吗?

我克服了这个疑问的一种理论是,如果我在输入后不按'enter',将不会打印*。但这又再次引起了一个问题,即如何在不按Enter的情况下获得输出(在提供输入之后)?又为什么最后一个*会由于按下'enter'而出现在那?

6 个答案:

答案 0 :(得分:4)

当您输入“ qwerty”并按回车键时,新行字符\n将附加到输入中。因此,程序的输入为:

"qwerty\n"
       ^^

在循环处理时,最后一个(换行符)字符即已打印的\n字符实际上将光标移动到了下一行,并且在其后打印了最后一个星星。

要不随输入内容一起添加尾随换行符,可以在while循环条件中添加对换行符的检查:

while ((c = getchar ()) != EOF && c != '\n')

或者,您可以输入文件EOF的结尾字符,而不是在输入输入后按Enter键。对于EOF,在Unix上,按 Control + D ,在Windows上,按 Control + Z

答案 1 :(得分:1)

#include <stdio.h>
int main () 
{ 
  int c; 
  while ((c = getchar ()) != EOF) 
    { 
      putchar (c); 
      printf ("*"); 
    }
  return 0; 
}

输出:

QWERTY<Enter>

Enter also Taking as Character 
last '*' for <Enter> Character..

答案 2 :(得分:0)

您的代码将为每个打印的字母打印一个.html
打印换行符,请注意最后一行中如何单独使用最后一个/
最后一个from functools import wraps import re from django.contrib.flatpages.views import flatpage def replace_dot_html_with_slash(f): """Decorator that adapt the flatpage view to accept .html urls""" @wraps(f) def wrapper(request, url): # pretend the url has a trailing slash instead of `.html` return f(request, re.sub(r'\.html$', '/', url)) return wrapper adapted_flatpage = replace_dot_html_with_slash(flatpage) urlpatterns = [ ... re_path(r'^pages/(.*)$', adapted_flatpage) ] 用于*,当您使用返回键输入输入内容时,将读取该文本。

您可能希望已在该换行符处停止循环,即

*

答案 3 :(得分:0)

  

如何在不按Enter的情况下获得输出(输入后)?

您可以在“ qwerty”之后按 Ctrl-D ,而不是按 Enter

答案 4 :(得分:0)

欢迎来到该网站。 H.S.已经回答了您的主要问题。尽管如此,我想添加一些解释并直接解决您的其他问题之一。

端子属性

  

但是它再次提出了一个问题,即如何在不按Enter的情况下获得输出(输入后)?

您需要按Enter的原因是,默认情况下,您的终端处于“规范”模式。从tcsetattr的UNIX手册中:

  

常规模式下:

     

逐行提供输入。输入一个行定界符(NL,EOL,EOL2;或在行首的EOF)时,输入行可用。除EOF以外,该行            定界符包含在read(2)返回的缓冲区中。

请注意,“包含行定界符”这一事实也间接回答了您的问题

  

为什么按下“ enter”(输入)会出现最后一个*?

(按Enter键将插入NL行定界符-程序将其与其余字符一起放置在输入缓冲区中)。

根据您的平台,您可能可以禁用规范模式

禁用规范模式

注意:以下信息可能是特定于平台的。 tcsetattr函数 et。 al 是POSIX标准的一部分-但我不知道它们是否可以在Windows上运行。

例如,在Linux上,以下命令禁用规范模式,并指示程序在用户键入字符后立即读取输入。

#include <stdio.h>
#include <string.h>
#include <termios.h>

int main(void) {
    char c = '\0';
    struct termios orig_attr, new_attr;

    tcgetattr(fileno(stdin), &orig_attr);
    memcpy(&new_attr, &orig_attr, sizeof(struct termios));
    new_attr.c_lflag &= ~(ICANON | ECHO);  // Disable canonical mode
    tcsetattr(fileno(stdin), TCSANOW, &new_attr);

    while ((c = getchar()) != '\n') {
        printf("%c * ", c);
    }
    puts("");

    // Restore original terminal attributes
    tcsetattr(fileno(stdin), TCSANOW, &orig_attr);

    return 0;
}

注释:

  • 上面的代码还禁用了终端“ echo”(否则,您将看到每个字符打印两次)。
  • 您可能还希望设置new_attr.c_cc[VTIME]new_attr.c_cc[VMIN]以便更好地控制读取缓冲区。 (有关详细信息,请参见man page。)
  • 最终-根据您的最终目标-也许仅使用fgetsgetline会更容易?

答案 5 :(得分:0)

  

这与putchar()的返回有关。那么putchar()函数实际上是如何返回的。我知道到达EOF后它会返回,因此在那种情况下,它不会打印任何内容,并且printf("*")将被执行。

这很混乱,您在这里完全走错了路。 putchar()仅输出一个字符,并在完成输出后立即返回。实际上,您可以编写如下相同的代码:

while ((c = getchar()) != EOF) 
{ 
   putchar(c); 
   putchar('*'); 
}

这意味着只要getchar()成功(文件末尾),就输出收到的字符,然后立即输出一个星号。

实际上,按下键qwerty时应该看到的是这样的东西:

qq*ww*ee*rr*tt*yy*

这是假设您的终端执行“本地回显”,这意味着它会显示您键入的任何内容。

您在按Enter键(或EOF的平台相关控制键,例如* nix系统Ctrl-D上)之前看不到任何输出的原因仅仅是stdin(您在C语言中的输入流),默认情况下为行缓冲。这意味着在您的循环中,getchar()永远不会返回,除非您有整行输入或达到EOF。

getchar()返回后,您的循环将运行。如果按回车键,则输入缓冲区中将有换行符,并且getchar()也将读取该换行符,因此循环中的putchar()也会输出该字符,后跟一个星号。 / p>

但是请注意,可以更改缓冲模式...如果在stdin上禁用缓冲,则可能会看到我上面描述的内容。


一种可靠地实现您想要的可靠方法的方法是,在代码中读取整行,并遍历所读取的字符。例如,如下所示:

char buffer[1024];
if (fgets(buffer, 1024, stdin))
{
    for (char *c = buffer; *c; ++c)
    {
        putchar(*c);
        if (*c != '\n') putchar('*');
    }
}

使用这样的代码,您将拥有自己的缓冲区,而不依赖于输入流的缓冲模式。