2016-07-10 7 views
3

Ich schreibe ein Programm, das eine Dateieingabe übernimmt und in einem Array speichert. Das Problem ist, ich bin mir nicht ganz sicher, ob ich ein 2D-Array machen soll oder nicht. Insbesondere meine While-Schleife, die ich gehört habe !feof ist wahrscheinlich nicht der Weg zu gehen. Ich muss auch den Durchschnitt von city_mpg und highway_mpg herausfinden und dann das Array als eine andere Spalte hinzufügen. Nachdem die Spalte hinzugefügt wurde, muss ich sie aufsteigend sortieren. Wie würde ich die Durchschnittswerte finden, wenn es ein 1D-Array ist, und es dann zu einer anderen Spalte hinzufügen? Wenn es 2D wäre, könnte ich nicht einfach [1][4] und [1][5] angeben und eine Operation wie diese ausführen, dann speichern Sie es als [1][6] und so weiter oder sollte ich bei Malloc bleiben?C Eingabedatei lesen und für einen Typ aufsteigend sortieren

Eingabedatei:

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 

Programm unvollständig:

#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; 
    } 

Erwartetes Ergebnis:

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

Wenn ein [Minimal, vollständig und prüfbare Beispiel] Erstellen (http://stackoverflow.com/help/mcve) hilft es in der Regel, dass es tatsächlich * ist * vollständig und überprüfbar. Mit anderen Worten, es kompiliert und läuft. Es sei denn, Sie fragen nach Build- oder Laufzeitfehlern. Und neben der erwarteten Ausgabe auch die * tatsächliche * Ausgabe. –

+3

Bitte lesen Sie auch [Warum ist "while (! Feof (Datei))" immer falsch?] (Http: // stackoverflow.com/questions/5431941/why-is-while-feof-Datei-immer falsch). –

+1

In Ihrem eigenen Code wird jede Art von Auto durch ein Objekt vom Typ 'struct car' repräsentiert. Sie müssen mehrere solcher Objekte unterbringen. Die Art und Weise, wie Sie sich dazu entschieden haben, dies zu tun, ist über eine Reihe von "struct car" (was in Ordnung ist). Warum brauchen Sie dafür ein 2D-Array? –

Antwort

2

Ich habe ein paar Änderungen an Ihrem Code vorgenommen, mit einigen Kommentaren. Es verwendet ein 1-D-Array.

#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; 
    } 

Programmausgabe:

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 
+1

@ user5468794 Ich habe die Kommentare ein wenig konkretisiert. Ich rate Ihnen, die Manpage für 'qsort' für eine ausführlichere Beschreibung zu lesen. –

+0

Eine letzte Sache, die hilfreich sein könnte, wenn es in das Programm aus einer Datei eingelesen wurde, wie würden Sie die Ausgabe in eine bestimmte Datei schreiben? –

+1

Öffnen Sie eine Textdatei zum Schreiben und verwenden Sie 'fprintf (Datei, ...)', wo ich 'printf' verwendet habe. Es gibt tatsächlich einen (nicht offensichtlichen) Fehler im Code - wo ich eine Zeichenfolge des Autotyps für die Ausgabe aufstelle, hat 'Modell []' möglicherweise nicht genug Platz, wenn die Fahrzeugdetails mit mehr als 99 Zeichen verkettet werden. Nicht sehr wahrscheinlich, aber immer noch ein potenzielles Loch. –

1

Lässt Ihre Fragen zu 2 Hauptteile aufgeteilt:

der ersten Sein - "Brauche ich Feuf? Gibt es Alternativen“

Und das zweite Wesen -‚Gibt es eine praktische Anwendung für 2D-Arrays in diesem Fall‘

So würde beginnen mit der ersten Frage, die ich bin ich nicht empfehlen?. feof zu verwenden, weil feof den Dateiende-Indikator testet, und nicht den Stream selbst. Und das bedeutet, dass eine andere Funktion tatsächlich für das Setzen des EOF verantwortlich ist, was schlecht ist.

Eine gute Alternative dazu ist zu lesen und immer zu prüfen, ob es mehr zu lesen gibt oder es ist das Ende, und dazu müssen Sie immer "lesen und prüfen".

Wenn Sie zum Beispiel getc verwenden, überprüfen Sie immer, dass das Ergebnis nicht -1 ist. Dies gilt auch für andere Fälle. In der Regel ist msdn der richtige Weg, um die eingebauten Rückgabewerte zu überprüfen.

Für die zweite Frage, in diesem Fall sind keine 2D-Arrays erforderlich. Ihre Fahrzeugstruktur ist sauber, dynamisch und lesbar aufgebaut, so dass Sie später Änderungen am Tisch vornehmen können, ohne dass Sie eine weitere Spalte in einem 2D-Array erstellen müssen, da dies häufig zu Verwirrung und weniger dynamischen Änderungen führt. Zum Beispiel, wenn Sie plötzlich weitere 5 Spalten in allen Arten von verschiedenen Fällen (MAX, MIN, AVG, etc usw.) wollen, kann dies ein wenig ermüdend erscheinen. Stellen Sie Datenwerte als Werte her, die Sie einfügen möchten, und nicht Datenstrukturen, die alle Meta-Informationen in Ihrem Programm enthalten. Dies wird Ihnen auch bei selection_sort helfen, da Sie dann nicht auf das 2d-Array verweisen müssen, um Ihre Daten zu sortieren, sondern das Objekt selbst.

Verwandte Themen