Search code examples
arrayscfor-loopmaxmin

Why this C program can calculate the min but can't calculate the max?


I'm learning C, and I wrote a program that reads a list of numbers and provides the sum, max, min and mean of the list. The list ends when a negative number is typed.

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

int main ()
{
    int i, number, sum, divider, min, max;
    double mean;
    int addend[1000];
    char s[80];

    for (i=0; i>=0; i++) {
        fgets (s, sizeof(s), stdin);
        number = atoi(s);
        addend[i]=number;
        if (addend[i]>=0) {
            continue;
        }
        else break;
    }
    divider=i;
    i=i-1;
    sum=addend[i];
    while (i>=1) {
        sum=sum+addend[i-1];
        i=i-1;
    }
    printf("[SUM]\n%i\n", sum);
    if (addend[0]<0) {
        printf("[MIN]\n0\n\n[MAX]\n0\n\n[MEAN]\n0\n");
    }
    else {
        mean=sum/divider;
        i=divider-1;
        min=addend[i];
        while (i>=0) {
            if (addend[i-1]<min) {
                min=addend[i-1];
            }
            i=i-1;
        }
        max=addend[i];
        while (i>=0) {
            if (addend[i-1]>max) {
                max=addend[i-1];
            }
            i=i-1;
        }
        printf("[MIN]\n%i\n\n[MAX]\n%i\n\n[MEAN]\n%f\n", min, max, mean);
    }
    return 0;
}

Everything works fine, except the max (if i type "3, 6, 8, 9, -1" the max is 1075314688). I already found a solution (if I write max=addend[divider-1] on line 42 it works fine), but I'm trying to understand why the code I originally wrote doesn't work. I tried searching for the answer online but I didn't find anything.


Solution

  • In general this code snippet

    i=i-1;
    sum=addend[i];
    

    can invoke undefined behavior if the first entered number will be negative. In this case i will be equal to 0 and the expression i - 1 will be equal to -1. That means that the expression addend[i] accesses memory beyond the array.

    This while loop invokes undefined behavior

        i=divider-1;
        min=addend[i];
        while (i>=0) {
            if (addend[i-1]<min) {
                min=addend[i-1];
            }
            i=i-1;
        }
    

    because when i is equal to 0 the expression addend[i-1] accesses memory beyond the array addend.

    And moreover after above loop is equal to -1 so this statement

    max=addend[i];
    

    again invokes undefined behavior and the following loop

        while (i>=0) {
            if (addend[i-1]>max) {
                max=addend[i-1];
            }
            i=i-1;
        }
    

    will not be executed.

    Also pay attention to that in this statement in the right-side of the assignment

    mean=sum/divider;
    

    there is used the integer arithmetic.

    The program can look the following way.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main( void ) 
    {
        enum { N = 1000 };
        int addend[N];
        char s[80];
    
        size_t n = 0;
    
        while ( n < N && fgets (s, sizeof( s ), stdin ) != NULL )
        {
            int number = atoi( s );
            if ( !( number < 0 ) )
            {
                addend[n++] = number;
            }
            else
            {
                break;
            }
        }
    
        if ( n == 0 )
        {
            printf("[MIN]\n0\n\n[MAX]\n0\n\n[MEAN]\n0\n");
        }
        else
        {
            long long int sum = 0;
            for ( size_t i = 0; i < n; i++ )
            {
                sum += addend[i];
            }
    
            printf( "[SUM]\n%lld\n", sum );
    
            int min = addend[0];
            int max = addend[0];
    
            for ( size_t i = 1; i < n; i++ )
            {
                if ( max < addend[i] )
                {
                    max = addend[i];
                }
                else if ( addend[i] < min )
                {
                    min = addend[i];
                }
            }
    
            double mean = ( double )sum / n;
    
            printf( "[MIN]\n%i\n\n[MAX]\n%i\n\n[MEAN]\n%f\n", min, max, mean);
        }
    
    }