正常に動くプルグラムを見やすく改良したい。
具体的に教えていただければありがたいです。セグメンテーションフォルトでベスト7まで表示して停止します。173行あたりだと思うのですが、よくわかりません。
"getputch.h"をお知らせしたいのですが文字数がオーバーします。どうすれば送れますか?
コード // ラックナンバーサーチ・トレーニング // 過去の履歴とそれらの実行日時,実行時間 // 過去のbesttenの実行日時,実行時間 // 最近の10回の実行日時,実行時間 #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 --- static int cmpptr( const void *p, const void *q ) { return (*(BEST_TEN**)p)->score - (*(BEST_TEN**)q)->score; } //1回実行したとき進むポイントの大きさを求める static int get_point_offset(fpos_t* offset) { FILE *fp; struct tm local; double score; fp=fopen(dtfile, "rb"); if(fp==NULL) { perror("fopen"); return -1; } if(fread(&local, sizeof(struct tm), 1, fp)<0) { perror("fread"); fclose(fp); return -1; } if(fread(&score, sizeof(double), 1, fp)<0) { perror("fread"); fclose(fp); return -1; } //ファイルポインタのfp位置を取得 if(fgetpos(fp, offset)!=0) { perror("fgetpos"); fclose(fp); return -1; } fclose(fp); //offsetの示す場所に格納します。 printf("ファイルポインタの位置offsetは「%d」です。\n", *offset); return 0; } //local のデータを新しい順にならべる。 static void update_local_data(fpos_t ft,int k) { FILE *fp; // これまでの履歴を指すポインタ double score; //これまでの履歴の所要時間 int i; struct tm local; //構造体変数 localの大きさ if((fp = fopen(dtfile,"rb"))==NULL) { printf("ファイルを作成します。\n\n"); bestscore=DBL_MAX; // float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX return; } printf("最近の10回の点数とそれらの実行日時は\n\n"); for(i = ft - k; i >= ft - 10 * k; i -= k) { //構造体変数 localの大きさoffsetで44 if(fseek(fp, i, SEEK_SET) != 0) { //ファイルポインタを先頭からiまで移動 perror("fseek"); break; } if(fread(&local, sizeof(struct tm), 1, fp) < 0) { perror("fread"); break; } 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); if(fread(&score, sizeof(double), 1, fp) < 0) { perror("fread"); break; } printf("得点(所要時間)は%.1f秒\n\n", score); } fclose(fp); printf("enterキーで開始します。\n"); fflush(stdout); getchar(); } //過去のトレーニング情報を取得・表示して最高得点を返す static double get_data(int *count) { FILE *fp; //これまでの履歴を指すポインタ double score; //これまでの履歴の所要時間 double bestscore; //これまでの最短所要時間 int i,j=0; BEST_TEN best_ten[100]={0}; BEST_TEN *plst[*count]; struct tm local; if((fp = fopen(dtfile, "rb"))==NULL) { printf("ファイルを作成します。\n\n"); bestscore = DBL_MAX; // float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX return 0.0; } 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); for(i=0; i < *count; i++) plst[i]=&best_ten[i]; //qsort(配列名, 配列の数, 配列一つのバイト数, 比較関数) qsort(plst, *count, sizeof(BEST_TEN*), cmpptr); printf("\n過去のscoreのbestscore10個\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; } //今回のトレーニング情報を書き込む static int put_data(double score, double bestscore) { FILE *fp; //fpはfopenされたdtfileを指すポインタ FILE *fp2; //fp2はfopenされたdtfile2を指すポインタ、最短時間が格納されている time_t t = time(NULL); struct tm *local = localtime(&t); time(&t); local = localtime(&t); if((fp = fopen(dtfile, "ab"))==NULL) { printf("ファイルがありません"); fflush(stdout); return -1; } if(fwrite(local, sizeof(struct tm), 1, fp)!=0) { perror("fwrite"); fclose(fp); return -1; } if(fwrite(&score, sizeof(double), 1, fp)!=0) { perror("fwrite"); fclose(fp); return -1; } fclose(fp); if(score > bestscore) { return 0; } if((fp2 = fopen(dtfile2, "wb"))==NULL) { printf("ファイルがありません"); fflush(stdout); return -1; } if(fwrite(local, sizeof(struct tm), 1, fp2)!=0) { perror("fwrite"); fclose(fp); return -1; } if (fwrite(&bestscore, sizeof(double), 1, fp2)!=0) { //fpに書き込む perror("fwrite"); fclose(fp); return -1; } fclose(fp2); return 0; } //トレーニングを実行して得点(所要時間)を返す static double do_training(void) { int i, j, stage; int dgt[9]={1, 2, 3, 4, 5, 6, 7, 8, 9}; int a[8]; double jikan; // 時間 clock_t start, end; // 開始時刻・終了時刻 printf("\n\n欠けている数字を入力してください。\n"); printf("スペースキーで開始します。\n"); while(getch()!=' ') ; start=time(NULL); for(stage=0; stage < MAX_STAGE; stage++) { int x=rand() % 9; // 0~8の乱数を発生 ,1から9までのうち8文字を表示するための数字 int no; // 読み込んだ値 ,キーボードから打ち込んだ数字 i=j=0; // dgt[x]を飛ばしてコピー while (i<9){ if (i!=x) a[j++]=dgt[i]; // dgt[x]は1から9までの数字が入っている配列 i++; } for(i=7; i>0; i--) { // 配列aをシャッフル、配列の添字は0から7までの8個である int j=rand()%(i + 1); //jは1から7まで変化する。 if(i!=j) swap(int, a[i], a[j]); //iとjの添字でシャッフルする。 } printf("%d回目:", stage+1); // 全要素を表示 for(i=0; i<8; i++) { printf("%d ", a[i]); } printf(":"); fflush(stdout); do{ no=getch(); if(isprint(no)){ // 表示可能であれば putch(no); // 押されたキーを表示 if(no!=dgt[x] + '0') // 正解でなければ putch('\b'); // カーソルを一つ戻す else printf("\n"); // 改行 } }while(no!=dgt[x] + '0'); } end=time(NULL); jikan=(double)difftime(end, start); printf("%.1f秒かかりました。\n", jikan); if(jikan>25.0) printf("鈍すぎます。\n"); else if(jikan > 20.0) printf("少し鈍いですね。\n"); else if(jikan > 17.0) printf("まあまあですね。\n"); else printf("素早いですね。\n"); return jikan; } int main(void) { int retry, count=0; // もう一度? double score; // 今回の所要時間 double bestscore; // 最短所要時間 //double jikan; // 時間 FILE *fp; fpos_t ft; fpos_t offset; int k; // get_data()で前回までの最短所要時間をbest2に格納する。 bestscore=get_data(&count); // ファイルから読み込んでbestに代入する。 printf("bestscoreは%.1f\n\n", bestscore); printf("count3は%d\n\n", count); fp=fopen(dtfile, "rb"); if(fp==NULL) { perror("fopen"); return -1; } if (get_point_offset(&offset)!=0) { return -1; } k=offset; //ファイルポインタの位置を取得 printf("mainのget_point_offset(&offset)後のkの値は「%d」です。\n\n", k); //ファイルポインタを末尾まで移動 if (fseek(fp, 0, SEEK_END)!=0) { perror("fseek"); return -1; } //ファイルポインタの位置を取得 //ファイルfpの現在のファイル位置を取得して if (fgetpos(fp, &ft)!=0) { perror("fgetpos"); fclose(fp); return -1; } // &ftの示す場所に格納します。 update_local_data(ft, k); if(fgetpos(fp, &ft)!=0) { perror("fgetpos"); return -1; } fclose(fp); //best = get_data(ft); // get_data()で前回までの最短所要時間を //ファイルから読み込んでbestに代入する。 //ライブラリの初期処理235p、initscr(),cbreak(),noecho(),refresh() init_getputch(); // 乱数の種を初期化 srand(time(NULL)); do{ // トレーニング(do_training)で実行、返却された所要時間(jika)を // scoreに代入する。 score=do_training(); if(score < bestscore){ printf("最短所要時間を更新しました!!\n"); // 最高得点更新 bestscore=score; } printf("もう一度しますか … (0)いいえ (1)はい:"); retry=0; scanf("%d", &retry); } while (retry==1); // 今回の日付・時刻・得点を書き込む put_data(score,bestscore); fflush(stdout); //ライブラリの初期処理235p,endwin() term_getputch(); return 0;
どんな立場の人にとっての「見やすさ」なのですか?
ちなみに、プルグラムでなくプログラムです。
#include "getputch.h"って何ですか? コードの一部を別のソースファイルに移して、本体のソースコードを簡素化するのもアリなんですか?
Stripeさんありがとうございます。おっしゃることはわかるのですが、それができなくてこまっています。struct tmを日付とbestにわけたり、bestをわかり易い名前scoreに変更して、書きなおしてやってみたのですが、うまく分割、整理ができません。分割したときのmainもいまいちよく書けません。
一応動くのですが、名前、ソースコードの簡素化、無駄なコード、エラー処理の追加などを関数ごとにテストしたいのですが、そのときのmain関数もおねがいします。
今夜仕事なので、明日いただいたコードを参考に修正に挑戦したいとおもいます。ありがとうございます。いろいろ指摘いただき恥しいかぎりです。初心者で申し訳ありません。趣味で、独学です。