0

Why are some grade (Hurup Mutu) column items getting printed with the mark (Angka Mutu) column items (for example B+3,5 where B+ is the grade and 3,5 is the mark), even though in my data struct, I have defined the grade (Hurup Mutu) char array to have only 2 characters, but it's storing up to 5.

This doesn't occur on every line, so I'm having a hard time finding the error, please help me.

You can see it in the following output, I have highlighted the results that are wrong:

Output

This is my C Code


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

struct data
{
    char nim[13];
    char nama[50];
    float uts, uas, tugas, kuis,total;
    char grade[2], angka[4], status[14];
};

void tampil();
void data(struct data[], int );
char* hurupMutu(int);
char* nilaiMutu(int);
char* status(int);

int main() {

    tampil();

    return 0;
}

void tampil(){
    int p;
    char *a;

    printf("+----------------------------------+\n");
    printf("|       Masukan Data Mahasiswa     +\n");
    printf("+----------------------------------+\n");

    printf("Masukan Banyak Data Mahasiswa : ");
    scanf("%d", &p);

    if (p < 1){
        printf("Data Mahasiswa harus lebih besar dari 0 ");
        exit(0);
    }

    struct data d[p];

    for(int i = 0; i < p; i++){
        int total = 0;
        
        printf("Data ke %d : \n", i+1);
        
        printf("Masukan NIM : ");
        fflush(stdin);
        gets(d[i].nim);
        
        printf("Masukan Nama : ");
        fflush(stdin);
        gets(d[i].nama);
        
        printf("Masukan Nilai UTS : ");
        scanf("%f", &d[i].uts);
        total +=  d[i].uts * 0.3;
    
        printf("Masukan Nilai UAS : ");
        scanf("%f", &d[i].uas);
        total += d[i].uas * 0.3;
        
        printf("Masukan Nilai Tugas : ");
        scanf("%f", &d[i].tugas);
        total += d[i].tugas * 0.2;
    
        printf("Masukan Nilai Kuis : ");
        scanf("%f", &d[i].kuis);
        total += d[i].kuis * 0.2;
        d[i].total = total;
      
        strcpy(d[i].grade, hurupMutu(d[i].total));
        strcpy(d[i].status, status(d[i].total));
        strcpy(d[i].angka, nilaiMutu(d[i].total));
    }
  
    data(d, p);
}

char* hurupMutu(int a){
    if (a >= 80 && a <= 100){
      return "A";
    }else if(a >= 70 && a < 80){
      return "B+";
    }
    else if(a >= 65 && a < 70){
      return "B";
    }else if(a >= 60 && a < 65){
      return "C+";
    }else if(a >= 55 && a < 60){
      return "C";
    }else if(a >= 50 && a < 55){
      return "D+";
    }else if(a >= 45 && a < 50){
      return "D";
    }else if( a < 45){
      return "E";
    }else{
      return "?";
    }
}



char* nilaiMutu(int a){
    if (a >= 80 && a <= 100){
      return "4,0";
    }else if(a >= 70 && a < 80){
      return "3,5";
    }else if(a >= 65 && a < 70){
      return "3,0";
    }else if(a >= 60 && a < 65){
      return "2,5";
    }else if(a >= 55 && a < 60){
      return "2,0";
    }else if(a >= 50 && a < 55){
      return "1,5";
    }else if(a >= 45 && a < 50){
      return "1,0";
    }else if( a < 45){
      return "0";
    }else{
      return "?";
    }
}

char* status(int a){
    if (a >= 80 && a <= 100){
      return "Istimewa";
    }else if(a >= 70 && a < 80){
      return "Sangat Baik";
    }
    else if(a >= 65 && a < 70){
      return "Baik";
    }else if(a >= 60 && a < 65){
      return "Cukup Baik";
    }else if(a >= 55 && a < 60){
      return "Cukup";
    }else if(a >= 50 && a < 55){
      return "Kurang Cukup";
    }else if(a >= 45 && a < 50){
      return "Kurang";
    }else if( a < 45){
      return "Sangat Kurang";
    }else{
      return "Tidak Tau";
    }
}


void data(struct data d[], int p){

    printf("+------------------------------------------------------------------------------------------+\n");
    printf("| NO |    NIM     |     Nama  | Total Nilai | Hurup Mutu | Angka Mutu | Gabungan Kemampuan |\n");
    printf("+------------------------------------------------------------------------------------------+\n");
    for(int i = 0; i < p; i++){
        printf("| %d  ", i + 1);
        
        int a = strlen(d[i].nim);
        int b = 10 - a;
        
        printf("| %s ", d[i].nim);
        for(int j = 0; j < b; j ++){
            printf(" ");
        }
    
        int c = strlen(d[i].nama);
        int e = 50 - c;
    
        printf("| %s", d[i].nama);
        
        for(int j = 0; j < e; j ++){
            printf(" ");
        }
    
        printf(" |");
        printf(" %.2f       " ,d[i].total);

        int f = strlen(d[i].grade);
        int g = 12 - f;
    
        printf("| %s" ,d[i].grade);
        
        for(int j = 0; j < g; j++){
            printf(" ");
        }

        int h = strlen(d[i].angka);
        int k = 12 - h;
    
        printf("| %s" ,d[i].angka);
    
        for(int j = 0; j < k; j ++){
            printf(" ");
        }

        int l = strlen(d[i].status);
        int m = 20 - l;
    
        printf("| %s" ,d[i].status);
    
        for(int j = 0; j < m; j ++){
            printf(" ");
        }
    
        printf("|\n");
        printf("+------------------------------------------------------------------------------------+\n");
    }
}
  • Also see this: [Why is the gets function so dangerous that it should not be used?](https://stackoverflow.com/q/1694036/1553090) – paddy Mar 20 '23 at 10:32
  • See also: [c - Using fflush(stdin) - Stack Overflow](https://stackoverflow.com/questions/2979209/using-fflushstdin) – MikeCAT Mar 20 '23 at 10:42
  • regarding: `fflush(stdin);``the `fflush` function is for output streams only altho some poor compilers (microsoft comes to mind) do allow it. – user3629249 Mar 24 '23 at 14:57

2 Answers2

6

char grade[2] is too short to store 2-character strings like "B+" because there are no room for the terminating null-character.

Allocate enough space to avoid errors.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
2

For starters this call of fflush

fflush(stdin);

has undefined behavior. Remove it.

The function gets used in your program as for example

gets(d[i].nim);

is unsafe and is not supported by the C Standard. Instead either use scanf or fgets. For example

scanf( " %12[^\n]", d[i].nim );

(Pay attention to the leading space in the format string. It allows to skip white space characters.)

Using the variable total declared as having the type int

int total = 0;

with values of the type float like

total +=  d[i].uts * 0.3;
total += d[i].uas * 0.3;
total += d[i].tugas * 0.2;
total += d[i].kuis * 0.2;

and then assigning its value to the data member total that has the type float

float uts, uas, tugas, kuis,total;

does not make a great sense. At least it is unclear why the local variable total declared with the type int.

Also all these functions hurupMutu, status, and nilaiMutu have parameters of the type int

  strcpy(d[i].grade, hurupMutu(d[i].total));
  strcpy(d[i].status, status(d[i].total));
  strcpy(d[i].angka, nilaiMutu(d[i].total));

but are called with argument expressions of the type float. So either declare the data member total as having the type int or redeclare parameters of the functions as having the type float.

The data member grade is declared as an array of 2 elements

char grade[2], angka[4], status[14];

but the function hurupMutu can return a string of 3 elements (including the terminating zero character '\0' of a string literal) like for example

return "B+";

In this case using the function strcpy invokes undefined behavior.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks a lot, it's working, I got a new lesson today, next time I won't be using gets(). related " strcpy(d[i].grade, hurupMutu(d[i].total));" integer value inside which is the index for the array of my struct – Dodek Mardana Mar 25 '23 at 05:27