简体   繁体   中英

unicode of char misused for int

I'm writing a program that reads student grade whether it was a char or an int and store it in a union , then it prints the students whose grades are A or >90.

But when I try to do that I get an unexpected output because the program doesn't know which one (the char or the int) I want to compare.

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

union StuGrade {
    char charGrade;
    int intGrade;
};

struct Student {
    int ID;
    int typeOfGrade;
    union StuGrade grade;
};

int main () {
    const int size = 5; 
    struct Student *sList[size]; 

    for (int i = 0; i < size; i++) {
        sList[i] = (struct Student *)calloc(1, sizeof(struct Student));
        if (!sList[i]) {
            puts("Error allocating memory");
            return 1;
        }
        printf("Enter ID: "); 
        scanf("%d", &(sList[i]->ID)); 
        printf("0 for char grade or 1 for int grade: "); 
        scanf("%d", &(sList[i]->typeOfGrade));

        if (sList[i]->typeOfGrade) { 
            printf("Enter an int grade: ");
            scanf("%d", &(sList[i]->grade.intGrade)); 
        } else { 
            printf("Enter a char grade: ");
            scanf(" %c", &(sList[i]->grade.charGrade)); 
        }
    } //end for loop

    printf("\n***Student(s) who take grade 'A' is/are***\n");
    for (int i = 0; i < size; i++) {
        if (sList[i]->grade.charGrade == 'A') 
            printf("ID: %d \nGrade: %c \n", sList[i]->ID, sList[i]->grade.charGrade);
        else if (sList[i]->grade.intGrade >= 90) 
            printf("ID: %d \nGrade: %d \n", sList[i]->ID, sList[i]->grade.intGrade);
    }
    for (int i = 0; i < size; i++)
        free(sList[i]);
    return 0;
}

And this is the output:

Enter ID: 1
0 for char grade or 1 for int grade: 0
Enter a char grade: A
Enter ID: 2
0 for char grade or 1 for int grade: 0
Enter a char grade: b
Enter ID: 3
0 for char grade or 1 for int grade: 1
Enter an int grade: 99
Enter ID: 4
0 for char grade or 1 for int grade: 1
Enter an int grade: 84
Enter ID: 5
0 for char grade or 1 for int grade: 1
Enter an int grade: 65

***Student(s) who take grade 'A' is/are***
ID: 1 
Grade: A 
ID: 2 
Grade: 98 
ID: 3 
Grade: 99 
ID: 5 
Grade: A 

Use the type of grade in the comparison:

  if (sList[i]->typeOfGrade == 0 && sList[i]->grade.charGrade == 'A') 
     printf("ID: %d \nGrade: %c \n", sList[i]->ID, sList[i]->grade.charGrade);
  else if (sList[i]->typeOfGrade == 1 && sList[i]->grade.intGrade >= 90) 
     printf("ID: %d \nGrade: %d \n", sList[i]->ID, sList[i]->grade.intGrade);

Note: My original answer used the ASCII Table , but someone pointed out I should be using the UTF-8 Table instead. However, both are really similar for the purposes described here. However, technically compilers will often use UTF-8 instead of ASCII, so I've edited my answer to reflect that.

Ville-Valtteri has a perfectly good answer, but I would like to explain what's going on too.

So, please review the UTF-8 Table .

As hopefully you should know, every character on any computer gets translated into a number. This is determined by the aforementioned table.

In C and C++, these are sort of treated equally in the sense that if I assign a number to an char:

char c = 65;

It will treat it as the letter 'A' .

Conversely, if I assign the letter 'A' to an int:

int i = int('A');

You end up with the number 65 .

Okay, so now with your code. Let's look at your first test:

if (sList[i]->grade.charGrade == 'A')

You test to see if the value is == to 'A' . Note you do not check for type, so 65 is perfectly acceptable for this test, even if you added it as an int because you are not testing for that. You are testing ONLY for 'A' or its equivalent 65 .

Now, your second test:

else if (sList[i]->grade.intGrade >= 90) 

So, if it's not a char grade 'A', it must be an int grade right? Wrong, because didn't test for if it's a char grade, only that it isn't char grade 'A'. Anything not that, and you get to this test.

That means the letter 'b' would get to this test, which has a value of 98 (see the UTF-8 table again). Since C and C++ treat numbers and letters as sort of the same (not technically, but close), it tests this as a int grade 98, even though it's intended to be a char grade. That means it passes you >= 90 check.

Which brings us to Ville-Valtteri's solution , which is to account for the type of grade in your check.

  if (sList[i]->typeOfGrade == 0 && sList[i]->grade.charGrade == 'A') printf("ID: %d \\nGrade: %c \\n", sList[i]->ID, sList[i]->grade.charGrade); else if (sList[i]->typeOfGrade == 1 && sList[i]->grade.intGrade >= 90) printf("ID: %d \\nGrade: %d \\n", sList[i]->ID, sList[i]->grade.intGrade); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM