1

I have a code here that has a job to see if the user input is either string or integer from a range of 1-49. If I enter "asdas" it says invalid, and if I enter a integer from "1-49" it says valid. The problems I am having with this code is that if I enter "2 asda" it will it count it has valid, and invalid at the same time, and if I enter "2 2" It will consider that valid as well. Just found out it also accepts "2d" as a valid input to.

for (i = 0; i < 6; i++)
        {

            printf("\nPlease enter the %d winning ticket numbers!: ", i+1);
            if (scanf("%d", (&winningNumbers[i])) == 0 || (winningNumbers[i] <= 0) || (winningNumbers[i] >= 50))
            {
                    inputFlush();
                    printf("\nInvalid Input. Please re-enter.\n") ;
                    i = i - 1;
            }
       }

        for (i = 0; i < 6; i++)
        {
            printf("%d, ", winningNumbers[i]);
        }

3 Answers3

2

Read the entire line into a string (fgets, line 2 in the snippet). Read data from the string using sscanf: read the integer and one more character, after a space. Check whether sscanf returns something different than 1. If it does then you either have strings in the beginning (it returns 0 since it couldn't read an integer) or you have extra whitespace characters at the end (that is it also matched the %c format specifier). The space is needed to jump over whitespace until the end of the line (including the stored \n).

printf("\nPlease enter the %d winning ticket numbers!: ", i+1);
fgets(buffer, size, stdin);
if (sscanf(buffer, "%d %c", &winningNumbers[i], &c) != 1 || (winningNumbers[i] <= 0) || winningNumbers[i] >= 50))
{
    // inputFlush(); not needed now that you read the entire line
    printf("\nInvalid Input. Please re-enter.\n") ;
    i = i - 1;
}
Mihai Maruseac
  • 20,967
  • 7
  • 57
  • 109
  • Another option is to use `strtol()` to do the conversion, rather carefully. Since the required range of valid inputs is only 1-49, the numeric range issues can be quietly ignored. But you probably do need to check that there are no characters other than white space after the number. – Jonathan Leffler Nov 18 '13 at 03:22
  • I have tried using fgets. The problem I was getting was that fgets wasn't storing numbers such as "45", but "4" –  Nov 18 '13 at 03:24
  • Yes, `strtol` can be used as well. And it also gives a pointer to the extra characters, if you don't pass in `NULL` for the second argument. – Mihai Maruseac Nov 18 '13 at 03:24
  • @Leoc: I'm pretty sure you didn't use `fgets`. Maybe `fgetc` -- it has the behaviour you described but it is intended. – Mihai Maruseac Nov 18 '13 at 03:25
  • Yeah that's it fgetsc, but using fgets in the fashion of the array. My compiler made me change it so it accepts characters –  Nov 18 '13 at 03:31
  • 1
    The code I posted should not require the compiler to make you change to characters. Please recheck. – Mihai Maruseac Nov 18 '13 at 03:33
  • I will once I get back. Which will be soon –  Nov 18 '13 at 03:37
  • a5.c:89:33: warning: incompatible pointer types passing 'int *' to parameter of type 'const char *' [-Wincompatible-pointer-types] –  Nov 18 '13 at 04:05
  • 1
    Consider `"%d %c"` instead of `"%d%c"`. That extra space will help when user enters "12". – chux - Reinstate Monica Nov 18 '13 at 04:07
  • ? spacing it didn't help. Its coming from my integer type array. –  Nov 18 '13 at 04:09
  • My bad, I forgot to add the string you're reading from (I feel stupid now :() – Mihai Maruseac Nov 18 '13 at 04:10
  • Does it work now? It was a stupid mistake from my part, I even told you that the code is perfect :-/ – Mihai Maruseac Nov 18 '13 at 04:12
  • Works beautifully now! Thank you. Can you maybe explain to me what you have done, and what you did to fix it! –  Nov 18 '13 at 04:14
  • I've updated the text in front of it to contain all of the decisions. – Mihai Maruseac Nov 18 '13 at 04:17
  • @Mihai Maruseac A very _minor_, but useful idea: Since OP said "1-49", consider using "1" and "49" in your code as in `winningNumbers[i] < 1) || winningNumbers[i] > 49)`. Even better to document those _magic_ numbers: `int ValidMin = 1; int ValdMax = 49; `if (... (winningNumbers[i] < ValidMin) || winningNumbers[i] > ValidMax)`. – chux - Reinstate Monica Nov 18 '13 at 04:18
  • @chux: I would code them the same as you said but I took that part from his code and I want to make as minor changes as possible. – Mihai Maruseac Nov 18 '13 at 04:19
  • 1
    I always use it since it clearly describes what you are expecting to read. – Mihai Maruseac Nov 18 '13 at 04:22
  • 1
    @Mihai Maruseac (Sorry to pester) "or you have extra **non-whitespace** characters at the end (that is it also matched the %c format specifier)." Drop the "The space is needed for platforms which implement newlines as CR-LF (\r\n) pair of characters." as that is incorrect. The space will scan any number of space, tab, \r, \n, whitespace. – chux - Reinstate Monica Nov 18 '13 at 04:22
  • @mihaiMaruseac with the same coding except for strings what if I wanted it to do the opposite how would that look like? –  Nov 18 '13 at 04:29
  • I'm afraid I didn't understand. What exactly do you want to read? – Mihai Maruseac Nov 18 '13 at 04:37
  • @MihaiMaruseac Sorry for being unclear. Is there a way I can PM you a code? or no. What I want is to enter a name, and protect the input against integers thats all :) –  Nov 18 '13 at 04:43
  • You cannot use the same trick. But you can read the string representing the name and loop through it and check each character if it is a digit or not (`isdigit`) – Mihai Maruseac Nov 18 '13 at 04:54
  • @MihaiMaruseac Can you give me an example? –  Nov 18 '13 at 04:59
  • 1
    Please move extended discussion to [chat], thanks :) – Tim Post Nov 18 '13 at 07:27
  • I tried doing this but he doesn't have enough reputation for that. Anyway, now the question is answered so no need for further discussion. – Mihai Maruseac Nov 18 '13 at 13:09
0

Look at this example.

#define MAX_LINE_SIZE 500

int main(int argc, char** argv)
{

    char line[MAX_LINE_SIZE];
    unsigned int num;
    char *ptr;

    while (fgets(line, MAX_LINE_SIZE, stdin) != NULL){
        num = strtol(line, &ptr, 10);
        if (line[0] != '\n' && (*ptr == '\n' || *ptr == '\0')) {
            printf("Your num: %u\n", num); // check num if you need
        } else {
            printf("Error\n");
        }
    }

    return 0;
}

The output:

12
Your num: 12
45
Your num: 45
34 2 
Error
ads
Error

Here fgets function read data from stdin. strtol parse read string and assign an address of a char after parsed number to ptr pointer. Assuming that user has to input only one number (without any character after) we have to check whether *ptr is new line or end of line.

line[0] != '\n' prevents empty string.

Deck
  • 1,969
  • 4
  • 20
  • 41
  • Works amazing so far. Can you please explain this to me:) –  Nov 18 '13 at 03:53
  • I understand the strtol part, but if you can explain to me the if statement you did with the null, and new line –  Nov 18 '13 at 03:57
  • One problem is that you need to enter another input till you get those messages. –  Nov 18 '13 at 04:03
  • Ahh makes sense. Thats cleaver, but how do you fix the part where you need to input again in order to have it working as intended ? –  Nov 18 '13 at 04:10
  • @Leoc I would use counter variable, increment it in "good" part of the loop and check whether it equals 6 (like you did). If yes then break. – Deck Nov 18 '13 at 04:16
-1

Check the next character using peek, as detailed here. You can tell if it's good or not that way.

Another SO question that's pretty much the same.

Community
  • 1
  • 1
kmort
  • 2,848
  • 2
  • 32
  • 54