Search code examples
cscanf

Problems with scanf input stream


I am trying to do a postfix evaluation using stack. The output is supposed to be in a format 2,3,4,+,-,# with # signifying the end of expression. The problem is negative numbers are allowed i.e 2,3,-10,+,-,# is also a valid input. I need a method to separate the numbers from the characters.

int main() {
    int num;
    char ch;
    int ret;

    printf("Enter integers or characters separated by commas (e.g., 12,a,34,#):\n");

    while (1) {

        scanf(" ,");

        ret = scanf("%d", &num);

        if (ret == 1) {
            printf("Input is an Integer: %d\n", num);
            if (ret == -1)
                break;
        } else {
            if (scanf(" %c", &ch) == 1) {
                // Print an error message for non-integer input
                //ch = getchar();
                printf("Input is a Character: '%c' (invalid integer)\n", ch);
            } else {
                printf("End of input\n");
                break;
            }
        }
    }

    return 0;
}

The problem I am facing is, if the input is 1,2,3,a,b,-1 -> it correctly identifies the numbers as numbers and a,b as characters. But if I give 1,2,3,+,-,#,-1 as input, it somehow takes , instead of + and - while recognizes #. What can I try next?


Solution

  • The issue is that the characters + and - may be part of a number, such as in -1, so in the case of these characters, when scanf("%d", &num) fails to read an integer decimal number it will consume the + or - characters from the input, therefore the following scanf(" %c", &ch) ends up reading the separating comma as the input character.

    One solution to this would be to first read each entry between commas , as a string and store it in a char array. And to do that you can use the specifier " %[^,\n]" in the scanf function, which is the string specifier to discard leading blank characters, and store anything that is not a comma , or a new line character \n in the char array.

    And then you can use the sscanf function to process the string in the array, to find out if it is a valid int or not.

    Like this:

    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char string[100] = "";
        char ch = '\0';
        int num = 0;
        int ret = 0;
        
        while (scanf(" %99[^,\n]", string) == 1) {
            if (sscanf(string, "%d", &num) == 1) {
                printf("Input is an Integer: %d\n", num);
            }
            else {
                printf("Input is Not an Integer: '%s'\n", string);
                if (strcmp(string, "#") == 0) break;
            }
            ret = scanf("%c", &ch);
            if (ret != 1 || ch == '\n') break;
        }
        printf("End of input\n");
        
        return 0;
    }
    

    Or, as suggested by @chux-ReinstateMonica, you could use strtol to process the string, so that you can also handle out of range input values, like this:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <limits.h>
    
    int main() {
        char string[100] = "";
        char ch = '\0';
        char *end = NULL;
        long num = 0;
        int ret = 0;
        
        while (scanf(" %99[^,\n]", string) == 1) {
            errno = 0;
            num = strtol(string, &end, 10);
            if (string < end && *end == '\0' && errno != ERANGE){
                printf("Input is an Integer: %ld\n", num);
            }
            else if (errno == ERANGE) {
                printf("Input is Out of Range: '%s' (Ranges from %ld to %ld)\n", string, LONG_MIN, LONG_MAX);
                errno = 0;
            }
            else {
                printf("Input is Not an Integer: '%s'\n", string);
                if (strcmp(string, "#") == 0) break;
            }
            ret = scanf("%c", &ch);
            if (ret != 1 || ch == '\n') break;
        }
        printf("End of input\n");
    
        return 0;
    }