C读取输入文件并对一种类型进行升序排序

标签 c arrays sorting file-io

我正在编写一个接受文件输入并将其保存到数组的程序。问题是我不完全确定我是否应该做一个二维数组。特别是我听说过的 while 循环 !feof 可能不是正确的方法。我还需要找出 city_mpg 和 highway_mpg 的平均值,然后将其作为另一列添加到数组中。添加列后,我需要对其进行升序排序。如果它是一维数组然后将其添加到另一列,我将如何找到平均值?如果它是 2D,我不能只指定 [1][4][1][5] 并执行类似的操作,然后将其保存为 [1][6] 等等还是我应该坚持使用 Malloc?

输入文件:

Mercury Sable 2009 18 28
Jeep Wrangler 2016 17 21
Honda civic 2015 31 41
Toyota Corolla 2015 30 42
Toyta Prius 2010 51 48
Ford Escape 2013 23 33
Ford Fusion 2013 25 37
Acura MDX 2014 20 28
Lexus RX 2013 32 28

程序不完整:

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

#define MAX_CARS 1000 //no more than 1000 cars
#define MAX_STR  30  //str wont be longer than 30

struct car {                       // declare my structure
    char *make;                    // pointers for char and declares my vars
    char *model;                  
    int manufacture_year;
    int city_mpg;
    int highway_mpg;
    int average_mpg;
};

//sorts array based on average mpg here

int main(void) { //main function
    int cars = 0;
    int c;
    struct car *data;
    char make[MAX_STR+1];  //char will be 30 + 1 for null char
    char model[MAX_STR+1];
    int year, city, highway; //declares ints
    FILE *file; //declares input file
    FILE *file2; //declares output file

    file = fopen("cars.txt", "r"); //opens car.txt as read
    if(file == NULL) { //if file is null
        printf("File error\n"); //throws error
        return 1;
    }

    data = malloc(MAX_CARS * sizeof(struct car)); //allocates memory for array by max cars for pointers
    if(data == NULL) {
        printf("Memory error\n"); //error if memory is a issue just incase mainly used for testing
        return 1;
    }

    while(fscanf(file, "%30s %30s %d %d %d", make, model, &year, &city, &highway) == 5) { //reads the data with a while loop
        if(cars >= MAX_CARS) { //just a check if file is more than 1k
            printf("Too many cars\n"); //outputs result if too many cars
            break;
        }
        data[cars].make = strdup(make);             // makes a copy of the strings
        data[cars].model = strdup(model);            
        data[cars].manufacture_year = year;         // copies the data so that it is headed properly
        data[cars].city_mpg = city;                 // copies the data so that it is headed properly
        data[cars].highway_mpg = highway;           // copies the data so that it is headed properly
        data[cars].average_mpg = (city + highway) / 2; //gets the average mpg
        cars++;                                     // loop counter
    }
    fclose(file); //closes file

    file2 = fopen("sorted_cars.txt", "a+"); //opens new file or creates one if there isnt one

    fprintf(file2,"Make Model           Year City mpg Highway mpg Average mpg\n"); //prints to new txt file
    for(c=0; c<cars; c++) {
        sprintf(model, "%s %s", data[c].make, data[c].model);    //sprintf sends formatted output to a string
        fprintf(file2,"%-20s %4d  %4d        %4d        %4d\n", model, data[c].manufacture_year,data[c].city_mpg, data[c].highway_mpg, data[c].average_mpg); //prints to oufile
    }

    // free the memory, It tries to allocate enough memory to hold the old string (plus a null character to mark the end of the string)
    while(--cars >= 0) {
        free(data[cars].model);     
        free(data[cars].make);       
    }
    free(data); //frees the array memory
    return 0;
    }

预期结果:

Make Model     year city mpg highway mpg average mpg
Jeep Wrangler  2016    17          21          19
Mercury Sable  2009    18          28          23
and so on...

最佳答案

我对您的代码进行了一些调整,并提供了一些评论。它使用一维数组。

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

#define MAX_CARS 1000
#define MAX_STR  99

struct car {                       // array of cars appears later
    char *make;                    // pointer to string memory that will be allocated
    char *model;                   // ditto
    int manufacture_year;
    int city_mpg;
    int highway_mpg;
    int average_mpg;
};

int cmp(const void *a, const void *b) {
    // compare function for qsort
    // this is the user-supplied compare function always required by qsort
    // qsort does not know or care about the data type, only its dimensions
    // so I cast the void pointers to our local data type
    struct car *aa = (struct car*)a;
    struct car *bb = (struct car*)b;
    if(aa->average_mpg > bb->average_mpg) return 1;
    if(aa->average_mpg < bb->average_mpg) return -1;
    return 0;
}

int main(void) {
    int cars = 0;
    int c;
    struct car *data;
    char make[MAX_STR+1];
    char model[MAX_STR+1];
    int year, city, highway;
    FILE *file;

    // set up
    file = fopen("cars.txt", "r");
    if(file == NULL) {
        printf("File error\n");                     // finish messages with a newline
        return 1;
    }
    // allocate dynamic memory for the array, for maximum cars specified
    // the argument is the total memory requirement
    // could have been a global array of struct but it's bad practice
    data = malloc(MAX_CARS * sizeof(struct car));
    if(data == NULL) {
        printf("Memory error\n");
        return 1;
    }

    // read the data, controlling the loop with fscanf return value
    // feof is commonly, but incorrectly used, and since it is essential to check the 
    // return value from fscanf, this kills two birds with one stone
    while(fscanf(file, "%49s %49s %d %d %d", make, model, &year, &city, &highway) == 5) {
        if(cars >= MAX_CARS) {
            printf("Too many cars\n");
            break;
        }
        data[cars].make = strdup(make);             // make a copy of the strings
        data[cars].model = strdup(model);
        data[cars].manufacture_year = year;         // copy the data
        data[cars].city_mpg = city;
        data[cars].highway_mpg = highway;
        data[cars].average_mpg = (city + highway) / 2;
        cars++;                                     // track the number of records
    }
    fclose(file);

    // sort the records, qsort needs to know the width of each element, 
    // and how many many, and you tell it your own comparison callback function
    qsort(data, cars, sizeof *data, cmp);

    // print the data
    printf("Make Model           Year City mpg Highway mpg Average mpg\n");
    for(c=0; c<cars; c++) {
        sprintf(model, "%s %s", data[c].make, data[c].model);   // to make alignment easy
        printf("%-20s %4d  %4d        %4d        %4d\n", model, data[c].manufacture_year,
                    data[c].city_mpg, data[c].highway_mpg, data[c].average_mpg);
    }

    // free the memory, note that strdup allocated memory secretly
    while(--cars >= 0) {
        free(data[cars].model);      // it was acquired by strdup
        free(data[cars].make);       // so was this
    }
    free(data);                      // now free the array memory we got ourselves
    return 0;
    }

程序输出:

Make Model           Year City mpg Highway mpg Average mpg
Jeep Wrangler        2016    17          21          19
Mercury Sable        2009    18          28          23
Acura MDX            2014    20          28          24
Ford Escape          2013    23          33          28
Lexus RX             2013    32          28          30
Ford Fusion          2013    25          37          31
Honda civic          2015    31          41          36
Toyota Corolla       2015    30          42          36
Toyta Prius          2010    51          48          49

关于C读取输入文件并对一种类型进行升序排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38294685/

相关文章:

java - 在 Java 中对自定义链表进行排序

c - 为什么我会收到关于 printf() with %s taking type void * as parameter 的警告?

c - 带套接字的多用户 'guess a number'游戏,使用C

c - 套接字聊天应用程序,即我想一次与多个客户端聊天?

PHP:变量为字符串时出现 "Array to string conversion"错误

java - 循环访问对象数组并访问特定的键/值字段

c - 如何根据有多少用户选择再次输入,在C编程中输出时打印do

javascript - 在 Javascript 中将数组格式化为 Google Map API 格式的 Lat Lng 数组

arrays - Swift:排序字典(按键或按值)并返回有序数组(键或值)

sorting - 使用awk删除包含唯一第一个字段的行?