質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • C

    4654questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラムを関数を作ってすっきりしたい

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 711

sanchu52

score 164

//【 構造体のポインタ配列を qsort するプログラム例 】
// 実行時間の短い順にならべるプログラムを関数を作って
// すっきりしたいにですが、うまくいかないので教えてください
// NDATAを定義しているのですがbest_tenをmallocで確保して、
// countの代わりに使いたいのですが。


#include <float.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define NDATA ((sizeof best_ten)/(sizeof(BEST_TEN)))
typedef struct {
    int tm_year;        
    int tm_mon;      
    int tm_mday;        
    int tm_hour;        
    int tm_min;      
    int tm_sec; 
    double best;   
} BEST_TEN;

// --------------- 比較用の関数 cmp -------------------
int cmpptr( const void *p, const void *q ) {
    return (*(BEST_TEN**)p)->best - (*(BEST_TEN**)q)->best;
}
// ----------------------------------------------------
char dtfile[] = "LACKNUM.DAT";

int main(void)
{
    FILE *lstfp;
    double best;
    int i,j=0;
    BEST_TEN best_ten[100]={0};
    int count=0;
    if((lstfp =fopen(dtfile, "rb")) == NULL){
         printf("ファイルを作成します。 \n\n");
         best = DBL_MAX;
    }else{
        struct tm lst;

        printf("\n過去の履歴のコピー\n-------------------------- \n");    
        while((i = fread(&lst,sizeof(struct tm), 1, lstfp)) > 0 ){
             printf("%d年 %d月 %d日 %d時 %d分 %d秒\n",
                lst.tm_year + 1900, lst.tm_mon + 1,
                lst.tm_mday, lst.tm_hour, lst.tm_min, lst.tm_sec);
             fread(&best, sizeof(double), 1, lstfp);
             printf("得点(所要時間)は %.1f秒です。\n\n", best);
             // 画面が一瞬で消えてしまうのを防止 
             //  一瞬で画面が消えてしまう場合には、以下の文を入力します。
             best_ten[j].tm_year=lst.tm_year;
             best_ten[j].tm_mon=lst.tm_mon;
             best_ten[j].tm_mday=lst.tm_mday;
             best_ten[j].tm_hour=lst.tm_hour;
             best_ten[j].tm_min=lst.tm_min;
             best_ten[j].tm_sec=lst.tm_sec;
             best_ten[j].best=best;
             /*printf( "%d年 %d月 %d日 %d時 %d分 %d秒 %.lf秒\n\n"
                , best_ten[j].tm_year + 1900, best_ten[j].tm_mon + 1,
                best_ten[j].tm_mday, best_ten[j].tm_hour, best_ten[j].tm_min, best_ten[j].tm_sec,best_ten[j].best);*/
             j++;
             count++;
        }
        printf("countは %dです。\n\n", count);
    } 
    printf("count2は %dです。\n\n", count);
    printf("NDATAは %dです。\n\n", NDATA);
    BEST_TEN *plst[NDATA];
    for( i = 0; i < count; i++ ) {
        plst[i] = &best_ten[i];
    }
    qsort( plst, count, sizeof(BEST_TEN*), cmpptr );


        printf("\n過去のbestten\n-------------------------- \n");    
    // 並べ替え後の内容を表示
    for(i=0;i<count;i++){
        printf( "%d年 %d月 %d日 %d時 %d分 %d秒 %.lf秒\n"
            ,plst[i]->tm_year+1900, plst[i]->tm_mon+1, plst[i]->tm_mday,
             plst[i]->tm_hour,plst[i]->tm_min,plst[i]->tm_sec );
           printf("得点(所要時間)は %.1f秒です。\n\n",     plst[i]->best);
    }

    fflush(stdin);
    getchar();
    fclose(lstfp);      
    return 0;
}

/*実行結果

....@naka ~/qsort/struct_sort
$ gcc -o qsort4 qsort4.c -lpdcursesw

....@naka ~/qsort/struct_sort
$  qsort4

過去の履歴のコピー
--------------------------
2015年 10月 27日 19時 9分 59秒
得点(所要時間)は 11.0秒です。

2016年 1月 4日 19時 15分 11秒
得点(所要時間)は 8.0秒です。

2016年 1月 4日 19時 16分 8秒
得点(所要時間)は 9.0秒です。

2016年 1月 4日 19時 16分 39秒
得点(所要時間)は 10.0秒です。

2016年 1月 4日 19時 19分 7秒
得点(所要時間)は 10.0秒です。

2016年 1月 4日 19時 21分 11秒
得点(所要時間)は 10.0秒です。

2016年 1月 4日 19時 21分 44秒
得点(所要時間)は 8.0秒です。

2016年 1月 4日 19時 22分 55秒
得点(所要時間)は 13.0秒です。

2016年 1月 5日 21時 31分 52秒
得点(所要時間)は 12.0秒です。

2016年 1月 5日 21時 33分 29秒
得点(所要時間)は 10.0秒です。


過去のbestten
--------------------------
2016年 1月 4日 19時 15分 11秒 0秒
得点(所要時間)は 8.0秒です。

2016年 1月 4日 19時 21分 44秒 0秒
得点(所要時間)は 8.0秒です。

2016年 1月 4日 19時 16分 8秒 0秒
得点(所要時間)は 9.0秒です。

2016年 1月 4日 19時 19分 7秒 0秒
得点(所要時間)は 10.0秒です。

2016年 1月 5日 21時 33分 29秒 0秒
得点(所要時間)は 10.0秒です。

2016年 1月 4日 19時 16分 39秒 0秒
得点(所要時間)は 10.0秒です。

2016年 1月 4日 19時 21分 11秒 0秒
得点(所要時間)は 10.0秒です。

2015年 10月 27日 19時 9分 59秒 0秒
得点(所要時間)は 11.0秒です。

2016年 1月 5日 21時 31分 52秒 0秒
得点(所要時間)は 12.0秒です。

2016年 1月 4日 19時 22分 55秒 0秒
得点(所要時間)は 13.0秒です。



*/
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • coco_bauer

    2016/02/01 13:30

    履歴のファイルからデータを読み出す前に、そのデータを保存する領域をmallocする実装は可能でしょうが、そうしてmallocした領域へのポインタの配列を保持する事が必要なので、best_10のようなデータ配列を使う場合と大差ないコードになると思いますから、「すっきり」とはいかないと思います。過去履歴の件数が100件を超えても正常に動作するというメリットはあります。

    キャンセル

  • sanchu52

    2016/02/02 07:51

    すみません。漠然としたお願いで申し訳ありませんでした。
    私は一連の質問を依頼してこちらが何をしているか分かってもらっている人でしたら、分かっていただいたと思います。要は配列でも、可変のポインタ配列でもおなじということですね。勉強のためにmalloc使って、NDATAをうまく使えるようにしたかったのです。
    すこしmallocを復習してからやってみます。

    キャンセル

回答 1

+1

こんにちは。

長くなるのでこちらから。

関数を作ってすっきりしたいにですが、うまくいかないので教えてください
NDATAを定義しているのですがbest_tenをmallocで確保して、countの代わりに使いたいのですが。

「関数を作ってすっきりしたい」のでしょうか?
それとも、「best_tenをmallocで確保して」可変個のデータに対応されたいのでしょうか?
もし、両方ともでしたら、両方を同時に進めるのはちょっと骨と思います。
後者→前者の順で行うことをお勧めします。


【追記:mallocで最大記録数を可変対応する方法】
一番問題になるのは、ファイルに記録されているデータの数をどうやって取得するか?です。
①既に実装されている仕組みを流用し、countで計算されているデータの数を使う
②ファイルのサイズを獲得して、データ1つのサイズで割ることでデータの数を計算する

プログラムの修正量は②の方が少ないので②の方法で提案します。

1.下記2つが必要な記憶領域ですが、これをmallocで獲得できるようにします。

BEST_TEN best_ten[100];
↓
BEST_TEN *best_ten;
BEST_TEN *plst[NDATA];
↓
BEST_TEN **plst;


2.次にデータ数を求めます
C言語のファイル操作機能には、下記があります。
(1)ファイルからデータを読みだす位置を示すファイル位置表示子
(2)ファイル位置表示子を指定位置へ移動する(fseek)
(3)ファイル位置表示子のファイル先頭からのバイト数を求める(fgetpos)

これらを使い下記方法にてファイルに記録されているデータのバイト数を調べることができます。
a.ファイル位置表示子を最後尾へ移動する(SEEK_END)
b.ファイル位置表示子のファイル先頭からのバイト数を求める
c.ファイル位置表示子を最後尾へ移動する(SEEK_SET)

データ1つのバイト数は、sizeof(struct tm)+sizeof(double)で計算できますので、b.で求めた値をこの値で割ればデータの数になります。

この処理は、printf("\n過去の履歴のコピー\n-------------------------- \n");文の直前が良いです。

3.次にmallocでメモリを獲得します
下記イメージです。

#define SIZE (sizeof(struct tm)+sizeof(double))      //A 
best_ten = (BEST_TEN *)malloc(データ数*SIZE);          //B
plst= (BEST_TEN **)malloc(データ数*sizeof(BEST_TEN *));//C


A, B, Cは適切な位置へ置いて下さい。
AはNDATAを#defineしている付近が良いです。
Bは2.でデータ数を求めた直後に置く必要があります。
CはBEST_TEN *plst[NDATA];BEST_TEN **plst;の直後に置く必要があります。

以上で基本的な処理は終わりです。
既に作られている部分は上記の提案部分以外は修正不要な筈です。

4.後始末
malloc等で獲得したメモリは解放する必要が有ります。
そのために、main()の最後に下記を記述して下さい。

free(best_ten );
free(plst);


5.エラー処理
mallocでデータを獲得できなかった時は、NULLが返ってきます。この時、獲得したかったメモリを使おうとするとプログラムが落ちます。ですので、そのエラー処理を書いておくことが推奨されますが、趣味のプログラムでしたら不要です。できることは、プログラムを終了させることしかありませんので。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/02 07:41

    おはようございます。
    「best_tenをmallocで確保して」可変個のデータに対応したいです。
    カウントで何とか対応したのですが、NDATAというのがありましたので、
    それをうまく使えるようにしたいです。
    最初の定義で設定できていないので、countを使いましたが、ここにNDATAを
    つかいたいのですが。mallocをどこでつかい、
    どうすればいいか教えてください。mallocは使ったことがあります。

    キャンセル

  • 2016/02/02 08:48

    なるほど。

    現在の姿は、NDATAが処理できる最大のデータ数で、countが実際にLACKNUM.DATに記録されているデータの数になっています。
    そして、NDATAを超える数を読みこませようとすると落ちますね。
    この問題に対処する方法に、処理したいデータの数の記録領域をmallocで獲得する方法があります。
    その方法を回答へ追記します。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    4654questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。