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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

3回答

307閲覧

プログラムを見やすく改良したい

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2017/09/13 05:36

編集2017/09/15 02:40

正常に動くプルグラムを見やすく改良したい。
具体的に教えていただければありがたいです。セグメンテーションフォルトでベスト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;

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coco_bauer

2017/09/13 05:54

どんな立場の人にとっての「見やすさ」なのですか?
mattn

2017/09/13 07:50

ちなみに、プルグラムでなくプログラムです。
Stripe

2017/09/13 13:39

#include "getputch.h"って何ですか? コードの一部を別のソースファイルに移して、本体のソースコードを簡素化するのもアリなんですか?
退会済みユーザー

退会済みユーザー

2017/09/14 00:13

Stripeさんありがとうございます。おっしゃることはわかるのですが、それができなくてこまっています。struct tmを日付とbestにわけたり、bestをわかり易い名前scoreに変更して、書きなおしてやってみたのですが、うまく分割、整理ができません。分割したときのmainもいまいちよく書けません。
退会済みユーザー

退会済みユーザー

2017/09/14 00:48

一応動くのですが、名前、ソースコードの簡素化、無駄なコード、エラー処理の追加などを関数ごとにテストしたいのですが、そのときのmain関数もおねがいします。
退会済みユーザー

退会済みユーザー

2017/09/14 00:54

今夜仕事なので、明日いただいたコードを参考に修正に挑戦したいとおもいます。ありがとうございます。いろいろ指摘いただき恥しいかぎりです。初心者で申し訳ありません。趣味で、独学です。
guest

回答3

0

気にかかった点を列挙させてもらいます。

1)データ型に気を掛けて

// --------------- 比較用の関数 cmp ------------------- int kaime_p(fpos_t* kaime_p1) { //途中のコードは割愛しました。 return *kaime_p1; }

例えば、関数kaime_pの返り値の型はintであると定義されています。返り値は、kaime_p1です(return kaime_p;)から、変数kaime_p1の型は int であるはずです。ところが、引数のkaime_p1の型宣言は fpos_t となっています。残念ながら、コードにはfpos_tの定義が含まれていません(たぶん、"getputch.h"で定義されているのでしょうが)から、どのようにすれば正しい記述になるのかが判りません。

このように型に整合性がないと、コードが判りにくくなります(私が監督者なら、コーディングミスとして差し戻すところ)
また、fpos_tという型はコードの各所で使われていますから、intと分ける必要性をちゃんと説明すべきです。fpos_tが何のための型なのかが判っていると、intとfpos_tを使い分けている箇所のプログラマの意図が察せされるのでコードの理解がしやすくなる可能性があります。

標準ではないinclude(#include <...>ではなく、#include "..."でインクルードされている)で定義されている型については、簡単で良いので、それぞれの説明をコードの初めに近い場所でしておくと読みやすいコードになります。特に名前が似た型が定義されている場合や、インクルードされているファイルが多い場合に有効です。

2)下手な英語もどきより、ローマ字で命名
英語で適切な名前を考えるのはハードルが高いですから、誰でも読めるローマ字を使いましょう。
dtfile[],dtfile2[]よりfileMei_KakoKiroku[],fileMei_saikoKiroku[]のほうがましでしょ。
go()よりkaitouJikanSokutei()のほうが、ラックナンバーサーチの回答時間を測定する関数だと判り易い でしょ。

3)バイナリファイルを使う必要がありますか?
質問のコードを読みにくくしているのは、バイナリファイルを使っている事が一因だと思います。
CSV形式のテキストファイルなら、readlineで1レコード(1行)読出して、splitで分割というように何をしているのかが判り易いですが、バイナリファイルだとsizeofで読みだすバイト数を求めて等々面倒な記述(読みにくい記述)が避けられませんし、動作が直観的ではありません。
テキストファイルからメモリに一気に読出し、メモリ上で処理して、最後に結果を書き戻すというやりかただとファイルとのやり取りをほとんど意識しなくて済みます。また、デバッグ時にファイルの内容が簡単に確認できるというメリットもあります。(バイナリファイルの内容を確認するのは、面倒です)

投稿2017/09/14 02:11

coco_bauer

総合スコア6915

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ゲームを実行する機能だけ作っても、これくらい複雑になりました。
...私のコードにも粗があるかと思います。参考程度によろしくお願いします。

C

1/* main.c */ 2#include "score_datum.h" 3#include "training.h" 4 5#include <stdio.h> 6 7int main(void) { 8 SCORE_DATUM score_datum; 9 do_training(&score_datum, DEFAULT_STAGE_NUM); 10 print_score_datum(&score_datum); 11 12 return 0; 13}

C

1/* score_datum.h */ 2#ifndef INCLUDED_SCORE_DATUM 3#define INCLUDED_SCORE_DATUM 4 5#include <time.h> 6 7typedef struct tm TIME_DATUM; 8 9typedef struct { 10 TIME_DATUM time_datum_; 11 double score_; 12 13} SCORE_DATUM; 14 15TIME_DATUM * get_time_datum(SCORE_DATUM *); 16double get_score(SCORE_DATUM *); 17 18void set_score_datum(SCORE_DATUM *dst, double); 19void print_score_datum(SCORE_DATUM *); 20 21#endif

C

1/* score_datum.c */ 2#include "score_datum.h" 3 4#include <stdio.h> 5#include <time.h> 6 7#define BUF_SIZE 128 8 9TIME_DATUM * get_time_datum(SCORE_DATUM *datum) { 10 return &datum->time_datum_; 11} 12double get_score(SCORE_DATUM *datum) { 13 return datum->score_; 14} 15 16void set_score_datum(SCORE_DATUM *dst, double score) { 17 time_t tmp_time; 18 time(&tmp_time); 19 20 dst->time_datum_ = *localtime(&tmp_time); 21 dst->score_ = score; 22} 23 24void print_score_datum(SCORE_DATUM *datum) { 25 char time_buffer[BUF_SIZE]; 26 strftime( 27 time_buffer, BUF_SIZE, 28 "%Y/%m/%d %H:%M:%S", 29 get_time_datum(datum) 30 ); 31 32 printf("%s : SCORE %.1f\n", time_buffer, get_score(datum)); 33}

C

1/* training.h */ 2#ifndef INCLUDED_TRAINING 3#define INCLUDED_TRAINING 4 5#define DEFAULT_STAGE_NUM 3 6double do_training(SCORE_DATUM *result, int stage_num); 7 8#endif

C

1/* training.c */ 2#include "my_util.h" 3#include "score_datum.h" 4#include "training.h" 5 6#include <stdio.h> 7#include <stdlib.h> 8#include <time.h> 9 10void do_one_stage(void); 11int *make_lack_array(int [], size_t, int [], size_t, int); 12 13#define NUM_LENGTH 9 14 15double do_training(SCORE_DATUM *result, int stage_num) { 16 clock_t start_time, end_time; 17 double elapsed_time; 18 19 srand(time(NULL)); 20 21 printf("\n\n"); 22 printf("Input lacked number.\n"); 23 printf("Press space key to start game.\n"); 24 25 wait_key_input(' '); 26 start_time = clock(); 27 28 for(int i = 0; i < stage_num; i++) { 29 do_one_stage(); 30 } 31 32 end_time = clock(); 33 elapsed_time = difftime_precise(end_time, start_time); 34 35 set_score_datum(result, elapsed_time); 36 return elapsed_time; 37} 38void do_one_stage(void) { 39 int complete_array[NUM_LENGTH]; 40 for(size_t i = 0; i < NUM_LENGTH; i++) { 41 complete_array[i] = i + 1; 42 } 43 44 int lacked_number = rand() % NUM_LENGTH + 1; 45 int lacked_array[NUM_LENGTH - 1]; 46 47 int *result = make_lack_array( 48 complete_array, ARRAY_LEN(complete_array), 49 lacked_array, ARRAY_LEN(lacked_array), 50 lacked_number 51 ); 52 if(result == NULL) { 53 perror("make_lack_array"); 54 exit(EXIT_FAILURE); 55 } 56 57 print_array(lacked_array, ARRAY_LEN(lacked_array)); 58 59 int input_num; 60 do { 61 input_num = input_int(); 62 63 } while(input_num != lacked_number); 64 65 printf("Correct.\n\n"); 66} 67 68// 69// 70int count_num_in_array(int array[], size_t size, int num) { 71 int count = 0; 72 for(size_t i = 0; i < size; i++) { 73 if(array[i] == num) count++; 74 } 75 return count; 76} 77int *make_lack_array(int src_array[], size_t src_size, 78 int dst_array[], size_t dst_size, int lack_num) { 79 80 if(src_size - 1 > dst_size) { 81 return NULL; 82 } 83 if(count_num_in_array(src_array, src_size, lack_num) != 1) { 84 return NULL; 85 } 86 87 for(size_t i = 0, j = 0; i < src_size; i++) { 88 if(src_array[i] == lack_num) { 89 continue; 90 } 91 dst_array[j] = src_array[i]; 92 j++; 93 } 94 return dst_array; 95}

C

1/* my_util.h */ 2#ifndef INCLUDED_MY_UTIL 3#define INCLUDED_MY_UTIL 4 5#include <stdlib.h> 6#include <time.h> 7 8#define SWAP(type, a, b) \ 9 do { \ 10 type tmp = a; a = b; b = tmp; \ 11 } while(0) 12 13#define ARRAY_LEN(array) \ 14 sizeof(array) / sizeof(array[0]) 15 16#define WAIT_ANY_KEY -1 17void wait_key_input(char); 18int input_int(void); 19 20void shuffle_array(int [], size_t); 21void print_array(int [], size_t); 22double difftime_precise(time_t, time_t); 23 24#endif

C

1/* my_util.c */ 2#include "my_util.h" 3#include <stdio.h> 4#include <stdlib.h> 5#include <time.h> 6 7int input_int(void) { 8 int ret; 9 10 char buffer[10]; 11 if(fgets(buffer, sizeof(buffer), stdin) != NULL) { 12 ret = atoi(buffer); 13 } 14 else { 15 perror("input_int"); 16 exit(EXIT_FAILURE); 17 } 18 19 return ret; 20} 21void wait_key_input(char key) { 22 if(key == WAIT_ANY_KEY) { 23 getchar(); 24 return; 25 } 26 27 while(getchar() != key); 28} 29 30void shuffle_array(int array[], size_t size) { 31 for(size_t i = 0; i < size; i++) { 32 int rand_index = rand() % size; 33 SWAP(int, array[i], array[rand_index]); 34 } 35} 36void print_array(int array[], size_t size) { 37 for(size_t i = 0; i < size; i++) { 38 printf("%d ", array[i]); 39 } 40 printf("\n"); 41} 42double difftime_precise(time_t time2, time_t time1) { 43 return (double)(time2 - time1) / CLOCKS_PER_SEC; 44}

実行例

Input lacked number. Press space key to start game. 1 2 3 4 5 7 8 9 6 Correct. 1 2 3 4 5 7 8 9 6 Correct. 1 2 3 4 5 6 7 9 9 8 Correct. 2017/09/14 12:01:40 : SCORE 7.6

ランキング機能を付けると、ファイル入出力が絡むだけもっと複雑になります。

追記

だいたい同じようなゲームを、Pythonでも実装してみました。

Python

1# main.py 2 3from score_datum import ScoreDatum 4from training import do_training 5 6def main(): 7 now_score_datum = do_training() 8 now_score_datum.print_info() 9 10if __name__ == '__main__': 11 main()

Python

1# score_datum.py 2 3import datetime 4 5 6class ScoreDatum(): 7 def __init__(self, score: float): 8 self._time_datum = datetime.datetime.today() 9 self._score = score 10 11 @property 12 def time_datum(self) -> datetime.datetime: 13 return self._time_datum 14 15 @property 16 def score(self) -> float: 17 return self._score 18 19 def print_info(self) -> None: 20 print(self.time_datum.ctime(), round(self.score, ndigits=1))

Python

1# training.py 2 3from score_datum import ScoreDatum 4from my_util import wait_key_input 5import random 6import time 7 8NUM_LENGTH = 9 9 10def do_training(stage_num: int = 3): 11 print() 12 print('Input lacked number.') 13 print('Press space key to start game.') 14 wait_key_input(' ') 15 16 start_time = time.time() 17 for _ in range(stage_num): 18 do_one_stage() 19 20 elapsed_time = time.time() - start_time 21 return ScoreDatum(elapsed_time) 22 23def do_one_stage() -> None: 24 complete_list = list(range(NUM_LENGTH + 1))[1:] 25 26 lacked_number = random.randint(1, NUM_LENGTH) 27 lacked_list = _make_lack_list(complete_list, lacked_number) 28 29 print(lacked_list) 30 while True: 31 try: 32 input_num = int(input()) 33 except: 34 continue 35 36 if input_num == lacked_number: 37 break 38 39 print('Correct.') 40 print() 41 42def _count_num_in_list(src_list: list, num: int) -> int: 43 return src_list.count(num) 44 45def _make_lack_list(src_list: list, lack_num: int) -> list: 46 if _count_num_in_list(src_list, lack_num) != 1: 47 return None 48 49 src_list.remove(lack_num) 50 return src_list

Python

1# my_util.py 2 3def wait_key_input(key: str = None) -> None: 4 if key is None: 5 input() 6 return 7 8 while input() != key: 9 pass 10

実行例

Input lacked number. Press space key to start game. [1, 2, 4, 5, 6, 7, 8, 9] 3 Correct. [1, 2, 3, 4, 5, 7, 8, 9] 6 Correct. [1, 2, 3, 4, 5, 6, 8, 9] 6 7 Correct. Thu Sep 14 13:39:56 2017 5.6

リスト処理が楽なのは嬉しいですね。
文字数でカウントすると、Cの場合の約40%で実装出来ました。

投稿2017/09/14 03:05

編集2017/09/14 04:40
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/09/15 03:47

LouiS0616さんありがとうございます。端末にはどのように実行するのですか。リンクの仕方がよくわかりません。随分前にやったことあるのですが、課題1個やるのに時間がかかりすぎて、前に進めません。よろしくお願いします。
LouiS0616

2017/09/15 03:51

gcc main.c score_datum.c training.c my_util.c でいけますよ。
退会済みユーザー

退会済みユーザー

2017/09/15 04:32

LouiS0616さん実行できました。分割ファイルの実行の復習もできてありがとうございました。甚だずうずうしいお願いなのですが、今日コードの書き直しをしたところ、説明文にあるような結果になり、困っています。最初のコードは保存してあるので、なんとかはなるのですが、ひどいコードを書いていたものだとおもっています。更新したプログラムのどこが悪いのでしょうか。よろしくおねがいします。
LouiS0616

2017/09/15 06:01

BEST_TEN *plst[*count]; ポインタ変数をcount数分しか確保していないのに、 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); } 毎回plst[9]まで参照しているからじゃないですかね。
LouiS0616

2017/09/15 06:02

エラーを一つ一つ潰せばいつか動くとは思いますが、ただそれだけです。 後から読み返したらもう理解できないでしょうし、機能追加なんて検討しようものなら地獄です。 全体の設計を見直した方がいいと思います。
退会済みユーザー

退会済みユーザー

2017/09/15 06:59

ありがとうございます。やってみます。
退会済みユーザー

退会済みユーザー

2017/09/15 07:03

plst[i]は整列した後の実行時間の順になっているので10個短い順にひろっているだけです。
退会済みユーザー

退会済みユーザー

2017/09/15 07:04

今日夜勤で寝ていないので、明日朝からプログラムをチェックする予定です。 ありがとうございます。
guest

0

見やすい見やすくないは個人差があるので、この回答が全て正しいとは思いません。

以下、見づらいなと思った理由です。

不定な位置のコメント

右付きだったり上付きだったり。

統一されていないスタイル

  • if の後の空白
  • for の中の空白
  • = の前後の空白

統一されていないエラー処理

エラー処理があったりなかったり。

明瞭でない関数名

関数名の意味が見ただけで分からない。

early return になってない

処理を中断しているのでもう return してよいのにしていない。

おまけ

気になった箇所だけ書き換えてみました。エラー処理を追加しているので処理の流れが変わってしまっていたらすみません。

見ただけで意味が伝わりにくい関数名について直そうと思いましたが、良く分からないので断念しました。

c

1// ラックナンバーサーチ・トレーニング 2// 過去の履歴とそれらの実行日時,実行時間 3// 過去のbesttenの実行日時,実行時間 4// 最近の10回の実行日時,実行時間 5#include <stdio.h> 6#include <time.h> 7#include <float.h> 8#include <ctype.h> 9#include <stdlib.h> 10#include <sys/types.h> 11#include <unistd.h> 12#include "getputch.h" 13 14#define MAX_STAGE 3 15#define swap(type, x, y) do { type t = x; x = y; y = t; } while (0) 16#define MAX_NUM 10 17 18char dtfile[] = "LACKNUM.DAT"; 19char dtfile2[] = "LACKNUM2.DAT";/* 最高記録用のファイル */ 20 21typedef struct { 22 int tm_year; 23 int tm_mon; 24 int tm_mday; 25 int tm_hour; 26 int tm_min; 27 int tm_sec; 28 double best; 29} BEST_TEN; 30 31// --------------- 比較用の関数 cmp ------------------- 32static int 33cmpptr( const void *p, const void *q ) { 34 return (*(BEST_TEN**)p)->best - (*(BEST_TEN**)q)->best; 35} 36// ---------------------------------------------------- 37 38//1回実行したとき進むポイントの大きさを求める 39 40static int 41get_point_offset(fpos_t* offset) { 42 FILE *fp; 43 struct tm local; 44 double best; 45 46 fp = fopen(dtfile, "rb"); 47 if (fp == NULL) { 48 perror("fopen"); 49 return -1; 50 } 51 52 if (fread(&local, sizeof(struct tm), 1, fp) < 0) { 53 perror("fread"); 54 fclose(fp); 55 return -1; 56 } 57 58 if (fread(&best, sizeof(double), 1, fp) < 0) { 59 perror("fread"); 60 fclose(fp); 61 return -1; 62 } 63 64 //ファイルポインタの位置を取得 65 if (fgetpos(fp, offset) != 0) { //ファイルfpの現在のファイル位置を取得して 66 perror("fgetpos"); 67 fclose(fp); 68 return -1; 69 } 70 71 fclose(fp); 72 73 // offsetの示す場所に格納します。 74 printf("ファイルポインタの位置offsetは「%d」です。\n", *offset); 75 return 0; 76} 77 78//local のデータを新しい順にならべる。 79static void 80update_local_data(fpos_t ft,int k) { 81 FILE *fp; // これまでの履歴を指すポインタ 82 FILE *fp2; // これまでの最短所要時間を指すポインタ 83 double best; //これまでの履歴の所要時間 84 double best2; //これまでの最短所要時間のベストテンも保存しておく 85 int i; 86 87 struct tm local;//構造体変数 localの大きさ 88 89 if ((fp = fopen(dtfile, "rb")) == NULL) { 90 printf("ファイルを作成します。\n\n"); 91 best = DBL_MAX; /* float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX */ 92 return; 93 } 94 95 printf("最近の10回の点数とそれらの実行日時は\n\n"); 96 for (i = ft - k; i >= ft - 10 * k; i -= k) { //構造体変数 localの大きさoffsetで44 97 //ファイルポインタを先頭からiまで移動 98 if (fseek(fp, i, SEEK_SET) != 0) { 99 perror("fseek"); 100 break; 101 } 102 103 if (fread(&local, sizeof(struct tm), 1, fp) < 0) { 104 perror("fread"); 105 break; 106 } 107 printf("%d年 %d月 %d日 %d時 %d分 %d秒\n", 108 local.tm_year + 1900, local.tm_mon + 1, 109 local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); 110 if (fread(&best, sizeof(double), 1, fp) < 0) { 111 perror("fread"); 112 break; 113 } 114 printf("得点(所要時間)は%.1f秒\n\n", best); 115 } 116 fclose(fp); 117 118 printf("enterキーで開始します。\n"); 119 fflush(stdin); 120 getchar(); 121} 122 123/*--- 過去のトレーニング情報を取得・表示して最高得点を返す ---*/ 124static double 125get_data(int *count) { 126 FILE *fp; /* これまでの履歴を指すポインタ */ 127 FILE *fp2; /* これまでの最短所要時間を指すポインタ */ 128 double best; //これまでの履歴の所要時間 129 double best2; //これまでの最短所要時間 130 int i,j=0; 131 BEST_TEN best_ten[100]={0}; 132 BEST_TEN *plst[*count]; 133 struct tm local; 134 double line[256]; 135 136 if ((fp = fopen(dtfile, "rb")) == NULL) { 137 printf("ファイルを作成します。\n\n"); 138 best = DBL_MAX; /* float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX */ 139 return 0.0; 140 } 141 142 printf("\n過去の履歴\n-------------------------- \n"); 143 144 while((i = fread(&local, sizeof(struct tm), 1, fp)) > 0 ){ 145 printf("%d年 %d月 %d日 %d時 %d分 %d秒\n", 146 local.tm_year + 1900, local.tm_mon + 1, 147 local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); 148 fread(&best, sizeof(double), 1, fp); 149 printf("得点(所要時間)は%.1f秒\n\n", best); 150 151 best_ten[j].tm_year = local.tm_year; 152 best_ten[j].tm_mon = local.tm_mon; 153 best_ten[j].tm_mday = local.tm_mday; 154 best_ten[j].tm_hour = local.tm_hour; 155 best_ten[j].tm_min = local.tm_min; 156 best_ten[j].tm_sec = local.tm_sec; 157 best_ten[j].best = best; 158 j++; 159 (*count)++; 160 } 161 printf("count1は%d\n\n", *count); 162 163 for(i = 0; i < *count; i++) 164 plst[i] = &best_ten[i]; 165 166 qsort(plst, *count, sizeof(BEST_TEN*), cmpptr); 167 168 printf("\n過去のbestten\n-------------------------- \n"); 169 170 // 並べ替え後の内容を表示 171 for (i = 0;i < 10; i++) { 172 printf("%d年 %d月 %d日 %d時 %d分 %d秒 \n" 173 ,plst[i]->tm_year+1900, plst[i]->tm_mon+1, plst[i]->tm_mday, 174 plst[i]->tm_hour,plst[i]->tm_min,plst[i]->tm_sec); 175 printf("得点(所要時間)は %.1f秒です。\n\n", plst[i]->best); 176 } 177 178 best = plst[0]->best; 179 180 fflush(stdin); 181 fclose(fp); 182 183 printf("count2は%d\n\n", *count); 184 return best; 185} 186 187/*--- 今回のトレーニング情報を書き込む ---*/ 188static int 189put_data(double best, double best2) { 190 FILE *fp; //fpはfopenされたdtfileを指すポインタ 191 FILE *fp2; //fp2はfopenされたdtfile2を指すポインタ、最短時間が格納されている 192 time_t t = time(NULL); 193 struct tm *local = localtime(&t); 194 195 time(&t); 196 local = localtime(&t); 197 if ((fp = fopen(dtfile, "ab")) == NULL) { 198 printf("ファイルがあーりません"); 199 fflush(stdout); 200 return -1; 201 } 202 203 if (fwrite(local, sizeof(struct tm), 1, fp) != 0) { //fpに書き込む 204 perror("fwrite"); 205 fclose(fp); 206 return -1; 207 } 208 209 if (fwrite(&best, sizeof(double), 1, fp) != 0) { //fpに書き込む 210 perror("fwrite"); 211 fclose(fp); 212 return -1; 213 } 214 215 fclose(fp); 216 217 if (best > best2) { 218 return 0; 219 } 220 221 if ((fp2 = fopen(dtfile2, "wb")) == NULL) { 222 printf("ファイルがあーりません"); 223 fflush(stdout); 224 return -1; 225 } 226 227 //point配列にbestをいれ、best2をベスト2にいれる。dtfile[0]にbest1,dtfile[1]にbest2.....dtfile[9]にbest10 228 if (fwrite(local, sizeof(struct tm), 1, fp2) != 0) { 229 perror("fwrite"); 230 fclose(fp); 231 return -1; 232 } 233 234 if (fwrite(&best2, sizeof(double), 1, fp2) != 0) { 235 perror("fwrite"); 236 fclose(fp); 237 return -1; 238 } 239 240 fclose(fp2); 241 return 0; 242} 243 244/*--- トレーニングを実行して得点(所要時間)を返す ---*/ 245static double 246do_training(void) { 247 int i, j, stage; 248 int dgt[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 249 int a[8]; 250 double jikan; // 時間 251 clock_t start, end; // 開始時刻・終了時刻 252 253 printf("\n\n欠けている数字を入力してください。\n"); 254 printf("スペースキーで開始します。\n"); 255 while (getch() != ' ') 256 ; 257 start = time(NULL); 258 259 for (stage = 0; stage < MAX_STAGE; stage++) { 260 int x = rand() % 9; /* 0~8の乱数を発生 ,1から9までのうち8文字を表示するための数字 */ 261 int no; /* 読み込んだ値 ,キーボードから打ち込んだ数字 */ 262 263 i = j = 0; 264 /* dgt[x]を飛ばしてコピー */ 265 while (i < 9) { 266 if (i != x) 267 /* dgt[x]は1から9までの数字が入っている配列 */ 268 a[j++] = dgt[i]; 269 i++; 270 } 271 272 /* 配列aをシャッフル、配列の添字は0から7までの8個である */ 273 /* 配列aの添字は0から7までの8個である。jは1から7まで変化する */ 274 /* jは1から7まで変化する。iとjの添字でシャッフルする。 */ 275 for (i = 7; i > 0; i--) { 276 int j = rand() % (i + 1); 277 if (i != j) 278 swap(int, a[i], a[j]); 279 } 280 281 printf("%d回目:", stage+1); 282 283 /* 全要素を表示 */ 284 for (i = 0; i < 8; i++) { 285 printf("%d ", a[i]); 286 } 287 printf(":"); 288 fflush(stdout); 289 290 do { 291 no = getch(); 292 if (isprint(no)) { /* 表示可能であれば */ 293 putch(no); /* 押されたキーを表示 */ 294 if (no != dgt[x] + '0') /* 正解でなければ */ 295 putch('\b'); /* カーソルを一つ戻す */ 296 else 297 printf("\n"); /* 改行 */ 298 } 299 } while (no != dgt[x] + '0'); 300 } 301 end = time(NULL); 302 303 jikan = (double)difftime(end, start); 304 305 printf("%.1f秒かかりました。\n", jikan); 306 307 if (jikan > 25.0) 308 printf("鈍すぎます。\n"); 309 else if (jikan > 20.0) 310 printf("少し鈍いですね。\n"); 311 else if (jikan > 17.0) 312 printf("まあまあですね。\n"); 313 else 314 printf("素早いですね。\n"); 315 316 return jikan; 317} 318 319int 320main(void) { 321 int retry, count = 0; // もう一度? 322 double score; // 今回の所要時間 323 double best; // 最短所要時間 324 double jikan; // 時間 325 FILE *fp; 326 fpos_t ft; 327 fpos_t offset; 328 struct tm local; 329 int k; 330 int i, j, x, stage; 331 332 // get_data()で前回までの最短所要時間を 333 best = get_data(&count); 334 335 // ファイルから読み込んでbestに代入する。 336 printf("bestは%.1f\n\n", best); 337 printf("count3は%d\n\n", count); 338 339 fp = fopen(dtfile, "rb"); 340 if (fp == NULL) { 341 perror("fopen"); 342 return -1; 343 } 344 345 if (get_point_offset(&offset) != 0) { 346 return -1; 347 } 348 349 k = offset; 350 //ファイルポインタの位置を取得 351 printf("mainのget_point_offset(&offset)後のkの値は「%d」です。\n\n", k); 352 353 //ファイルポインタを末尾まで移動 354 if (fseek(fp, 0, SEEK_END) != 0) { 355 perror("fseek"); 356 return -1; 357 } 358 359 //ファイルポインタの位置を取得 360 //ファイルfpの現在のファイル位置を取得して 361 if (fgetpos(fp, &ft) != 0) { 362 perror("fgetpos"); 363 fclose(fp); 364 return -1; 365 } 366 367 // &ftの示す場所に格納します。 368 update_local_data(ft, k); 369 370 if (fgetpos(fp, &ft) != 0) { 371 perror("fgetpos"); 372 return -1; 373 } 374 fclose(fp); 375 376 //best = get_data(ft); 377 // get_data()で前回までの最短所要時間を 378 //ファイルから読み込んでbestに代入する。 379 380 //ライブラリの初期処理235p、initscr(),cbreak(),noecho(),refresh() 381 init_getputch(); 382 383 // 乱数の種を初期化 384 srand(time(NULL)); 385 do { 386 // トレーニング(do_training)で実行、返却された所要時間(jika)を 387 // scoreに代入する。 388 score = do_training(); 389 if (score < best) { 390 printf("最短所要時間を更新しました!!\n"); 391 /* 最高得点更新 */ 392 best = score; 393 } 394 395 printf("もう一度しますか … (0)いいえ (1)はい:"); 396 retry = 0; 397 scanf("%d", &retry); 398 } while (retry == 1); 399 400 /* 今回の日付・時刻・得点を書き込む */ 401 put_data(score,best); 402 fflush(stdout); 403 404 //ライブラリの初期処理235p,endwin() 405 term_getputch(); 406 407 return 0; 408}

投稿2017/09/13 07:39

編集2017/09/13 08:12
mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/09/15 03:56

mattnさんのコードを参考に自分なりに修正したのですが、最後までいかないでとまってしまいます。 どこがわるいのでしょうか?途中までの表示は正常に表示されています。debugをやってみたのですが debugもうまくできないので、よろしくおねがいします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問