Question

I'm writing a program which is supposed to read two strings that can contain line breaks and various other characters. Therefore, I'm using EOF (Ctrl-Z or Ctrl-D) to end the string.

This works fine with the first variable, but with the second variable, however, this seems to be problematic as apparently something is stuck in the input buffer and the user doesn't get to type in anything.

I tried to clean the buffer with while (getchar() != '\n'); and several similar variations but nothing seems to help. All cleaning attempts have resulted in an infinite loop, and without cleaning, adding the second variable is impossible.

The characters for both of the variables are read in a loop like this: while((c = getchar()) != EOF), which would suggest it is EOF what I have stuck in my buffer. Or does it affect the behavior of the program in some other way? Is there something wrong with the logic I'm using?

I'm starting to get bit desperate after struggling with this for hours.

[edit: added code below]

[edit 2: clearerr() seems to make this EOF solution work after all.

It seems to run in its original form like I intended under Linux, I was trying it with Windows yesterday.]

code:

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

int main(void)
{
    int x = 0;
    int c;
    char a[100];
    char b[100];

    printf("Enter a: ");
    while((c = getchar()) != EOF)
    {
        a[x] = c;
        x++;
    }
    a[x] = '\0';
    x = 0;

    /*while (getchar() != '\n'); - the non-working loop*/

    printf("\nEnter b: ");
    while((c = getchar()) != EOF)
    {
        b[x] = c;
        x++;
    }
    b[x] = '\0';

    printf("\n\nResults:\na: %s\n", a);
    printf("b: %s\n", b);

    return(0);
}

[edit 3:]

Dynamic memory issue:

My program is also supposed to handle strings longer than 100 characters. Originally I intended to solve that by dynamic memory allocation, but when I had problems with the infinite loop described above and memory-related crashes I left it out and switched over to char[100].

I think what I tried was generally something like this:

while((c = getchar()) != EOF)
{
  a = malloc(sizeof(char));
  a[x] = c;
  x++;
}

Is that a possible (or sensible) way to do that? I'm trying to allocate more memory for every character that's being handled there. Individually. With code like that (this example contains probably syntax errors) I experienced crashes, so looks to me malloc might not be the right function here, or I'm trying it wrong. Supposing it's even possible.

Was it helpful?

Solution

After you received an EOF from the terminal, you will not receive any additional data. There is no way of un-EOF-ing the input - the end of the file is, well, the end.

So you should define that each variable is input on a separate line, and have users press enter instead of EOF. You still need to check whether you have received eof, because that means that the user actually typed EOF, and you won't see anything else - in this case, you need to break out of the loop and print an error message.

OTHER TIPS

EOF isn't a character - it's a special value that the input functions return to indicate a condition, that the "end of file" on that input stream has been reached. As Martin v. Löwis says, once that "end of file" condition occurs, it means that no more input will be available on that stream.

The confusion arises because:

  • Many terminal types recognize a special keystroke to signal "end of file" when the "file" is an interactive terminal (eg. Ctrl-Z or Ctrl-D); and
  • The EOF value is one of the values that can be returned by the getchar() family of functions.

You will need to use an actual character value to separate the inputs - the ASCII nul character '\0' might be a good choice, if that can't appear as a valid value within the inputs themselves.

I run the code on my linux box, here is the result:

Enter a: qwer
asdf<Ctrl-D><Ctrl-D>
Enter b: 123
456<Ctrl-D><Ctrl-D>

Results:
a: qwer
asdf
b: 123
456

Two Ctrl-D was needed because the terminal input buffer was not empty.

You could use the null character ('\0') to separate the variables. Various UNIX tools (e.g. find) are capable of separating their output items in this way, which would suggest that it's a fairly standard method.

Another advantage of this is that you can read the stream into a single buffer and then create an array of char*s to point to the individual strings, and each string will be correctly '\0'-terminated without you having to change anything in the buffer manually. This means less memory allocation overhead, which may make your program run noticeably faster depending on how many variables you're reading. Of course, this is only necessary if you need to hold all the variables in memory at the same time — if you're dealing with them one-at-a-time, you don't get this particular advantage.

What you are trying is fundamentally impossible with EOF.

Although it behaves like one in some ways, EOF is not a character in the stream but an environment-defined macro representing the end of the stream. I haven't seen your code, but I gather you're doing is something like this:

while ((c=getchar()) != EOF) {
    // do something
}
while ((c=getchar()) != EOF) {
    // do something else
}

When you type the EOF character the first time, to end the first string, the stream is irrevocably closed. That is, the status of the stream is that it is closed.

Thus, the contents of the second while loop are never run.

Rather than stopping reading input at EOF -- which isn't a character -- stop at ENTER.

while((c = getchar()) != '\n')
{
    if (c == EOF) /* oops, something wrong, input terminated too soon! */;
    a[x] = c;
    x++;
}

EOF is a signal that the input terminated. You're almost guaranteed that all inputs from the user end with '\n': that's the last key the user types!!!


Edit: you can still use Ctrl-D and clearerr() to reset the input stream.

#include <stdio.h>

int main(void) {
  char a[100], b[100];
  int c, k;

  printf("Enter a: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    a[k++] = c;
  }
  a[k] = 0;

  clearerr(stdin);

  printf("Enter b: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    b[k++] = c;
  }
  b[k] = 0;

  printf("a is [%s]; b is [%s]\n", a, b);
  return 0;
}
$ ./a.out
Enter a: two
lines (Ctrl+D right after the next ENTER)
Enter b: three
lines
now (ENTER + Ctrl+D)
a is [two
lines (Ctrl+D right after the next ENTER)
]; b is [three
lines
now (ENTER + Ctrl+D)
]
$

How do you enter null in the program?

You can implement the -print0 function using:

putchar(0);

This will print an ASCII nul character '\0' to sdtout.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top