Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking the stdin buffer if it's empty

Tags:

c

I am trying to read a number character with character, but I don't know if the stdin buffer is empty or not.

My first solution whas to look for \n character in stdin buffer, but this is no good if I what to enter multiple numbers separated by " ".

How can I know if in stdin buffer I have characters or not?

I need to do it in C and to be portable.

like image 362
Tandura Avatar asked Nov 15 '14 17:11

Tandura


People also ask

How do I check if a buffer is empty?

If you want to check if the buffer holds no characters, you can use the strlen() function from string. h (make sure the buffer is \0-terminated after fread(). If you want to check if malloc failed, compare the pointer with NULL.

What is the buffer of Stdin?

Default Buffer sizes: if stdin/stdout are connected to a terminal then default size = 1024; else size = 4096.

Do you need to close Stdin?

However, calling fclose(stdin) will work on any POSIX compliant operating system as well as Windows operating systems, so you should hit pretty much anything in general use at the moment. As stated by the previous answer as well as my comment, there is no need to call close on the file handle.


3 Answers

There are several soutions:

poll or select with timeout of 0 - these would return immediately and result is either -1 with errno EAGAIN if no data available or number of descriptors with data (one, since you're checking only stdin).

ioctl is a swiss army knife of using descriptors. The request you need is I_NREAD:

if (ioctl(0, I_NREAD, &n) == 0 && n > 0)
    // we have exactly n bytes to read

However the correct solution is to read everything you got (using scanf) as a line, then process the result - and this works good enough with sscanf:

char buf[80]; // large enough
scanf("%79s", buf); // read everything we have in stdin
if (sscanf(buf, "%d", &number) == 1)
    // we have a number

... as long as you properly handle re-reading, strings that are longer than your buffer, and other real-life complications.

like image 168
aragaer Avatar answered Sep 24 '22 07:09

aragaer


For anyone who comes here from google – easy select solution to check stdin emptyness:

fd_set readfds;
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
fd_set savefds = readfds;

struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;

int chr;

int sel_rv = select(1, &readfds, NULL, NULL, &timeout);
if (sel_rv > 0) {
  puts("Input:");
  while ((chr = getchar()) != EOF) putchar(chr);
} else if (sel_rv == -1) {
  perror("select failed");
}

readfds = savefds;

Needs unistd.h, stdlib.h and stdio.h.

Explanation can be found here.

UPD: Thanks DrBeco for noticing that select returns -1 on error -- error handling was added.

Actually, select returns:

  • the number of ready descriptors that are contained in the descriptor sets
  • 0 if the time limit expires
  • -1 if an error occurred (errno would be set)
like image 45
stek29 Avatar answered Sep 25 '22 07:09

stek29


I inspired from this as referenced by @stek29's post on this page and prepared a simple example as follows:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    fd_set readfds;
    FD_ZERO(&readfds);

    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    char message[50];

    while(1)
    {
        FD_SET(STDIN_FILENO, &readfds);

        if (select(1, &readfds, NULL, NULL, &timeout))
        {
            scanf("%s", message); 
            printf("Message: %s\n", message);
        }

        printf("...\n");
        sleep(1);
    }

    return(0);
}
like image 40
ccerhan Avatar answered Sep 23 '22 07:09

ccerhan