0

I am writing a program where I have to read data from a file and then sort them in descending ascending order. I am having trouble with the sorting part of it. How do I sort the float values and then print the struct sorted? Here is my code. I keep getting a segmentation fault. I am not sure how to fix it.

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

typedef struct importedData {
    char type[100];
    float literAmount;
    int miles;
    char color[20];
}DATA;

void sorting();

int main() {
    int userInput;
    //initialize();
    DATA *data = NULL;
    sorting(data);
    //Do while loop to loop through  menu until exit.
    do {
    //Print statements to put out the output options
        printf("Choose the option you would like to preform \n");
    printf("1.Sort data from the float value & print high to low \n2.Sort data by the float value & print low to high\n3.Sort data by the int value & print high to low\n4.Sort data by the int value & print low to high");
    scanf("%d", &userInput); //Scanner to take in the keyboard input


    } while (userInput != 5);


    return 0;
}

int numberOfLines() {
    FILE *fp = fopen("hw3.data", "r"); //Opens file name and in the read format
    int c = 0; //Count the number of characters
    int count = 0; //Number of lines

    if(fp == NULL) { //If file was not able to be opened program will exit
        printf("Unable to read file. Closing");
        return 0;
    }
    while((c = fgetc(fp)) != EOF) { //Get the character and make sure it isnt the END OF FILE
        if(c == '\n') { //If the charcter is set to \n (New Line) will add one to counter
            count++;
        }
    }
    fclose(fp);
    return count;
}

DATA* initialize(DATA *data) {
    data = malloc(numberOfLines() * sizeof(*data));
    FILE *fp = fopen("hw3.data", "r"); //Opens file name and in the read format
    int counter = 0;
    int totalIterations = numberOfLines();
    while(counter < totalIterations) {
        if(fscanf(fp, "%s %f %d %s\n", data[counter].type, &data[counter].literAmount, &data[counter].miles, data[counter].color) !=4) {
    } 
    printf("data stored is: %s %f %d %s\n", data[counter].type, data[counter].literAmount, data[counter].miles, data[counter].color);
    }
    return (data);
}

void sorting() {
    DATA *data = malloc(numberOfLines() * sizeof(*data));
    FILE *fp = fopen("hw3.data", "r"); //Opens file name and in the read format
    int counter = 0;
    int totalIterations = numberOfLines();
    while(counter < totalIterations) {
        if(fscanf(fp, "%s %f %d %s\n", data[counter].type, &data[counter].literAmount, &data[counter].miles, data[counter].color) ==4) {
    counter++;
    } 
}
    DATA *temp;
    int i, j;
    for(i = 0; i < (numberOfLines() -1); i++) {
        for(j = 0; j < (numberOfLines() -1); j++)  {
            if(data[i].literAmount > data[i+1].literAmount) {
                data[i].literAmount = (*temp).literAmount;
                printf("Temp: %f", (*temp).literAmount);
            }
        }
    }
}
6
  • You as almost everyone else, are using scanf() the wrong way, it has a return value, do not ignore it. Have you tried qsort()? Commented Feb 16, 2015 at 23:36
  • Oh, and you could cause an infinite loop in while (counter < totalIterations). Just use while (fscanf(...) != 4) and the format string can be "%s%f%d%s\n", the spaces are not needed. And return does not need parentheses. Commented Feb 16, 2015 at 23:38
  • 1
    That segmentation fault will likely divulge some significant information if you run this in a debugger. Commented Feb 16, 2015 at 23:39
  • I have looked into it but when I use qsort does it transfer over the rest of the data from that index into the new sorted position? Commented Feb 16, 2015 at 23:41
  • I am not sure how to use the debugger. I am very new to C Commented Feb 16, 2015 at 23:42

1 Answer 1

1

You can have these 4 comparison functions

int compare_literAmount(const void *const lhs, const void *const rhs)
{
    if ((lhs == NULL) || (rhs == NULL))
        return -1;
    return ((int)(((DATA *)lhs)->literAmount)) - ((int)(((DATA *)rhs)->literAmount));
}

int compare_type(const void *const lhs, const void *const rhs)
{
    if ((lhs == NULL) || (rhs == NULL))
        return -1;
    return strcmp(((DATA *)lhs)->type, ((DATA *)rhs)->type);
}

int compare_miles(const void *const lhs, const void *const rhs)
{
    if ((lhs == NULL) || (rhs == NULL))
        return -1;
    return (((DATA *)lhs)->miles) - (((DATA *)rhs)->miles);
}

int compare_color(const void *const lhs, const void *const rhs)
{
    if ((lhs == NULL) || (rhs == NULL))
        return -1;
    return strcmp(((DATA *)lhs)->color, ((DATA *)rhs)->color);
}

and then after reading the data you can

qsort(data, numberOfItems, sizeof(*data), compare_literAmount);

to sort by the literAmmount field, and so on.

Your initialize() function is also very weak, make it more robust by adding some checks, and you could cause an inifinite loop in while (counter < totalIterations), because you didn't check that all lines were valid in numberOfLines(), also it would be better if you pass fp to numberOfLines() instead of openning and closing the file there.

This is a suggestion of fixes to your initialize() function

DATA* initialize(DATA *data) {
    int totalCount = numberOfLines();
    int count      = 0;
    data           = malloc(totalCount * sizeof(*data));
    if (data == NULL)
        return NULL;
    FILE *fp = fopen("hw3.data", "r"); //Opens file name and in the read format
    if (fp == NULL)
    {
        free(data);
        return NULL;
    }
    /* write a safer format string */
    while(fscanf(fp, "%99s%f%d%19s\n", data[count].type, &data[count].literAmount, &data[count].miles, data[count].color) == 4)
        count++;
    qsort(data, count, sizeof(*data), compare_literAmount);
    for (int i = 0 ; i < count ; i++)
        printf("data stored is: %s %f %d %s\n", data[count].type, data[count].literAmount, data[count].miles, data[count].color);

    return (data);
}

notice that the first thing I did was to store the value of the number of lines in the file. Because it would be more efficient.

Sign up to request clarification or add additional context in comments.

5 Comments

Excellent answer, but I suspect this should have moved to Codereview
I am having trouble with this method. I used the qsort with the compare functions you wrote but it doesnt actually seem to be any sorting. I called the qsort in the sort function and then did a while loop to print out the values. They dont actually switch
@user1881401 why did you use a while loop? I added the printing part to the code using a for loop. And they wont switch if the are already sorted, can you provide the input data please?
The problem is that they arent sorted. I tried using the miles sorter and that works perfectly! I am nto sure why the floating point part isnt. The data files contents: F150 6.0 59000 white and RAM1500 5.2 14578 orange when running the qsort function on the floating point part it just prints it out in the order that is in the data file
@user1881401 it's because 6.0 - 5.2 = 0.8 and (int)0.8 -> 0 so it takes them as equals, I've updated the answer to make it work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.