2016-07-10 5 views
3

ファイル入力を受け取り、配列に保存するプログラムを作成しています。問題は、二次元アレイを行うべきかどうか、私が完全にはわからないことです。具体的には、私が聞いたループwhile !feofはおそらく行く方法ではありません。私はまた、city_mpgとhighway_mpgの平均を見つけて、それを別の列として配列に追加する必要があります。列が追加された後、昇順にソートする必要があります。その平均値を1D配列にして、それを別の列に追加するにはどうすればよいですか?もしそれが2Dだったら、[1][4][1][5]を指定して、それを[1][6]というように保存しますか?C入力ファイルを読み込み、あるタイプの昇順ソート

入力ファイル:不完全

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... 
+2

[、最小完全、かつ検証例]を作成する場合(http://stackoverflow.com/help/mcve)それは通常*それは実際に*であることができます完全で検証可能なつまり、コンパイルして実行します。あなたがビルドエラーや実行時エラーを要求している場合を除きます。また、期待される出力のほかに、実際の出力も含まれます。 –

+3

また、[while(!feof(file))が常に間違っているのはなぜですか?](http:// stackoverflow。com/questions/5431941/why-is-feof-file-always-wrong)を参照してください。 –

+1

独自のコードでは、各タイプの車は 'struct car'型のオブジェクトで表されます。このようなオブジェクトをいくつか用意する必要があります。あなたがそうすることを決めたのは、 'struct car'(これは問題ありません)の配列です。 2Dアレイが必要なのはなぜですか? –

答えて

2

私はコードにいくつかのコメントを付けて少し微調整しました。これは1次元配列を使用します。

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

@ user5468794私は少しコメントを洗い出した。より完全な説明のために 'qsort'のマニュアルページを読むことをお勧めします。 –

+0

最後に、ファイルからプログラムに読み込まれた場合、どのように出力を指定されたファイルに書き出すと便利でしょうか? –

+1

書き込み用のテキストファイルを開き、 'printf'を使ったところで' fprintf(file、...) 'を使います。実際にはコードにバグはありません。カーの種類の文字列を出力に使用する場合、車の詳細が99文字を超えると 'model [] 'に十分な余裕がないかもしれません。それほど可能性は低いですが、潜在的な穴です。 –

1

ができます2つの主要な部分にあなたの質問を分割:

最初存在する - 「私は必要ですか? feof?どんな選択肢があるの「

そして第二にビーイング - 『?この場合は、2Dアレイのための任意の実用化があります』

だから私は、最初の質問で始めるつもりだ 私はお勧めしません?。 feofはストリーム自体ではなくend-of-fileインジケータをテストするためです。これは、実際に到達したときに別の関数が実際にEOFを設定することを意味します。

いつも読むか、それとも終わりかを常にチェックし、それを行うには、常に「読むとチェックする」必要があります。

たとえば、getcを使用する場合、常に結果が-1でないことを確認します。これは他のケースにも注意を払います。通常、msdnはビルドされた戻り値をチェックする方法です。

この場合、2D配列は必要ありません。車の構造はきれいでダイナミックで読みやすいので、後でテーブルを変更できるので、2D配列に別の列を作成する必要はありません。混乱や動的変化が少なくなることが多いからです。たとえば、突然、さまざまなケース(MAX、MIN、AVGなど)で別の5つの列が必要な場合、これは少し疲れているようです。あなたのプログラム上のすべてのメタを保持するデータ構造ではなく、貼り付けたい値としてデータ値を作ります。これはselection_sortでも役に立ちます。データをソートするために2d配列を参照する必要はなく、オブジェクト自体をソートするためです。

関連する問題