0

I have 4 arrays. 1 is a char array. The other 3 are int arrays. I want to perform data validation on them inside of my for loop. With the char array input validation, I want the user to go into a while loop until they enter an alphabetical value. And for the other 3 int arrays, I want the user to go into a while loop until they enter a numerical value. I tried to do this myself, but it is making me enter the values twice, meaning my while loop is running once and then moving forward. Can anyone see what I am doing wrong

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

#define NUM_TEAM 10

void displayWelcome(void);

int main(void)
{

char teamName[NUM_TEAM + 1][30] = { "" };
int teamWins[NUM_TEAM] = {0};
int teamLosses[NUM_TEAM] = {0};
int teamTies[NUM_TEAM] = {0};
int i, bestPercent, worstPercent;

displayWelcome();

//Team Name
for (i = 0; i < NUM_TEAM; i++)
    {
    //Prompt and enter team name
    fflush(stdin);
    printf("\nEnter %i's team name: ", i + 1);
    fgets (teamName[i], sizeof teamName[NUM_TEAM], stdin);
    while ( 1 != scanf( "\n%c", &teamName ))  //Data validation
    {
        fflush(stdin);
        printf("Enter an alphabetical value: ");
    }
    //Team wins array prompt & input
    printf("\nEnter wins for team number %i : ", i + 1);
    scanf("%i", &teamWins[ i ]);
    while ( 1 != scanf( "%i", &teamWins[ i ] ) || teamWins[ i ] <= 0) //Data validation
    {
        fflush(stdin);
        printf("Enter a numerical value: ");
    }
    //Team losses array prompt & input
    printf("\nEnter losses for team number %i : ", i + 1);
    scanf("%i", &teamLosses[ i ]);
    while ( 1 != scanf( "%i", &teamLosses[ i ] ) || teamLosses[ i ] <= 0) 
//Data validation
    {
        fflush(stdin);
        printf("Enter a numerical value: ");
    }
    //Team ties array prompt & input
    printf("\nEnter ties for team number %i : ", i + 1);
    scanf("%i", &teamTies[ i ]);
    while ( 1 != scanf( "%i", &teamTies[ i ] ) || teamTies[ i ] <= 0)             
//Data validation
    {
        fflush(stdin);
        printf("Enter a numerical value: ");
    }
}
//Display Data
for (i = 0; i < NUM_TEAM; i++)/* output each word read */
{
    printf("%s", teamName[i]);
    printf("wins losses ties\n");
    printf("%i %i %i\n", teamWins[i], teamLosses[i], teamTies[i]);
}

return 0;
}

void displayWelcome(void)
{
printf("Welcome to my Football Stats\n");
}
Mohtsu
  • 31
  • 6

3 Answers3

2

fflush(stdin) will produce undefined behavior for streams that are not seekable. You can easily write your own function to empty stdin in a portable way.

The primary pitfall most new (and not so new) C programmers face with scanf is accounting for characters that remain in stdin, either the '\n' or after a matching failure or forgetting to handle EOF. A short example that does both can be something like the following (it is for int, but will be the same for char -- except without possibility of a matching failure)

#include <stdio.h>

/* empty all chars from stdin */
void emptystdin ()
{
    for (int i = getchar(); i != '\n' && i != EOF; i = getchar()) {}
}

int main (void) {

    int v, rtn;     /* value & scanf return */

    for (;;) {
        printf ("\nenter value: "); /* prompt */

        if ((rtn = scanf ("%i", &v)) != 1) {
            if (rtn == EOF) {       /* ctrl+d (ctrl+z on windoze) */
                printf ("input canceled by user, exiting.\n");
                break;
            }
            /* handle invalid input */
            fprintf (stderr, "error: invalid input - integer only.\n");
            emptystdin();   /* empty characters that remain in stdin */
        }
        else    /* output good value */
            printf ("           : %d\n", v);
    }

    return 0;
}

Example Use/Output

$ ./bin/scanf_input_all

enter value: foo
error: invalid input - integer only.

enter value: bar
error: invalid input - integer only.

enter value: 9
           : 9

enter value: 8
           : 8

enter value: input canceled by user, exiting.

Look things over and let me know if you have questions.

David C. Rankin
  • 69,681
  • 6
  • 44
  • 72
1

This may be the problem, i.e. a scanfbefore the loop.

scanf("%i", &teamWins[ i ]);  // Why this line ???
while ( 1 != scanf( "%i", &teamWins[ i ] ) || teamWins[ i ] <= 0)

Simply try:

while ( 1 != scanf( "%i", &teamWins[ i ] ) || teamWins[ i ] <= 0)
             ^^^^^^
             This scanf will be executed at least once
             so no need for a scanf before this line

Also check these links for information about flush:

https://stackoverflow.com/a/22902085/4386427

How to clear input buffer in C?

4386427
  • 33,845
  • 4
  • 32
  • 53
  • That definitely worked for the INT arrays. However, I tried playing around with the char array in that sense, and still can not find the fix. – Mohtsu Oct 20 '17 at 05:59
1

The problem lies in this statement :- "while ( 1 != scanf( "\n%c", &teamName ))"

Background - Workings of a while statement:

while(condition){
     ...instructions 1...
     ...instructions 2...
     ...instructions 3...
}

instructions 4 ...

If the condition is true, the instructions inside the while loop are carried out, otherwise the loop is exited and we execute instruction set 4.

Now, if we are to see the while loop in your code:

  1. First thing is to check the condition : (1 != scanf()). To evaluate this condition, a scanf() function call is made. Thus, irrespective of whether the condition is true or false, there will be at least one scanf() call made.
  2. Thus, to generalize the above statement, there will be one more scanf() call execution that the instructions present inside the while loop. This follows the above point, as to check the condition inside the while loop, we need to execute the scanf() function.

I hope this explanation will help you identify how to get to your desired solution.

  • You should definitely be a teacher if not already. Thank you so much for explaining it like this. Allowed me to think for myself and still come up with the output I was after. – Mohtsu Oct 20 '17 at 06:19
  • This is the nicest thing that I have heard in a while ! Big thanks. I am glad you were able to get the desired output. – Abhishek Mangal Oct 23 '17 at 02:20