I need help with the function to show the top 5 scores in the text file in C

advertisements

I am currently creating a really simple program for my beginners course in C programming and I am stuck. I want to be able to print the 5 best scores that are saved in a text file but right now it is only showing the first 5 lines not the best scored lines. The history part works okay and is printing everything but I cannot understand how to print the 5 best scores, maybe it has to do with sorting out the information in the extern text file? Sorry if this post is dumb but I need to ask somewhere (I am really basic at this).

Here is a part of the code that I think is not working properly, it is for codeblocks:

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

char name [40];     // Here every integer and character etc. is introduced as global.
int menu(char *name);
int startPractice(int choice);
int startTest(int choice, char *name);
char randomOperator();
int getRandomNumber(int min, int max);
int calc(int a, int b, char c);
int rand(void);
int showHistory();
int saveHistory(char *name, float average);
int showTop5();

struct gamer{
char *username;
float average;
};

int main()
{
printf("Hello and welcome to the program!\n"); // This is the introduction
printf("\nWhat is your name? ");
scanf("%s", &name);

printf("\nWelcome %s! \n\nWhat would you like to do? \n" , name);
menu(&name); // This line calls the main menu.

return 0;
}

int compare(const void *s1, const void *s2)
{
struct gamer *g1 = (struct gamer *)s1;
struct gamer *g2 = (struct gamer *)s2;/* same gender so sort by id */

return g1->average - g2->average;
}

int menu(char *name) {        // This is the main menu and whenever this function is called the program starts from here.
int qanswer;        // This variable is set so it can be used in this body, it is not a global integer.

printf("\n1. Do practices \n2. Do a test \n3. Quit \n4. Test history \n5. Top 5 \n");
scanf("%d", &qanswer);

switch (qanswer) {      // Switch cases for a more compressed code, here only one case will be activated and that is decided by the value of "qanswer".
    case 1:
        printf("\nNow, you can choose to do practices on: \n\n1. Additions\n2. Subtractions\n3. Addition and Subtractions: ");
        printf("\n\nEnter your choice: ");
        scanf("%d" , &qanswer);
        startPractice(qanswer);
        break;      //This breaks the code at any chosen case.
    case 2:
        printf("\nYou will be given 15 questions to solve as the test!\n\n");
        printf("\nYou can choose to do the test on: \n\n1. Additions\n2. Subtractions\n3. Addition and Subtractions: ");
        printf("\n\nEnter your choice: ");
        scanf("%d", &qanswer);
        startTest(qanswer, name);
        break;
    case 3:
        printf("\nExiting program... \n");
        exit(0); // Shuts down the program.
        break;
    case 4:
        printf("Test history\n");
        showHistory();
        break;
    case 5:
        printf("Top 5 test results:\n");
        showTop5();
        break;
    default:        // if the user enter anything except 1,2,3 this line of code will be returned.
        printf("Your input wasn't valid. Please try again...\n\n");
        menu(name);     // This calls the main menu again
}

return 0;
}

int startPractice(int choice) {     // If practice is chosen then this function will be called.

int a, b, answer1;
char c;

int i;
for (i = 1; i <= 10; i++) {     // The for loop runs this code until i=10 and increases by 1 each time. Therefore this code will run 10 times fully.
    a = getRandomNumber(1, 30);     // This calls the function for a random number.
    b = getRandomNumber(1, 30);
    if (choice == 1) {      // If choice is set to "1" c will be t to + otherwise -.
        c = '+';
    } else if (choice == 2) {
        c = '-';
    } else {
        c = randomOperator();
    }

    printf("%d. %d %c %d = ", i, a, c, b);
    scanf("%d", &answer1);

    while (answer1 != calc(a, b, c)){
        printf("Try again! ");
        scanf("%d", &answer1);
    }

    printf("Very good!\n\n");
}
printf("Practice is complete\n");
printf("\nNow what would you like to do?\n");
menu(name);

return 0;
}

int startTest(int choice, char *name) {
int a, b, answer1;
char c;
int counter = 0;
float average;
int i;
for (i = 1; i <= 15; i++) {
    a = getRandomNumber(1, 30);
    b = getRandomNumber(1, 30);
    if (choice == 1) {
        c = '+';
    } else if (choice == 2) {
        c = '-';
    } else {
        c = randomOperator();
    }

    printf("%d. %d %c %d = ", i, a, c, b);
    scanf("%d", &answer1);
    if (answer1 == calc(a, b, c)){
        counter++;
    }

    printf("\n\n");
}
printf("The test is complete\n");
average = (float) counter/(float)15;        // This calculates the average score as a float with the counter / 15.
printf("You scored %d out of 15 which is and average of %d %%\n", counter, (int)average*100);       // This line takes the value of average and multiply it by 100 to show the percentage.
saveHistory("Test", average);
printf("\nNow what would you like to do?\n");
menu(name); // This function calls the main menu again.

return 0;

}

int calc(int a, int b, char c) {        // This function is used to define the equation as (a + b) or (a - b).
switch(c) {
    case '+':
        return a+b;
    case '-':
        return a-b;
}
}

char randomOperator() {         //This code is used to decide if + or - is going to be used.
switch(getRandomNumber(0,1)) {      //Switch statement when you need two or more ways to return a value.
    case 0:
        return '+';     //If the random number is 0 return is + otherwise it is -.
    case 1:
        return '-';
}

return '+';
}

int getRandomNumber(int min, int max) {     // This simply decides a random value of min 0 and max 1.
return rand() % (max + 1 - min) + min;
}

int showHistory(){
FILE *f;
char c;
f=fopen("test.txt","rt");

if (f) {
    while((c=fgetc(f))!=EOF){
        printf("%c",c);
    }

    fclose(f);
    printf("\nWhat would you like to do now?\n");
} else {
    printf("There is no history file at the moment.");
}

menu(name);

return 0;
}

int saveHistory(char *name, float average){
FILE *f;
char c;
f=fopen("test.txt","a");

fprintf(f, "%s_%.2f\n", name, average);

fclose(f);
return 0;
}
int showTop5(){
//printf("\n");
FILE *f;
char c;
char line[256];
int count = 0;
f=fopen("test.txt","rt");

if (f) {
    while (fgets(line, sizeof(line), f)) {
        if (strlen(line) > 0) {
            count++;
        }
    }

    char delimiter[] = "_";
    char *ptr;

    fclose(f);

    f=fopen("test.txt","rt");

    struct gamer gamers[count];
    int i = 0;
    printf("\n");
    while (fgets(line, sizeof(line), f)) {
        ptr = strtok(line, delimiter);
        char n[40];
        strcpy(n, ptr);
        //printf("n: %s, ", n);
        ptr = strtok(NULL, delimiter);
        float avg = *(float *) ptr;
        //printf("points: %f\n", avg);
        gamers[i].average = avg;
        gamers[i].username = n;

        i++;
    }

    qsort(gamers, count, sizeof(struct gamer), compare);

    int j;
    for(j = 0; j < count; j++){
        if (j==5){
        break;
    }
        printf("Rank %d: %s with %.2f %% as average.\n", j+1, gamers[j].username, gamers[j]. average);
    }

    fclose(f);
} else {
    printf("There is no history file at the moment.");
}

menu(name);

return 0;
}


This isnt going to work

 ptr = strtok(NULL, delimiter);
    float avg = *(float *) ptr;

you are treating the score in the file as though it were the binary representation of a float. It is not, it is text. You need to do

   ptr = strtok(NULL, delimiter);
    float avg = atof(ptr);