2
#include <stdio.h>

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


  return 0; 
}

when I run this program, the output I get is as

qwerty                                          

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

#I'm not getting how this last "*" is getting printed.

It has something to do with the return of putchar(). So how does putchar() function actually returns. I know that it returns after EOF is reached, so in that case, it won't print anything and printf("*") will get executed. But the thing is, why the last * is getting printed in the next line. Is it like putchar() returns and shift the printing pointer to new line?

One theory I get over this doubt is that, if I don't press 'enter' after giving input, * will not be printed. But it again created a question as of how do I get output (after giving the input), without pressing enter? And why is it like that the last * is there due to pressing 'enter'?

Jens
  • 69,818
  • 15
  • 125
  • 179
aambazinga
  • 53
  • 7

6 Answers6

4

When you give input "qwerty" and press enter key, the new line character \n appended to the input. So, the input to program would be:

"qwerty\n"
       ^^

When loop process the last (newline) character i.e. the \n character printed which actually moves the cursor to next line and the last star is getting printed after it.

To not to get the trailing new line character along with input, you can add check for new line character in while loop condition:

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

Alternatively, you can give end of file EOF character instead of pressing enter key after entering input. For EOF, on Unix press Control+D and on Windows press Control+Z.

H.S.
  • 11,654
  • 2
  • 15
  • 32
  • but when i declared variable, say n and initialized it with 0. now, i'm replacing the extra condition you have given, with the condition 'n<10', and incrementing 'n' inside the while loop. then putchar() and the printf() statement inside while loop is not working. how it is so? – aambazinga Jul 21 '18 at 10:28
  • You would have to demonstrate that problem with a [mcve] as part of a new separate question. Please do not change this one away from the original question. There are already answers here, some of them upvoted. – Yunnosch Jul 21 '18 at 10:29
  • @aambazinga I don't see any reason for which it wont work. It should work. Show the while loop condition. – H.S. Jul 21 '18 at 10:31
  • @H.S. the reason is the same this construct "works" at all: line buffering on `stdin`. I assume he doesn't hit enter and expects some output appears after 10 characters. Won't happen. –  Jul 21 '18 at 10:36
  • @H.S. ctrl+d is working.. but the putchar is executing from the same line as on the input is given. ctrl+z is working differently.... (1)- it is not putting putting all characters, except the last *. (2)-it is skipping one line after the input and then * is printed. – aambazinga Jul 21 '18 at 10:52
  • @aambazinga On which OS you are compiling and running your program? – H.S. Jul 21 '18 at 10:57
  • @H.S. its an online gdb compiler. – aambazinga Jul 21 '18 at 11:03
  • @aambazinga gdb is GNU debugger and not a compiler. I believe you mean to say gcc, which is a standard compiler for most Unix-like operating systems. On Unix you should use ctrl+d for EOF. The EOF is non printable ASCII character. Hence you will not see it in the terminal but as soon as you press ctrl+d, unlike enter key press which moves the cursor to next line, the program process the input and print output on the same line as on the input is given. – H.S. Jul 21 '18 at 11:05
1
#include <stdio.h>
int main () 
{ 
  int c; 
  while ((c = getchar ()) != EOF) 
    { 
      putchar (c); 
      printf ("*"); 
    }
  return 0; 
}

OUTPUT:

QWERTY<Enter>

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

Your code will print one * for each other letter printed.
A newline is printed, note how the last * is alone in the last line.
The last * is for the \n, which is read when you enter the input with the return key.

You might want to stop the loop already at that newline, i.e.

while (((c = getchar ()) != EOF) && (c!='\n'))
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
0

how do I get output( after giving the input), without pressing enter?

You can press Ctrl-D after "qwerty" instead of pressing Enter.

  • 4
    Without further explanation, this should be a comment. Note that this also depends on the platform. –  Jul 21 '18 at 10:20
  • @FelixPalmen It is a partial answer, answering a part of the question which actually all the other partial answers did not answer. Isn't it? – Yunnosch Jul 21 '18 at 10:24
  • 1
    @Yunnosch it could be, but then it's missing explanation. I'd be happy with it if it wasn't for the fact that Ctrl-D isn't a universal standard for giving EOF from the keyboard :o -- AFAIK, this already doesn't work on windows, Ctrl-Z should instead. –  Jul 21 '18 at 10:26
  • @FelixPalmen That is true. But it stays an answer, not a comment. Consider it a bad answer, with assumptions, but it is an answer. – Yunnosch Jul 21 '18 at 10:27
  • @Yunnosch a matter of definition ... Yes, I wouldn't flag this NAA, but if it's an answer, it's partial **and** partially wrong and I'd say it's common practice to give this kind of little hints as comments instead. –  Jul 21 '18 at 10:30
  • @yahor zabalotski but i'm not getting that output in the next line. what if i want answer in the next line? – aambazinga Jul 21 '18 at 10:30
  • @aambazinga the approach is flawed anyways. What do you think why you can type a whole line before any output appears? Just because `stdin` is line buffered, something that can be disabled as well, then you'll get an asterisk as soon as you hit a single key. A sane approach here would be to read a whole line (e.g. with `fgets()`) and then iterate over the characters, outputting them with asterisks in between. –  Jul 21 '18 at 10:34
  • I made the OS assumption. Thanks for reminder me about it! Possibly, https://stackoverflow.com/questions/11968558/how-to-enter-the-value-of-eof-in-the-terminal answer clarified it. – yzabalotski Jul 21 '18 at 10:34
  • @yahor zabalotski ctrl+D is for making the while loop false. i'm saying this because, after pressing ctrl+d, while loop condition becomes false and output is printed. but after that while loop is not taking any input(as int the case of enter, where we can iterate the loop for as per out need) – aambazinga Jul 21 '18 at 10:43
  • @aambazinga "*after pressing ctrl+d, while loop condition becomes false and output is printed.*" <- are you sure you know how `while` works? In your code, output is printed as long as the condition is **true**. –  Jul 21 '18 at 10:45
  • On Unix terminals `eof` can be changed from ctrl+d to something else using `stty` (you could make it ctrl+z on Unix if you reassign `susp` as well). Confuses the heck out of people when you put it into a startup file like `.bashrc`. So maybe the caveat: "ctrl+d by default". – cdarke Jul 21 '18 at 15:34
0

Welcome to the site. H.S. has answered your main question. Nonetheless I wanted to add a little more explanation and address one of your other questions directly.

Terminal attributes

But it again created a question as of how do I get output (after giving the input), without pressing enter?

The reason you need to press enter is that your terminal is in 'canonical' mode by default. From the UNIX manual for tcsetattr:

In canonical mode:

Input is made available line by line. An input line is available when one of the line delimiters is typed (NL, EOL, EOL2; or EOF at the start of line). Except in the case of EOF, the line delimiter is included in the buffer returned by read(2).

Note the fact that 'the line delimiter is included' also indirectly answers your question

And why is it like that the last * is there due to pressing 'enter'?

(as pressing enter inserts the NL line delimiter - which the program just places in the input buffer along with the rest of the characters).

Depending on your platform, you may be able to disable canonical mode.

Disabling canonical mode

NOTE: The information below may be platform-specific. The tcsetattr functions et. al are part of the POSIX standard - but I don't know if they will work on Windows.

On Linux, for example, the following disables canonical mode and instructs the program to read input as soon as the user types a character.

#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;
}

Notes:

  • The above code also disables terminal 'echo' (Otherwise you would see each of the characters printed twice).
  • You may also want to set new_attr.c_cc[VTIME] and new_attr.c_cc[VMIN] for finer control of the read buffer. (See man page for details.)
  • Ultimately - depending on your ultimate goal - maybe it is easier to just use fgets or getline?
David Collins
  • 2,852
  • 9
  • 13
  • it's really an interesting thing.. i've tried this out and the input is not getting buffered, direct output is getting printed. – aambazinga Jul 21 '18 at 11:56
  • i've one question here, so if we disable canonical mode, then context switching must be disabled in the processor.. because if it is not so, then some input must get lost due to lack of buffer.. am i right? – aambazinga Jul 21 '18 at 11:58
  • No. And not trying to disrespect this answer, but I'd suggest you stay within what C defines for now. Pulling OS-specific stuff in will only add to the confusion. –  Jul 21 '18 at 12:00
  • @aambazinga: I'm not 100% sure what you mean by "context switching ... in the processor". Do you mean in the operating system _kernel_ (for switching processes)? If so, then no - you certainly don't need such radical measures. I can not think of a scenario where input might "get lost" (although perhaps other readers might know of one). – David Collins Jul 21 '18 at 12:37
  • @aambazinga: This technique is not uncommon on Linux/UNIX operating systems. Nonetheless, if you need something that is operating system agnostic, maybe go with a simpler option such as `fgets` (as Felix Palmen suggested). In any case ... The above hopefully helps you to understand the issue at least. – David Collins Jul 21 '18 at 12:44
0

It has something to do with the return of putchar(). So how does putchar() function actually returns. I know that it returns after EOF is reached, so in that case, it won't print anything and printf("*") will get executed.

This is very confused and you're completely on the wrong path here. putchar() just outputs a single character and returns as soon as this output is done. In fact, you could write the same code like this:

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

This means as long as getchar() is successful (no end of file), output the character you received and then immediately output an asterisk.

In fact, what you should expect to see when hitting the keys qwerty is something like this:

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

This is assuming your terminal does "local echo", which means it shows anything you type.

The reason you don't see any output before hitting enter (or the platform-dependent control key for EOF, e.g. on *nix systems Ctrl-D) is simply that stdin, your input stream in C, is by default line buffered. This means that in your loop above, getchar() won't ever return unless you have a whole line of input or reach EOF.

As soon as getchar() returns, your loop will run. If you pressed enter, there will be a newline character in the input buffer and getchar() will read this as well, so it will also be output by the putchar() inside your loop, followed by an asterisk.

Note however that buffering modes can be changed ... if you disable buffering on stdin, you will probably see what I described above.


A sane way to implement what you want reliably is to read a whole line in your code and iterate over the characters you read. This could look for example like the following:

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

With code like this, you have your own buffer and don't depend on the buffering mode of your input stream.

  • okay, so you are saying that whenever a new character is encountered, putchar() is called. if i get it right, then what is there to check for occurence of a character? – aambazinga Jul 21 '18 at 12:22
  • well, `getchar()`? As I said, your input stream is line buffered, so `getchar()` waits for input until a line is complete.... –  Jul 21 '18 at 12:26