Yi-Hsuan Huang
Yi-Hsuan Huang

Reputation: 131

How to read multiple lines of string from stdin in C?

I am a novice in C programming. Suppose I want to read multiple lines of string from stdin. How can I keep reading until a line only containing EOL?

example of input

1+2\n
1+2+3\n
1+2+3+4\n
\n (stop at this line)

It seems that when I hit enter(EOL) directly, scanf won't execute until something other than just EOL has been entered. How can I solve that problem?

I'll be really grateful if someone can help me with this. Thank you.

Upvotes: 1

Views: 1864

Answers (3)

William Pursell
William Pursell

Reputation: 212248

If you want to learn C, you should avoid scanf. The only use cases where scanf actually makes sense are in problems for which C is the wrong language. Time spent learning the foibles of scanf is not well spent, and it doesn't really teach you much about C. For something like this, just read one character at a time and stop when you see two consecutive newlines. Something like:

#include <stdio.h>

int
main(void)
{
        char buf[1024];
        int c;

        char *s = buf;

        while( (c = fgetc(stdin)) != EOF && s < buf + sizeof buf - 1 ){
                if( c == '\n' && s > buf && s[-1] == '\n' ){
                        ungetc(c, stdin);
                        break;
                }
                *s++ = c;
        }
        *s = '\0';
        printf("string entered: %s", buf);
        return 0;
}

Upvotes: 3

Jeff Holt
Jeff Holt

Reputation: 3190

If you need to read one character at a time then you can with either getchar or fgetc depending upon whether or not you're reading from stdin or some other stream.

But you said you were reading strings, so I'm assuming fgets is more appropriate.

There are primarily two considerations:

  1. maximum line length
  2. whether or not to handle Windows versus non-Windows line endings

Even if you are a beginner--and I won't go into #2 here--you should know you can defend against it. I will at least say that if you compile on one platform and read from stdin from a redirected file from another platform, then you might have to write a defense.

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

int main (int argc, char *argv[]) {
    char buf[32];  // relatively small buf makes testing easier
    int lineContinuation = 0;
    // If no characters are read, then fgets returns NULL.
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
       int l = strlen(buf); // No newline in buf if line len + newline exceeds sizeof(buf)
       if (buf[l-1] == '\n') {
          if (l == 1 && !lineContinuation) {
             break; // errno should indicate no error.
          }
          printf("send line ending (len=%d) to the parser\n", l);
          lineContinuation = 0;
       } else {
          lineContinuation = 1;
          printf("send line part (len=%d) to the parser\n", l);
       }
    }
    printf("check errno (%d) if you must handle unexpected end of input use cases\n", errno);
}

Upvotes: 0

chux
chux

Reputation: 153468

to read multiple lines of string from stdin. How can I keep reading until a line only containing EOL?

Keep track of when reading the beginning of the line. If a '\n' is read at the beginning, stop

getchar() approach:

bool beginning = true;
int ch;
while ((ch = getchar()) != EOF) {
  if (beginning) {
    if (ch == '\n') break;
  }
  // Do what ever you want with `ch` 
  beginning = ch == '\n';  
}

fgets() approach - needs more code to handle lines longer than N

#define N 1024
char buf[N+1];
while (fgets(buf, sizeof buf, stdin) && buf[0] != '\n') {
  ; // Do something with buf
}

Upvotes: 0

Related Questions