-2

Everything works in this code, except for case 4. The if statement where it checks if name and array are empty works. However, if array and char name are not empty, the while loop and the entire program just quit. Basically it doesn't print the summary. If I take away the "name" in my printf statement it runs fine. Once I insert it back, it causes me the same problem.

Am I calling the string wrong?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define true 1
#define false 0

float calculate_percent( float score, float max_score );
float getAvg( float num1, float num2, float num3 );
char getGradeLetter( float score );
void print_line( char symbol, int count );

int main()
{
    char name[20] = { 0 };
    int scores[3] = { 0 };
    float avg = 0;
    int reply;

    print_line( '*', 10 );

    while ( true )
    {
        print_line( '*', 10 );

        printf( "\nChose an option.\n" );
        printf( "1.Enter user name.\n2.Enter exam scores.\n3.Display average exam scores.\n4.Display Summary.\n5.Quit\n" );
        scanf( "%d", &reply );

        switch ( reply )
        {
            case 1:
                printf( "Enter name.\n" );
                scanf( "%s", &name[20] );
                break;

            case 2:
                for ( int i = 0; i < 3; i++ )
                {
                    printf( "Enter a score.\n" );
                    scanf( "%d", &scores[i] );
                }
                break;

            case 3:
                if ( name[20] == 0 && scores[0] == 0 || scores[1] == 0 || scores[2] == 0 )
                {
                    printf( "You havent entered the scores.\n" );
                }
                else
                {
                    avg = getAvg( scores[0], scores[1], scores[2] );
                    printf( "Your average is %.2f\n", avg );
                }
                break;

            case 4:
                if ( name[20] == 0 && scores[0] == 0 || scores[1] == 0 || scores[2] == 0 )
                {
                    printf( "Name and scores are empty.\n" );
                }
                else
                {
                    printf( "Hello %s, your scores are %d %d %d.\n", name[20], scores[0], scores[1], scores[2] );
                    printf( "your average is %d with a letter of grade %c.\n", avg, getGradeLetter( avg ) );
                }
                break;

            case 5:
                exit( 0 );
        }
    }

    getchar();
    return 0;
}

float calculate_percent( float score, float max_score )
{
    return score / max_score * 100;
}

float getAvg( float num1, float num2, float num3 )
{
    return ( num1 + num2 + num3 ) / 3;
}

char getGradeLetter( float score )
{
    char grade_letter;

    if ( score >= 90 )
    {
        grade_letter = 'A';
    }
    else if ( score >= 80 )
    {
        grade_letter = 'B';
    }
    else if ( score >= 70 )
    {
        grade_letter = 'C';
    }
    else if ( score >= 60 )
    {
        grade_letter = 'D';
    }
    else if ( score > 0 && score < 59 )
    {
        printf( "you failed the test.\n\n" );
    }

    return grade_letter;
}

void print_line( char symbol, int count )
{
    for ( int i = 0; i < count; i++ )
    {
        printf( "%c", symbol );
    }
}
Jongware
  • 22,200
  • 8
  • 54
  • 100
jdlucero7
  • 1
  • 2
  • 8
    With `name[20] == 0` you're going out of bounds of the array. That means `case 3` doesn't work either. And worse, with `scanf("%s", &name[20]);` you will *start* writing the input at `name[20]` and beyond, going way out of bounds. All of this out of bounds indexing will lead to [*undefined behavior*](https://en.wikipedia.org/wiki/Undefined_behavior). – Some programmer dude Jul 16 '18 at 07:53
  • 1
    Also, don't define your own `true` and `false`, use [the standard C types with help from ``](https://en.cppreference.com/w/c/types/boolean). – Some programmer dude Jul 16 '18 at 07:55
  • You're right. I removed the scores part of that if statement and case 3 stopped working. How can i fix? what am i doing wrong? – jdlucero7 Jul 16 '18 at 07:56
  • 1
    from the code it looks like you haven't quite understood how arrays work. You don't need to pass the size of the array everywhere. –  Jul 16 '18 at 07:57
  • Do **not** use `scanf()` to read potentially malformed input, especially *user* input. Reading a whole line with `fgets()` and parsing it in-memory is less prone to errors. **If** you use `scanf()`, *check the return value*. If the user enters something that is not a number when you expected one (`"%d"`), your variable does not get initialized, and you run into undefined behaviour. – DevSolar Jul 16 '18 at 08:08
  • The reformatting was done with `astyle --style=ansi --indent-switches --indent-preprocessor --pad-oper --pad-paren-in --pad-header --unpad-paren --convert-tabs --break-blocks --add-brackets --align-pointer=middle` plus some manual touches. [Astyle](http://astyle.sourceforge.net/) is free and can pretty-print other languages as well, I suggest you give it a try. – DevSolar Jul 16 '18 at 08:13

3 Answers3

1

First of all warnings are not to be ignored. My own compiler (CLang) blinked like a Christmas tree when I compiled your code, and all of its warnings were true code errors. Here is a minimally fixed version of your program. But once it will work, I advise you to submit it on Code Review to get more in depth remarks on how to improve your coding style.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define true 1                // not incorrect but uncommon since stdbool.h have existed
#define false 0

float calculate_percent( float score, float max_score );
float getAvg( float num1, float num2, float num3 );
char getGradeLetter( float score );
void print_line( char symbol, int count );

int main()
{
    char name[20] = { 0 };               // ok initializes the full array to `\0` chars
    int scores[3] = { 0 };
    float avg = 0;
    int reply;

    print_line( '*', 10 );

    while ( true )                   // while (1) would be idiomatic C
    {
        print_line( '*', 10 );

        printf( "\nChose an option.\n" );
        printf( "1.Enter user name.\n2.Enter exam scores.\n3.Display average exam scores.\n4.Display Summary.\n5.Quit\n" );
        scanf( "%d", &reply );

        switch ( reply )
        {
            case 1:
                printf( "Enter name.\n" );
                scanf( "%s", name ); // an array decays to a pointer to its first element
                break;

            case 2:
                for ( int i = 0; i < 3; i++ )
                {
                    printf( "Enter a score.\n" );
                    scanf( "%d", &scores[i] );     /* dangerous because you do not control
                        the retun value: what will happen is an alphabet is typed? */
                }
                break;

            case 3:
                // you must test the FIRST element of the string, not one past end
                // and never mix && and || without ()
                if ( name[0] == 0 || scores[0] == 0 || scores[1] == 0 || scores[2] == 0 )
                {
                    printf( "You havent entered the scores.\n" );
                }
                else
                {
                    avg = getAvg( scores[0], scores[1], scores[2] );
                    printf( "Your average is %.2f\n", avg );
                }
                break;

            case 4:
                // same remark as above...
                if ( name[0] == 0 || scores[0] == 0 || scores[1] == 0 || scores[2] == 0 )
                {
                    printf( "Name or scores are empty.\n" );
                }
                else
                {
                    printf( "Hello %s, your scores are %d %d %d.\n", name, scores[0], scores[1], scores[2] );
                    // %d is for an int, use %f for a float
                    printf( "your average is %.2f with a letter of grade %c.\n", avg, getGradeLetter( avg ) );
                }
                break;

            case 5:
                exit( 0 );
        }
    }

    // getchar();           // refrain! good IDE allow a breakpoint on the return in debug mode
                            // and do not close the window in non debug mode
    return 0;
}

float calculate_percent( float score, float max_score )
{
    return score / max_score * 100;
}

float getAvg( float num1, float num2, float num3 )
{
    return ( num1 + num2 + num3 ) / 3;
}

char getGradeLetter( float score )
{
    char grade_letter = 'F';            // you MUST initialize if at least a branch sets no value

    if ( score >= 90 )
    {
        grade_letter = 'A';
    }
    else if ( score >= 80 )
    {
        grade_letter = 'B';
    }
    else if ( score >= 70 )
    {
        grade_letter = 'C';
    }
    else if ( score >= 60 )
    {
        grade_letter = 'D';
    }
    else if ( score > 0 && score < 59 )
    {
        printf( "you failed the test.\n\n" );
    }

    return grade_letter;
}

void print_line( char symbol, int count )
{
    for ( int i = 0; i < count; i++ )
    {
        printf( "%c", symbol );
    }
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

In the statement in case 4:

printf("Hello %s, your scores are %d %d %d.\n", name[20], scores[0], scores[1], scores[2]);

replace name[20] to just name. name holds the starting address pointer of the array name and that is all needed by print function to print the content of char array. so your code should look like this

printf("Hello %s, your scores are %d %d %d.\n", name, scores[0], scores[1], scores[2]);
SHR
  • 7,940
  • 9
  • 38
  • 57
Rizwan
  • 3,324
  • 3
  • 17
  • 38
0
  • An array index is 0-based, meaning that name[0] is the first element and name[19] is the last one. char name[20] defines a 20-element character array, which means it can hold a 19 character string, plus the terminating NUL.
  • In C, arrays of type char are used to store strings and strings are NUL-terminated, which means that the last byte (char) of the string must be the non-printable value '\0' in order for standard string library functions and for printf to work properly.
  • As the earlier commenter says, &name[20] is a pointer to the first byte following your array. While the memory for the name array is allocated automatically on the stack, name[20] is out of this memory block and accessing this byte will lead to undefined behavior.

In other words:

  • When you call scanf, do it like this: scanf("%s", &name[0]); or simply like this: scanf("%s", name);
  • Make sure that the string you read using scanf is less than 19 characters long, or increase the size of the name array. That's not your immediate concern, but it's generally not safe to use scanf to read user input (read here for more on buffer overflows)
  • to check if your string is "empty", use: name[0] == '\0'instead of name[20] == 0
  • In your print statement use printf("%s...", name,...) instead of printf("%s...", name[20],...)
esyldor
  • 11
  • 3