Dynamic array of Structs, delet elements - c

I am trying to create a database program of students where you should be able to add/modify and delete students. I have managed to get the add function working, and also the modify function but the delete function gives me some problems. my code seems to crash when im trying to delete a student from the database, can anyone tell me where the problem lies?
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* TODO: Avoid global variables. */
struct student {
char name[60];
long long personalNumber;
char gender[6];
char studyProgram[60];
char email[30];
int age;
};
struct student *pointer = NULL;
int numberofstudents = 0;
void modify()
{
long long persnr;
long long comp;
int match = 0;
printf("Please enter the personal number that you wish to modify: \n");
scanf("%lld", &persnr);
getchar();
for(int i = 0; i <= numberofstudents; i++)
{
comp = ((pointer+i)->personalNumber);
printf("%lld\n", ((pointer+i)->personalNumber));
printf("%lld\n", comp);
printf("Inne");
if (pointer[i].personalNumber == persnr && match == 0)
{
printf("Enter name, personalnumber, gender, studyprogram, email and age in this order\n");
scanf("%s%lld%s%s%s%d", (pointer+i)->name, &(pointer+i)->personalNumber, (pointer+i)->gender, (pointer+i)->studyProgram, (pointer+i)->email, &(pointer+i)->age);
match = 1;
getchar();
}
if (match == 0)
{
printf("Could not find person");
}
}
}
void deletestudent()
{
long long persnr;
long long comp;
int match = 0;
printf("Please enter the personal number that you wish to delete: \n");
scanf("%lld", &persnr);
getchar();
struct student *temporary = malloc((numberofstudents - 1) * sizeof(struct student));
for(int i = 0; i <= numberofstudents; i++)
{
if (pointer[i].personalNumber == persnr && match == 0)
{
match = 1;
}
else if (match == 1){
temporary[i-1] = pointer[i];
}
else
{
temporary[i] = pointer[i];
}
if (match == 0)
{
printf("Could not find person");
}
}
free(pointer);
pointer = temporary;
}
void add(){
if (numberofstudents > 0)
{
pointer = (struct student*) realloc(pointer, (numberofstudents+1) * sizeof(struct student));
printf("Lyckades allokeringen!\n\n");
}
printf("Enter name, personalnumber, gender, studyprogram, email and age in this order\n");
scanf("%s%lld%s%s%s%d", (pointer+numberofstudents)->name, &(pointer+numberofstudents)->personalNumber, (pointer+numberofstudents)->gender, (pointer+numberofstudents)->studyProgram, (pointer+numberofstudents)->email, &(pointer+numberofstudents)->age);
getchar();
printf("Visar data:\n");
for(int i = 0; i <= numberofstudents; ++i)
{
printf("%s\t%lld\t%s\t%s\t%s\t%d\n", (pointer+i)->name, (pointer+i)->personalNumber, (pointer+i)->gender, (pointer+i)->studyProgram, (pointer+i)->email, (pointer+i)->age);
}
numberofstudents = numberofstudents+1;
}
int main(void)
{
pointer = (struct student*) malloc(2 * sizeof(struct student));
if (pointer == NULL)
{
printf("pointer NULL");
exit(1);
}
int run = 1;
int choice;
while (run == 1)
{
printf("Please enter an option listed below\n1.ADD\n2.Modify\n3.Delete\n4.Search\n5.Save\n6.Load\n7.Exit");
scanf("%d", &choice);
getchar();
switch(choice) {
case 1 :
add();
break;
case 2 :
modify();
break;
case 3 :
deletestudent();
case 7 :
exit(0);
break;
default :
break;
}
}
return 0;
}

As mentioned in a comment, this:
for(int i = 0; i <= numberofstudents; i++)
is a huge warning sign. In C, such a loop should typically have i < numberofstudents in it, assuming numberofstudents is the actual length of the array.
Using <= rather than < makes the loop go one step too far, thus indexing outside the array and causing undefined behavior.
Writing outside heap-allocated memory and then trying to free() it is a good way to provoke crashes, since there's a chance you're stepping on the heap allocator's data structures (in practice; in theory all that happens is that you get undefined behavior and thus anything can happen).

Related

C - numbers not entering in the "if condition", dont know why

So, basically, I was instructed to make a function that asks the user for a size, and then creates an array with elements chosen by the user...
for example: size:4 , input:10 20 30 40, created array = {10,20,30,40}.
Then next step the user is to apply some function for this created array. Example:
For example, if the user chooses letter 'A' the function "add1" will be applied and all elements of the array will be increased in one unit, so with an input example of {10,20,30,40}, the output will be {11,21,31,41}.
My code is not working, why? Someone can help me? I've used the debugger and the function is not entering in the "if condition".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* add1(int* array, int size)
{
int *novo;
novo = malloc(size*sizeof(int));
for (int i = 0; i < size; i++){
*(novo + (i)) = *(array + i)+1;
}
return novo;
};
int* add2(int* array, int size)
{
int *novo;
novo = malloc(size*sizeof(int));
for (int i = 0; i < size; i++){
*(novo + (i)) = *(array + i)+2;
}
return novo;
};
void print1(int* array, int size)
{
for (int i = 0; i < size; i++)
{
printf("%i\n", *(array+i));
}
};
int main(void)
{ int i, elemento, size;
char *new;
printf("Insert Size:\n");
scanf("%i", &size);
int newArray[size];
printf("Insert Elements:\n");
for (i = 0; i < size; i++)
{
scanf("%i", &elemento);
newArray[i] = elemento;
}
printf("Select option:\n");
scanf(" %c", &new);
if (new == 'A') {
int* result;
result = add1(&newArray, size);
print1(result, size);
} else if (new == 'B') {
int* result;
result = add2(&newArray, size);
print1(result, size);
} else if (new == 'C') {
} else if (new == 'D') {
}
}
Change:
char *new;
to
char new;
as
scanf(" %c", &new);
is expecting a character and as the code stands new is an undefined character pointer. So passing a pointer to a undefined pointer is not good.
PLEASE SWITCH ON YOUR COMPILER WARNINGS AND THIS WOULD BE PICKED UP!
new is not a good variable name. As it leads to confusion with C++ keyword
Check the return values for scanf- see the manual page for that
Perhaps using switch instead of if new == 'A' .....

Asking for user's input multiple times with loop in C

With this beginner's code, I am trying to ask the user for input as long as the input is not 'quit'. My code:
void createReport(){
printf("Welcome to the report generator, type item's ID: ");
char *userInput;
int i=0;
struct myStruct{
char *name;
int id;
float sale;
};
struct myStruct *myStructArray[MAX_ITEMS];
fgets(userInput,sizeof(int),stdin);
while(strcmp(userInput,"quit")!=0) {
userInput = malloc(sizeof(int));
fgets(userInput,sizeof(int),stdin);
searchA(userInput); //different function that changes global variable deletion
printf("Added to the report, add more or type \'quit\' \n");
strcpy(myStructArray[i]->name,inventoryItem[deletion].name); //inventoryItem is global
myStructArray[i]->id = atoi(input);
myStructArray[i]->sale = inventoryItem[deletion].sale;
i++;
free(userInput);
}
for(int x=0;x<30;x++) printf(myStructArray[x]->name); //never executed
}
This code runs once, asking the user for input, and then finishes
Does anybody know where can be the mistake? Thanks for any suggestions
Before the while loop you do
fgets(userInput,sizeof(int),stdin);
at that moment your variable userInput is not yet to be set.
Edit:
Running example of the idea of the code:
printf("Welcome to the report generator, type item's ID: ");
const int input_size = 6 * sizeof(char);
char *userInput = malloc(input_size);
int i = 0;
struct myStruct {
char *name;
int id;
float sale;
};
struct myStruct *myStructArray[MAX_ITEMS];
fgets(userInput, input_size, stdin);
while (strcmp(userInput, "quit") != 0 && strcmp(userInput, "quit\n") != 0)
{
// do whatever you like with myStructArray[i], for example:
myStructArray[i] = malloc(sizeof(struct myStruct));
myStructArray[i]->name = malloc(sizeof(char));
myStructArray[i]->name = "ab";
myStructArray[i]->id = 7;
myStructArray[i]->sale = 99.9F;
printf("Added %s, %d, %f\n", myStructArray[i]->name, myStructArray[i]->id, myStructArray[i]->sale);
//prepare for next iteration:
printf("Added to the report, add more or type \'quit\' \n");
for (int j = 0; j < input_size; ++j) // zeroing allocated data on the heap
userInput[j] = 0;
fgets(userInput, input_size, stdin);
i++;
}
free(userInput);
for (int x = 0; x < i; x++) printf("%s,", myStructArray[x]->name);

C strcmp segmentation fault

#include <string.h>
#include<stdio.h>
#include<stdlib.h>
typedef struct bank
{
char an;
char name;
char type;
int bal;
};
int main()
{
int i=0,n;
printf("Enter the number of accounts\n");
scanf("%d",&n);
struct bank a[n];
printf("Enter the details of the users\n");
for(i=0;i<n;i++)
{
scanf("%s%s%s%d",a[i].an,a[i].name,a[i].type,&a[i].bal);
}
printf("The details of the users are\n");
for(i=0;i<n;i++)
{printf("%s\n%s\n%s\n%d\n\n",a[i].an,a[i].name,a[i].type,a[i].bal);}
char atype[10];
printf("Enter the type of account you want to search\n");
scanf("%s",atype);
char typ[10];
char s[]="savings";
char c[]="current";
int result,res1,res2;
result = strcmp(atype,s);
if(result == 0)
{
for(i=0;i<n;i++)
{
typ[10] = a[i].type;
res1 = strcmp(typ,s);
if(res1 == 0)
{
printf("%s\n%s\n%s\n%d\n\n",
a[i].an,a[i].name,a[i].type,a[i].bal);
}
printf("\n");
}
} else
{
for(i=0;i<n;i++)
{
typ[10] = a[i].type;
res2 = strcmp(typ,c);
if(res2 == 0)
{
printf("%s\n%s\n%s\n%d\n\n",
a[i].an,a[i].name,a[i].type,a[i].bal);
}
printf("\n");
}
}
}
so basically ik its my homework but i did everythimg and i still cannot resolve the segmentation fault.please help
i think its something to do with strcmp() function but oh well
i checked all the sources but couldnt really find any fix.
any help would be appreciated.
For starters:
This
typ[10] = ...
accesses typ one past its valid memory. This invokes undefined behaviour, so anything can happen from then on.
In C array indexing is 0-based. So for char[10] the highest allowed index would be 9. Access the 1st element would be done by using 0.
You have made 2 mistakes here .
First your struct bank declaration was wrong. You forgot to declare name an and type as string. You declared it as just character(char).It should be like :-
struct bank
{
char an[100]; // assuming 100 is max size of input strings
char name[100];
char type[100];
int bal;
};
second you cannot do typ[10] = a[i].type; you should use strcpy() Something like this :-
strcpy(typ,a[i].type);
So this corrected code will work :-
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct bank // change made 1
{
char an[100];
char name[100];
char type[100];
int bal;
};
int main()
{
int i = 0, n;
printf("Enter the number of accounts\n");
scanf("%d", &n);
struct bank a[n];
printf("Enter the details of the users\n");
for (i = 0; i < n; i++)
{
scanf("%s%s%s%d", a[i].an, a[i].name, a[i].type, &a[i].bal);
}
printf("The details of the users are\n");
for (i = 0; i < n; i++)
{
printf("%s\n%s\n%s\n%d\n\n", a[i].an, a[i].name, a[i].type, a[i].bal);
}
char atype[10];
printf("Enter the type of account you want to search\n");
scanf("%s", atype);
char typ[10];
char s[] = "savings";
char c[] = "current";
int result, res1, res2;
result = strcmp(atype, s);
if (result == 0)
{
for (i = 0; i < n; i++)
{
strcpy(typ,a[i].type); // change made 2
res1 = strcmp(typ, s);
if (res1 == 0)
{
printf("%s\n%s\n%s\n%d\n\n",
a[i].an, a[i].name, a[i].type, a[i].bal);
}
printf("\n");
}
}
else
{
for (i = 0; i < n; i++)
{
strcpy(typ,a[i].type); // change made 3
res2 = strcmp(typ, c);
if (res2 == 0)
{
printf("%s\n%s\n%s\n%d\n\n",
a[i].an, a[i].name, a[i].type, a[i].bal);
}
printf("\n");
}
}
}
So your mistake was not with strcmp()

strcmp refuses to work [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I've tried everything, yet strcmp (as well as strncmp) always give a value other than 0, both with and without using pointers, as well as inside and outside functions. What should I do?
The point of the program is to create a student data system for signing up and in, as well as managing and sorting said data, the latter which I haven't implemented yet.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int signup(char* ET, char* OT, int* G1T, int* G2T, int* G3T, int* avg, char* status, int* LI, int* sT, int* TT, char** UT, int** PT)
{
int i;
char LU[21];
int ID;
if (strcmp (status, "Register") == 0)
{
printf("Enter last name: ");
scanf("%s", ET);
printf("Enter first name: ");
scanf("%s", OT);
while(1)
{
printf("Enter C grade: ");
scanf("%d", G1T);
if (*G1T >= 0 && *G1T <= 10)
{
break;
}
}
while(1)
{
printf("Enter Java grade: ");
scanf("%d", G2T);
if (*G2T >= 0 && *G2T <= 10)
{
break;
}
}
while(1)
{
printf("Enter C++ grade :");
scanf("%d", G3T);
if (*G3T >= 0 && *G3T <= 10)
{
break;
}
}
*avg = (*G1T + *G2T + *G3T)/3;
*UT[*TT] = *ET;
*sT = 1;
}
else
{
printf("Enter username: ");
scanf("%s", &LU);
for (ID = 0; ID < 100; ID++)
{
if (strncmp(LU, UT[ID], 20) == 0)
{
break;
}
}
if (ID == 100)
{
return 0;
}
else
{
printf("Enter password: ");
scanf("%s", LU);
}
}
return 0;
}
void pass(char** User, int** Pass, int* Total)
{
int cd[21];
int i, j;
for (i=0; i<21; i++)
{
cd[i] = *User[i];
if (i%2 == 0)
{
if(cd[i] >= 97 && cd[i <= 122])
{
cd[i] = cd[i] - 32;
}
}
else
{
if(cd[i] >= 65 && cd[i] <= 90)
{
cd[i] = cd[i] + 32;
}
}
}
}
int main(void) {
int i, j, z;
int succ, *sT;
char intro[9], *status;
int Total = 0;
int* TT;
int LoggedIn = 0;
int* LI;
char Ep[100][21], *ET, On[100][21], *OT;
int Age[100], *AgeT, Gr1[100], *G1T, Gr2[100], *G2T, Gr3[100], *G3T, avg[100], *avgT;
char UN[100][21], *UT[100];
int PW[100][21], *PT[100];
while(1)
{
system("cls");
if (succ = 0)
{
printf("ERROR: Last name found.");
}
succ = 1;
while(1)
{
printf("Type your option (Login/Register): ");
scanf("%s", intro);
if ((strcmp (intro, "Login") == 0) || (strcmp (intro, "Register") == 0))
{
break;
}
}
if ((strcmp (intro, "Login") == 0) || (strcmp (intro, "Register") == 0))
{
for(i = 0; i < 100; i++)
{
UT[i] = &UN[i][0];
PT[i] = &PW[i][0];
}
ET = &Ep[Total][0];
OT = &On[Total][0];
G1T = &Gr1[Total];
G2T = &Gr2[Total];
G3T = &Gr3[Total];
avgT = &avg[Total];
LI = &LoggedIn;
status = &intro[0];
sT = &succ;
TT = &Total;
signup(ET, OT, Gr1, Gr2, Gr3, avg, status, LI, sT, TT, UT, PT);
for(i = 0; i<Total; i++)
{
if(strncmp(UN[Total], UN[i], 20) == 0)
{
succ = 0;
}
}
if (succ == 1)
{
pass(UT, PT, TT);
Total++;
}
}
}
return 0;
}
An example for my inputs is the following:
Register
LastName
FirstName
4
5
6
Then:
Register
LastName
FN2
7
6
5
And I expect to see "ERROR: Last name found." right above the starting message. However, it never appears, suggesting strcmp failed.
First off, you're allocating a lot of arrays in local variables in main(). That could lead to a stack overflow. You should probably use malloc() to allocate them instead.
Second, this line is an assignment, not a comparison, which is a bug:
if (succ = 0)
Change it to this, if you want it to be a comparison:
if (succ == 0)
Third, you're not initializing succ at the beginning of main() which is a bug.
If I see anything else suspect I'll update my answer. But start with fixing those issues.
There are a few issues with your code, as was pointed out, but the reason it doesn't work as you expect is the line: if(succ = 0)
I changed it to: if(succ==0)
And it worked as you described.
Additionally this line here: scanf("%s", &LU); should be scanf("%s", LU);
The compiler is probably generating a warning about the format.

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

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);
So when i fixed the code that made the program crash (as was mentioned in the answers, thanks!) it seems like the problem with the sorting came from this line of code not treating the values correct, since I wanted to return it as percentage and it must have stopped reading after the decimal which made every user either scoring 0 or 1 if this makes sense. It works now when the return value is multiplied by 100.
Started with this code:
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;
}
And this code seems to be the problemsolver.
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 (int)((g2->average - g1->average)*100);
After taking into account of previous remarks, it remains other problems before to manage correctly the sort of array of struct gamer by using the qsort() optimized function.
Problem 1 - no allocated space to store the username into a struct gamer.
The struct gamer is using a char *username;;
When reading data from "test.txt" file, the user name is storing only the pointer to the buffer instead of the content gamers[i]->username = n;;
Even if the read username is strcpy(n, ptr);, that storage is in the heap and be overwritten at the next reading operation;
As #pm100 suggestes, the average is decoded as a binary data instead of a text value float avg = *(float *) ptr;
In the showTop5() function use:
while (fgets(line, sizeof(line), f)) {
ptr = strtok(line, delimiter);
char n[40];
strcpy(n, ptr);
ptr = strtok(NULL, delimiter);
float avg = atof(ptr); // #pm100 proposed solution
gamers[i].average = avg;
gamers[i].username = (char *)malloc(sizeof(char)*(strlen(n)+1));
strcpy(gamers[i].username,n); // allocate and copy the username
i++;
}
Instead of
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; // error no size allocated
i++;
}
Problem 2 - When using qsort() the structure of data shall have a fixed-size length. Use an array of pointer struct gamer * to be sorted.
If sizeof(struct gamer) is used to qsort(), the float average and the char *username will be sorted, but it is not optimized;
After allocating the size to store username, it will be not easy to free the memory if the array struct gamer gamers[count]; is allocated from the heap;
It the amount of gamers is large, storing in the heap could be a problem;
Allocating the gamers[] array:
struct gamer **gamers;
int i;
gamers = malloc(count*sizeof(struct gamer *));
for (i = 0; i < count; i++) {
gamers[i] = malloc(sizeof(struct gamer));
}
Manage the reading operation to the array:
See the source code in the Problem 1
Update the compare function of quicksort:
int compare(const void *s1, const void *s2)
{
struct gamer *g1 = *((struct gamer **)s1); // instead of (struct gamer *)s1;
struct gamer *g2 = *((struct gamer **)s2); // instead of (struct gamer *)s2;
// as #BeginnerC suggests, reverse the comparison
return ((int)((g2->average - g1->average)*100));
}
Perform the quicksort:
qsort(gamers, count, sizeof(struct gamer *), compare);
Print the Top 5 gamers:
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);
}
Free the allocated gamers[] array:
for (i = 0; i < count; i++) {
free (gamers[i]->username); // allocated to the username
free (gamers[i]);
}
free(gamers);
Note: in order to simplify the solution of Problem 1 and to have a fixed-size struct gamer, the field char *username could be replaced by char username[40]; (because char n[40]; before strcpy(n, ptr);.

Resources