Search code examples
cinputscanfgetchar

How to make getchar() not get the ENTER I did before?( in C)


here's the problem: I have to read a bunch of numbers(student's grades) , calculate their average, and if the average is under 70 i have to apply a factor to the grade(grade curve) either +x or *x and then print the amount of students in the class and the average. I have written the whole code already, but my problem is that after i finish entering the numbres and i need to enter the factor formula, it skips the part where the factor is supposed to read input, as if the getchar() gets my ENTER from when i finish entering the numbers... im sorry i'm having really hard time explaining the problem, but here's the code:

    #include <stdio.h>

#define num_of_students 80
int Grades_Array[num_of_students]={0};

int getGrades()
{
    int i=0;
    int grade_checker=0;
    while (grade_checker >= 0)
    {
        scanf("%d", &grade_checker);
        if (grade_checker < 0)
            break;
        Grades_Array[i] = grade_checker;
        i++;
    }
    return i;
}

float averageGrade(int stud_num)
{
    int i=0;
    int total=0;
    float avg_grade=0;
    for (i=0 ; i < stud_num ; i++)
        total = total + Grades_Array[i];
    avg_grade = total / stud_num;
    return avg_grade;
}

void factor(int stud_num)
{
    float i=0;
    int j=0;
    char c=0;
    printf("Please enter a factor formula:\n");
    while ( c!='\n' && c!=EOF)
    {
        c=getchar();
        if ( c == '+' || c == '*')
        {

            scanf("%f", &i);
            break;
        }
    }
    if ( c == '+')
    {
        for (j=0 ; j<stud_num ; j++)
        {
            Grades_Array[j] = Grades_Array[j] + i;
            if (Grades_Array[j] > 100)
                Grades_Array[j] = 100;
        }
    }
    if ( c == '*')
    {
        for (j=0 ; j<stud_num ; j++)
        {
            Grades_Array[j] = Grades_Array[j] * i;
            if (Grades_Array[j] > 100)
                Grades_Array[j] = 100;
        }
    }
}

void printAverage(int stud_num, float average)
{
    printf("Number of students in the course: %d\n", stud_num);
    printf("Average number: %f", average);
}

void main()
{
    int i=getGrades();
    float avg = averageGrade(i);
    if (avg < 70)
        factor(i);
    printAverage(i, avg);
}

here's my code, and a few notes: num_of_students indicates the maximum students that can be in the class and getGrades function read the students grades and also counts how many students are in the class atm (returns i)

here's an example of input and output: input : 57 99 20 60 69 73 44 100 85 66 75 0 87 73 -1 (grades) +3 (factor formula

output:

Number of students in the course: 14 Average grade: 67.500000

Any help would be appreciated, thank you for your time!


Solution

  • Unfortunately, getting interactive input is quite problematic when using scanf(), getchar(), fgets(), etc. That's why most people usually write their own custom functions, often getting a whole line from stdin and then parsing it according to their needs. Most of the time trouble comes from the line-buffering nature of stdin, which in many cases is left unflushed, so leftovers from previous reads feed the next ones (btw, here is a good ol' read, ihmo).

    I'm not quite sure I've nailed all possible cases in your code, but here is a version of it that seems to work with minimal changes. Basically I've coded a simple flush_stdin() function and I changed a bit your scanf() calls (added error-checking, re-arranged the code a bit, etc). I've also dropped getchar() inside your factor() function, and replaced what I thought you were trying to do with scanf() instead.

    While I was at it, I fixed a couple more things irrelevant to the original question (for example, I added a sanity check in your averageGrade() function, in order to prevent a division-by-zero runtime error).

    It seems to work ok, but I haven't tested extensively. Note though that in general, the preferred way to handle interactive input is via custom functions (GNU for example recommend using their getline() and getdelim() extensions for reading lines from a stream).

    So here is the code, I hope it helps...

    #include <stdio.h>
    #include <stdlib.h>
    
    #define num_of_students 80
    
    int Grades_Array[num_of_students] = {0};
    
    /* -------------------------------------- */
    void flush_stdin(void)
    {
        int c;
        while ( !feof(stdin) && '\n' != (c=getchar()) && EOF != c )
            ;   /* void */
    }
    /* -------------------------------------- */
    int getGrades( void )
    {
        int i     = 0;
        int grade = 0;
    
        for (;;)
        {
            if ( 1 != scanf("%d", &grade) || grade < 0 )
                break;
            Grades_Array[i++] = grade;
        }
        flush_stdin();
    
        return i;
    }
    /* -------------------------------------- */
    float averageGrade(int stud_num)
    {
        int i = 0;
        int total = 0;
        float   avg_grade = 0;
    
        /* avoid division by zero */
        if ( 0 == stud_num )
            return -1.0;
    
        for (i=0; i < stud_num; i++)
            total += Grades_Array[i];
    
        avg_grade = total / stud_num;
    
        return avg_grade;
    }
    /* -------------------------------------- */
    void factor(int stud_num)
    {
        float   i = 0;
        int j = 0;
        char    c = '\0';
    
        printf("Please enter a factor formula:\n");
        if ( 2 != scanf(" %c%f", &c, &i) )  /* skip leading blanks, then read c and i */
            return;
    
        for (j=0; j < stud_num; j++)
        {
            if ( '+' == c )
                Grades_Array[j] += i;
            else if ( '*' == c )
                Grades_Array[j] *= i;
            else
                break;
    
            if ( Grades_Array[j] > 100 )
                Grades_Array[j] = 100;
        }
    }
    
    /* -------------------------------------- */
    void printAverage( int stud_num, float average )
    {
        printf("Number of students in the course: %d\n", stud_num);
        printf("Average number: %f\n", average);
    }
    
    /* -------------------------------------- */
    int main( void )
    {
        int i     = getGrades();
        float avg = averageGrade(i);
    
        if (avg < 70)
            factor(i);
        printAverage(i, avg);
    
        exit(0);
    }