Search code examples
cstdin

Check if stdin pipe is empty in C


I am using user input to fill a 2d array. A user inputs numbers in one line and I then use nested loops to fill the array like so:

//User inputs: "1 2 3 4 5"

for(i = 0; i < r; i++){
    for(j = 0; j < c; j++){
            scanf("%d", &arr[i][j]);
    }
 }

However, the problem is if the user enters 5 ints when there is room for 6, it just waits for another input. How can I detect if there are insufficient numbers?

I have tried using this but it didn't work:

for(i = 0; i < r; i++){
    for(j = 0; j < c; j++){
        if (!feof(stdin)){
            scanf("%d", &arr[i][j]);
        }
        else{
            printf("insufficient datapoints\n");
        }
    }
 }

Solution

  • One way to accomplish your goal would involve using fgets() instead of scanf() to read in a line of input at a time. Then strtok() can be used to break the line of input into tokens, and strtol() can be used to parse the tokens into numbers. Compared with scanf(), it is much easier to use fgets to handle unstructured user input.

    The code below does this. If there are too many elements on an input row, too few elements, or if one of the elements is not a valid number, a message is printed and the row must be entered again.

    As each line is entered by the user, strtok() is used to break the line into tokens. The list of token delimiters is stored in delims[]. Note that tokens may be separated by spaces or tabs; the delimiters themselves are not part of the token, so including \r and \n ensures that these characters will not be part of the final token in a line.

    When a token is found, strtol() is used to convert it to an integer, if possible. After the call to strtol(), the pointer tail points to the first character in the token that was not part of a number; if tail points to the NUL terminator, then the entire string was parsed as a number, otherwise the input is considered bad and the row must be entered again.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define BUF_SIZE  1000
    
    int main(void)
    {
        size_t r = 3;
        size_t c = 5;
        size_t i, j;
        char buffer[BUF_SIZE];
        char *token;
        char *tail;
        const char delims[] = " \t\r\n";
        int arr[r][c];
        int temp_val;
    
        printf("Enter rows of %zu data elements:\n", c);
    
        for(i = 0; i < r; i++){
            j = 0;
    
            if (fgets(buffer, BUF_SIZE, stdin) == NULL) {
                perror("Error in fgets()");
                exit(EXIT_FAILURE);
            }
    
            token = strtok(buffer, delims);
            while (token != NULL) {
                temp_val = strtol(token, &tail, 10);
                if (*tail == '\0') {
                    arr[i][j] = temp_val;
                    ++j;
                } else {                // token not a valid number
                    j = 0;
                    break;
                }
    
                if (j > c) {            // too many input values
                    break;
                }
    
                token = strtok(NULL, delims);
            }
    
            if (j != c) {
                printf("insufficient datapoints\n");
                --i;                    // enter row again
            }
        }
    
        for (i = 0; i < r; i++) {
            for (j = 0; j < c; j++) {
                printf("%5d", arr[i][j]);
            }
            putchar('\n');
        }
    
        return 0;
    }
    

    Sample interaction:

    Enter rows of 5 data elements:
    1 2 3 4
    insufficient datapoints
    1 2 3 4 5 6
    insufficient datapoints
    1 x 2 3 4
    insufficient datapoints
    1 2 3 4 x
    insufficient datapoints
    1 2 3 4 5 x
    insufficient datapoints
    1 2x 3 4 5
    insufficient datapoints
    1 2 3 4 5
    2 3 4 5 6
     3  4  5    6 7
        1    2    3    4    5
        2    3    4    5    6
        3    4    5    6    7