Home > Software engineering >  Error in the program that's give additional output
Error in the program that's give additional output

Time:11-26

#include <stdio.h>
#include <math.h>

int main()
{
    int i;
    int j;
    int base;
    int height;
    int side;
    int up;
    int down;
    int output[1001];
    
    for (i = 0; i < 1000; i  )
    {
        char type = getchar();
        
        if(type == 'P')
        {
            scanf("%d", &side);
            
            output[i] = side * side;
        }
        else if (type == 'S')
        {
            scanf("%d %d", &base, &height);
            
            output[i] = 0.5 * base * height;
        }
        else if (type == 'T')
        {
            scanf("%d %d %d", &up, &down, &height);
            
            output[i] = height * (up   down) / 2;
        }
        else if(type == '0')
        {
            break;
        }
    }
    
    for(j = 0; j < i; j  )
    {
        {
            printf("%d\n", output[j]);
        }
    }
    
    return 0;
}

What i want is after i input '0', the program stop asking for input and then give the output. Overall it's working but there's an error where in every output, there's always have 1 line of '0'.

Sample Input:

P 5
S 10 10
T 10 10 10
0

Output that i want:

25
50
100

Output that i have with this code right now:

25
0
50
0
100
0

I'm guessing it's the

else if(type == '0')
        {
            break;
        }

that make this error but i'm not sure and i don't know how to fix this

CodePudding user response:

The input could be better visualized as:

P 5\n
S 10 10\n
T 10 10 10\n
0\n

i is being incremented an additional time for every newline character it encounters before a lone zero.

The very quick fix is to only increment i when you add something to the array:

for (i = 0; i < 1000;)
{    
    char type = getchar();    

    if(type == 'P')    
    {    
        scanf("%d", &side);    

        output[i  ] = side * side;    
    }    
    else if (type == 'S')    
    {    
        scanf("%d %d", &base, &height);    

        output[i  ] = 0.5 * base * height;    
    }    
    else if (type == 'T')    
    {    
        scanf("%d %d %d", &up, &down, &height);    

        output[i  ] = height * (up   down) / 2;    
    }    
    else if(type == '0')    
    {    
        break;    
    }    
}

This still has the problem of infinitely looping when EOF is returned by getchar, and not checking the return values of scanf to see if the call successfully performed the expected number of conversions leaves you open to operating on indeterminate values.

Refactoring this a bit:

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

#define MAX 1001

int get_int(void)
{
    int x;

    if (1 != scanf("%d", &x))
        exit(EXIT_FAILURE);

    return x;
}

int main(void)
{
    int i = 0;
    int output[MAX];

    while (i < MAX) {
        int type = getchar();

        if (EOF == type || '0' == type)
            break;

        int value;
        int up, down, height, side;

        switch (type) {
            case 'P':
                side = get_int();
                value = side * side;
                break;
            case 'S':
                value = 0.5 * get_int() * get_int();
                break;
            case 'T':
                up = get_int();
                down = get_int();
                height = get_int();
                value = height * (up   down) / 2;
                break;
            default:
                continue;
        }

        output[i  ] = value;
    }

    for (int j = 0; j < i; j  ) {
        printf("%d\n", output[j]);
    }
}

CodePudding user response:

The problem is that the lines

scanf("%d", &side);
scanf("%d %d", &base, &height);
scanf("%d %d %d", &up, &down, &height);

will not extract the newline character at the end of the line.

Therefore, in the next loop iteration, the call to getchar will extract that newline character and the call to scanf will fail, because the next character is a letter and not a number. This means that only the call to getchar one loop iteration later will actually extract the first character of the new line.

This bug should be clearly visible by running your program line by line in a debugger, as the debugger will show you that the value of type will be \n (ASCII Code 10) in the second loop iteration.

To fix this bug, the simplest solution would be to add a call to getchar after every call to scanf, which will discard the newline character from the input stream.

A more robust solution would not use scanf, but would use the function fgets to always read exactly one line of input and sscanf to parse the input:

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

int main( void )
{
    int output[1000];
    char line[200];
    int i;

    //attempt to read one line of input per loop iteration
    for ( i = 0; ; i   ) //infinite loop
    {
        char *p;

        //protect against buffer overflow
        if ( i == sizeof output / sizeof *output )
        {
            fprintf( stderr, "Too many lines!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to read one line of input
        if ( fgets( line, sizeof line, stdin ) == NULL )
        {
            fprintf( stderr, "Error reading input!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to find newline character in the line
        p = strchr( line, '\n' );

        //verify that entire line was read and remove the
        //newline character, if it exists
        if ( p == NULL )
        {
            //a missing newline character is probably acceptable
            //when end-of-file has been reached, for example when
            //standard input is being piped from a file.
            if ( !feof( stdin ) )
            {
                fprintf( stderr, "Line too long for input buffer!\n" );
                exit( EXIT_FAILURE );
            }
        }
        else
        {
            //remove the newline character by overwriting it with
            //a terminating null character
            *p = '\0';
        }

        if( line[0] == 'P' )
        {
            int side;

            if ( sscanf( line 1, "%d", &side ) != 1 )
            {
                fprintf( stderr, "Error parsing input!\n" );
                exit( EXIT_FAILURE );
            }

            output[i] = side * side;
        }
        else if ( line[0] == 'S' )
        {
            int base, height;

            if ( sscanf( line 1, "%d %d", &base, &height ) != 2 )
            {
                fprintf( stderr, "Error parsing input!\n" );
                exit( EXIT_FAILURE );
            }

            output[i] = 0.5 * base * height;
        }
        else if ( line[0] == 'T' )
        {
            int up, down, height;

            if ( sscanf( line 1, "%d %d %d", &up, &down, &height ) != 3 )
            {
                fprintf( stderr, "Error parsing input!\n" );
                exit( EXIT_FAILURE );
            }

            output[i] = height * (up   down) / 2;
        }
        else if ( line[0] == '0' )
        {
            //break out of infinite loop
            break;
        }
    }
    
    for ( int j = 0; j < i; j   )
    {
        printf( "%d\n", output[j] );
    }
    
    return 0;
}

For the input specified in the question, this program has the desired output:

25
50
100
  •  Tags:  
  • c
  • Related