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

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

ただいまの
回答率

90.34%

  • C

    3988questions

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

過去のbestten を表示したいが表示はされるが完全な順序になっていない。

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 313

sanchu52

score 142

実行結果が時間の短い順になっていない。大体は時間順になっています。
どこを直せばいいでしょうか。c言語でかいています。
構造体の定義や、名前のわかりにくさがありますが、とりあえずこれで正常に
うごくようにしてから、コードの修正をかんがえています。
もう何回も挑戦してここまでプログラムをつくりました。
前回作って正常に動くと思っていたのですが、ちゃんと動いていないことがわかり
苦戦しています(1か月くらい)。よろしくお願いします。

c言語
/* ラックナンバーサーチ・トレーニング(過去の履歴と最短時間の表示)*/

#include <stdio.h>
#include <time.h>
#include <float.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/types.h> 
#include <unistd.h>
#include "getputch.h"

#define MAX_STAGE    3
#define swap(type, x, y)    do { type t = x; x = y; y = t; } while (0)
#define MAX_NUM         10

char dtfile[]  = "LACKNUM.DAT";
char dtfile2[] = "LACKNUM2.DAT";/* 最高記録用のファイル */

typedef struct {
    int tm_year;        
    int tm_mon;      
    int tm_mday;        
    int tm_hour;        
    int tm_min;      
    int tm_sec; 
    double score;   
} BEST_TEN;

// --------------- 比較用の関数 cmp -------------------
int cmpptr( const void *p, const void *q ) {
    return (*(BEST_TEN**)p)->score - (*(BEST_TEN**)q)->score;
}
// ----------------------------------------------------

/*--- 過去のトレーニング情報を取得・表示して最高得点を返す ---*/
double get_data(int *count)
{
    FILE *fp;            // これまでの履歴を指すポインタ 
    FILE *fp2;            // これまでの最短所要時間を指すポインタ 
    double score;        //これまでの履歴の所要時間
    double bestscore;   //これまでの最短所要時間
    int i,j=0;
    BEST_TEN best_ten[100]={0};

    if ((fp = fopen(dtfile, "rb")) == NULL) {
        printf("ファイルを作成します。\n\n");
        bestscore = DBL_MAX;  /* float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX */
    } else {

        struct tm local;
        double line[256];

        printf("\n過去の履歴\n-------------------------- \n");

        while((i = fread(&local, sizeof(struct tm), 1, fp)) > 0 ){
             printf("%d年 %d月 %d日 %d時 %d分 %d秒\n",
                 local.tm_year + 1900, local.tm_mon + 1,
                 local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
             fread(&score, sizeof(double), 1, fp);
             printf("得点(所要時間)は%.1f秒\n\n", score);

            best_ten[j].tm_year=local.tm_year;
             best_ten[j].tm_mon=local.tm_mon;
             best_ten[j].tm_mday=local.tm_mday;
             best_ten[j].tm_hour=local.tm_hour;
             best_ten[j].tm_min=local.tm_min;
             best_ten[j].tm_sec=local.tm_sec;
             best_ten[j].score=score;
             j++;
             (*count)++;
        }
       printf("count1は%d\n\n", *count);  
    } 
    BEST_TEN *plst[*count];
    for( i = 0; i < *count; i++ ) plst[i] = &best_ten[i];

    //qsort(配列名, 配列の数, 配列一つのバイト数, 比較関数)
    qsort( plst, *count, sizeof(BEST_TEN*), cmpptr );


        printf("\n過去のbestten\n-------------------------- \n");    
    // 並べ替え後の内容を表示
    for(i=0;i<10;i++){
        printf( "%d年 %d月 %d日 %d時 %d分 %d秒 \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]->score);
    }
    bestscore=plst[0]->score;
    fflush(stdout);
    fclose(fp);      
    printf("count2は%d\n\n", *count);  
    return bestscore;
}


int main(void)
{
    int       count=0;            //  
    double score;            // 今回の所要時間 
    double bestscore;        // 最短所要時間 
    double    jikan;            // 時間
    FILE *fp;

    struct tm local ;
    int k;
    int     i, j, x, stage;
    bestscore= get_data(&count);    // get_data()で前回までの最短所要時間を
                                    // ファイルから読み込んでbestscoreに代入する。 
    printf("bestscoreは%.1f\n\n", bestscore); 
    printf("count3は%d\n\n", count);                         

    return 0;

}                        

    
/*

C:\MinGW\users\chap09\kadai>gcc -I. -o kadai9-1-6 kadai9-1-6.c pdcurs
es.a

C:\MinGW\users\chap09\kadai>kadai9-1-5

過去の履歴

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

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

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

省略

count1は66

過去のbestten

2017年 8月 14日 20時 57分 40秒
得点(所要時間)は 6.0秒です。

2017年 9月 9日 12時 14分 36秒
得点(所要時間)は 6.2秒です。

2016年 5月 2日 17時 0分 48秒
得点(所要時間)は 7.0秒です。

2017年 9月 9日 12時 3分 5秒
得点(所要時間)は 6.1秒です。//ここがおかしい

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

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

2017年 9月 9日 12時 4分 2秒 
得点(所要時間)は 7.5秒です。//ここがおかしい

2017年 9月 9日 12時 38分 12秒
得点(所要時間)は 8.0秒です。

2016年 1月 31日 21時 12分 13秒
得点(所要時間)は 8.0秒です。

2017年 9月 9日 11時 28分 59秒
得点(所要時間)は 8.0秒です。

count2は66

bestscoreは6.0

count3は66

C:\MinGW\users\chap09\kadai>
*/

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • sanchu52

    2017/09/11 16:11

    ご指摘ありがとうございます。コードの上は私が使っている言語を書くのでしょうか?質問文はどこに書くのでしょうか?ヘルプを探したのですがよくわかりませんでした。ご迷惑かけてすみません。

    キャンセル

  • PineMatsu

    2017/09/11 17:20

    コードは```~```の間に書きます。質問はその外側に書けばOKです。

    キャンセル

  • sanchu52

    2017/09/12 20:52

    へんじありがとございます。説明文とコードを書く場所、使っている言語を書くところなど2年使っていてやっとわかりました。

    キャンセル

回答 1

0

すみません、これは直接的な回答ではないのですが...
修正依頼欄では伝えきれないので、こちらに書かせていただきます。

他人が書いたコードを読むのには、かなりの労力が要ります。
なるべく読みやすいコードを心掛けてください。後から読み返すときにも有用です。


例えば、これ。何回も使ってますよね。

typedef struct {
    int tm_year;        
    int tm_mon;      
    int tm_mday;        
    int tm_hour;        
    int tm_min;      
    int tm_sec; 
    double score;   
} BEST_TEN;

次のように書き換えたり、専用の関数を充実させると、かなり読みやすくなります。

typedef struct tm TIME_DATA;

typedef struct {
    TIME_DATA time;
    double score;
} SCORE_DATA;

size_t fread_score_data(SCORE_DATA *score_data, FILE *fp) {
    return fread(&score_data->time,  sizeof(TIME_DATA), 1, fp)
        && fread(&score_data->score, sizeof(double),    1, fp);
}
void print_score_data(SCORE_DATA *score_data) {
    printf( "%d年 %d月 %d日 %d時 %d分 %d秒 \n",
        score_data->time.tm_year  + 1900,
        score_data->time.tm_month + 1,
        score_data->time.tm_day,
        score_data->time.tm_hour,
        score_data->time.tm_min,
        score_data->time.tm_sec
    );
    printf("得点(所要時間)は %.1f秒です。\n\n",
        score_data->score
    );
}
double get_score(SCORE_DATA *score_data) {
    return score_data->score;
}

書き換えた理由

  • BEST_TENって名前は不適。これを10個集めて初めてベスト10になるはず。
  • せっかくtime.hをインクルードしているんだから、使えるものは使う。
    私は詳しく知りませんが、使えそうな関数もあるかもしれません。
  • とにかく抽象化。同じコードを二回書いたら関数化を検討しましょう。

while((i = fread(&local, sizeof(struct tm), 1, fp)) > 0 ){
    ...
    j++;
}

こんな感じにも書けます。

for(j = 0; fread(&local, sizeof(struct tm), 1, fp) > 0; j++) {
    ...
}

書き換えた理由

  • jが毎ループ増えていくイメージが掴みやすいです。

あとは、変数の名前がわかりづらいです。

BEST_TEN *plst[*count];

...plst? なんの略称でしょうか。


他にもいろいろありそうですが、読みやすいコードを書くことを意識してください。
質問の際もすんなり伝わるようになりますし、バグも減ります。

あとは... 再現できるような情報をください。
xxxxx.datファイルを用いていることはわかりますが、その内部の構造がわかりません。
そのまま使えるものを提示してもらえるのが一番早いです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/12 14:57

    色々教えていただきありがとうございます。コードをご指南のとおり修正して試してみます。
    そのあとまたおねがいいたします。

    キャンセル

  • 2017/09/12 19:19

    LouiS0616さん指摘を受けていろいろやってみたのですが、このコードで過去の履歴は正常に表示されます。このままで実行時間の短い順に10個表示したいのですが、どこか順番にならないところがあります。
    これが正常に表示されてから、コードの修正をしたいと思っています。よろしくお願いします。

    キャンセル

  • 2017/09/12 23:38

    ここから、https://teratail.com/questions/92144に移っていくわけですね。
    なんというか、難しく考えすぎな気がします。
    私の書いたサンプルは、まあデバッグしてないので不具合があるかもわかりませんが、役割を絞ることを意識して作っています。
    一度汎用的な関数を定義してしまえば、あたかも最初から存在する機能かのように使ってしまえばいいんです。

    キャンセル

  • 2017/09/12 23:41

    問題を段階に分けて考えてください。
    ・まず、ファイルからスコアとその時刻データ(SCORE_DATA)を読み取る関数を作ってください。そして、問題がなくなるまでテストしてください。
    ・次に、読み取った複数のSCORE_DATAを、目的に沿うような順にソートする関数を作ってください。そして、問題がなくなるまでテストしてください。
    ・最後に、その中からベストテンを選び出し、情報を出力する機能を作ってください。そして、問題がなくなるまでテストしてください。
    以上、完成です。

    キャンセル

  • 2017/09/12 23:42

    コードを全部書ききってからテストするのはやめましょう。
    問題の所在が不明瞭になって、デバッグが困難になります。
    まずはここまで、次はここまで、少しずつ機能を拡張してください。

    キャンセル

  • 2017/09/13 08:32

    ありがとうございます。おっしゃる通りにやってみます。

    キャンセル

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

  • C

    3988questions

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