code kid
code kid

Reputation: 414

Organizing a struct in alphabetical order with qsort

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

#define ARRAY_MAX 100
#define FNAME 31
#define LNAME 31

typedef int (*compfn)(const void*, const void*);

struct student {

    char firstName[FNAME];
    char lastName[LNAME];
    int quiz1, quiz2 , quiz3, quiz4, mid1, mid2, final;
    char letterGrade;
    int finalGradePercentage;
};

// Function for Qsort
int compare(struct student *element1, struct student *element2)
{
    if ( element1->firstName[0] < element2->firstName[0])
        return -1;

    else if (element1->firstName[0] > element2->firstName[0])
        return 1;

    else
        return 0;
    }


int main(int argc, char *argv[]){


    FILE *inputFile, *outputFile;
    char buf[100];
    char *token;
    int count = 0;

    inputFile = fopen("/Users/Home/Desktop/input_data.txt", "r");


    struct student studentData[ARRAY_MAX];
    while (fgets(buf, sizeof(buf), inputFile) != NULL){ //scan through the input file
        token = strtok(buf, " ");
        strcpy(studentData[count].firstName, token);
        token = strtok(NULL, ",");
        strcpy(studentData[count].lastName, token);
        token = strtok(NULL, ",");
        studentData[count].quiz1 = atoi(token);
        token = strtok(NULL, ",");
        studentData[count].quiz2 = atoi(token);
        token = strtok(NULL, ",");
        studentData[count].quiz3 = atoi(token);
        token = strtok(NULL, ",");
        studentData[count].quiz4 = atoi(token);
        token = strtok(NULL, ",");
        studentData[count].mid1 = atoi(token);
        token = strtok(NULL, ",");
        studentData[count].mid2 = atoi(token);
        token = strtok(NULL, ",");
        studentData[count].final= atoi(token);


        studentData[count].finalGradePercentage = studentData[count].quiz1 * .10 +studentData[count].quiz2 * .10 + studentData[count].quiz3 * .10 + studentData[count].quiz4 * .10 + studentData[count].mid1 * .20 + studentData[count].mid2 * .15 + studentData[count].final * .25;

        if (studentData[count].finalGradePercentage <=100 &&  studentData[count].finalGradePercentage>=90 )
        {
            studentData[count].letterGrade = 'A';
        }
        else if(studentData[count].finalGradePercentage <= 89 && studentData[count].finalGradePercentage >=80)
        {
            studentData[count].letterGrade = 'B';
        }
        else if(studentData[count].finalGradePercentage <= 79 && studentData[count].finalGradePercentage >=70)
        {
            studentData[count].letterGrade = 'C';
        }
        else if(studentData[count].finalGradePercentage <= 69 && studentData[count].finalGradePercentage >=60)
        {
            studentData[count].letterGrade = 'D';
        }
        else if(studentData[count].finalGradePercentage <= 59){
            studentData[count].letterGrade = 'F';
        }


        count++;
    }


    qsort((void *) &studentData,count,sizeof(struct student),(compfn)compare);           


    for (int i = 0; i< count; i++) {
        char name[62];

        sprintf(name, "%s %s", studentData[i].firstName, studentData[i].lastName);
        printf("%-20s %c\n", name, studentData[i].letterGrade);

    }

    fclose(inputFile);
    fclose(outputFile);

    return 0;
}

Hi Guys I'm having a tough time getting my struct organized in alphabetical order. Any help doing so would be greatly appreciated. This is what I have so far. I think the problem is the in the compare function. But I'm not sure I really understand qsort all that well. Anyone one know of some good references for reading up on it.

Upvotes: 0

Views: 1391

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754600

Using your existing structure, you are comparing the first character of the first name, only. You need to compare strings with strcmp(), and given that there could be two students called John or Jane in a class, you probably want to compare on last name too.

int compare(struct student *element1, struct student *element2)
{
    if ((rc = strcmp(element1->firstName, element2->firstName)) != 0)
        return rc;
    return strcmp(element1->lastName, element2->lastName);
}

On the whole, I prefer to write comparison functions as:

int compare(const void *v1, const void *v2)
{
    const struct student *p1 = (struct student *)v1;
    const struct student *p2 = (struct student *)v2;

    if ((rc = strcmp(p1->firstName, p2->firstName)) != 0)
        return rc;
    return strcmp(p1->lastName, p2->lastName);
}

I then don't have to cast the pointer to qsort() since the pointer to function is of the same type that qsort() expects. In practice, there isn't much difference.

See also How to sort an array of structs in C?

Upvotes: 1

Related Questions