0

I have been searching for a few hours and can't seem to find the answer I'm after. My apologies if this ends up being a duplicate.

Now my program asks the user for 2 integers. Example

Prompt: 15 24

I after going threw other questions so people have mentioned scanf and fgets. But each of those were for entering one number at a time, whereas I want both from the one input.

My other issue is error checking. Whether they actually entered an integer or something invalid. Example:

Prompt: Hello World
Prompt: foo 5
Prompt: 4 bar
Prompt: foo
Prompt: 

Code:

int get_input(int* x, int* y) {

    char* p, buf[LINE_MAX];
    int n1, n2;

    printf("Prompt: ");
    fgets(buf, sizeof(buf), stdin);
    n1 = strtol(buf, &p, 10);
    if (p == buf || *p != '\n') {
        return 0;
    }

    n2 = strtol(buf, &p, 10);
    if (p == buf || *p != '\n') {
        return 0;
    }

    *x = n1;
    *y = n2;

    return 1;
}

int main(int argc, char** argv) {
    int x, y;
    if (get_input(&x, &y)) {
        printf("Worked: %d %d\n", x, t);
    } else {
        printf("Invalid\n");
    }
    return 0;
}

Some of the error checking is missing, but just really stuck on getting the second value if there is one. Also checking if there are more than 2 values. Much help would be appreciated.

References that got me this far:

SO Question

strtol doc

Community
  • 1
  • 1
Steven Summers
  • 5,079
  • 2
  • 20
  • 31
  • 4
    Hint: `n2 = strtol(p, &p, 10)`. – zwol Aug 17 '16 at 11:57
  • 1
    DV for not even reading the man-page of `scanf`. – too honest for this site Aug 17 '16 at 12:04
  • @Olaf I did attempt `scanf` but I could only get it working for valid inputs. Any invalid input as mentioned gives me a strange output and I'm rather confused. Plus the SO question mentioned says to not use `scanf` so I when for `fgets` @zwol Made the change but can't get it to work when trying something valid. Could you please elaborate? – Steven Summers Aug 17 '16 at 12:10
  • Have you tried using strtok instead of strtol? With strtok you can extract first two entries, no matter how long the input is. After that you can convert them to integer with atoi(). You can also check if the character after the second strtok is newline "\n" and if it is, it's valid input. If not, it's invalid. – Mirakurun Aug 17 '16 at 12:20
  • Don't even bother trying to use `scanf`, it's broken as specified. As you have discovered, one of the problems with it is that invalid input is effectively impossible to handle robustly. – zwol Aug 17 '16 at 12:20
  • If you want more actual help from me, I'm going to need you to elaborate on "made the change but can't get it to work when trying something valid". List the exact inputs you tried, what happened for each, and what you thought should have happened for each. (Then reread the `strtol` manpage and possibly light will dawn.) – zwol Aug 17 '16 at 12:21
  • Also, protip: your pointer p is uninitialized and it points nowhere. – Mirakurun Aug 17 '16 at 12:22
  • You can also use isdigit() for checking if your characters are only digits. – Mirakurun Aug 17 '16 at 12:26
  • Many thanks @zwol seems I messed up the logic for the if statements. – Steven Summers Aug 17 '16 at 12:59

2 Answers2

0

What I ended up coming up with, also works for a variable number of values.

bool get_input(int count, int* ref_values) {
    char buffer[MAX_LINE_LENGTH];
    char* input = fgets(buffer, sizeof(buffer), stdin);
    char* end;
    int i = 0;

    if (feof(stdin)) {
        clearerr(stdin);
        return false;
    }

    for (long val = strtol(input, &end, 10); input != end && i < count; val = strtol(input, &end, 10), i++) {
        input = end;
        if (errno == ERANGE) {
            errno = 0;
            return false;
        }

        if (val <= INT_MIN || val >= INT_MAX) {
            return false;
        }
        ref_values[i] = val;
    }
    return i == count && strlen(input) == 1;
}

int main(int argc, char** argv) {
    while (true) {
        int values[2] = {};
        printf("Enter 2 numbers: ");
        if (get_input(2, values)) {
            printf("You entered %d %d %d\n", values[0], values[1]);
        } else {
            printf("Invalid\n");
        }
    }
    return 0;
}
Steven Summers
  • 5,079
  • 2
  • 20
  • 31
-1

Once you have the input in a string you could use sscanf normally, but with a trick parameter in the end:

int get_input(int* x, int* y) {

    char* p, buf[LINE_MAX], buf2[LINE_MAX];
    int n1, n2;

    printf("Prompt: ");
    fgets(buf, sizeof(buf), stdin);
    if  (sscanf(buf, "%d%d%s", &n1, &n2, buf2) == 2) {
        /* Success */
        *x = n1;
        *y = n2;
        return 1;
    }
    /* Failure */
    return 0;
}

Note:

The 3rd parameter (buf2) is a guard against invalid input efter the second integer. This trick works because you first read the input into a string. If you try to do scanf("%d%d%s", ...) directly, then the user will be prompted for further input until he provides some non-whitespace to put into buf2.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82