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

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

ただいまの
回答率

90.76%

  • C

    3465questions

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

配列を使っているところをmalloc使って動的にメモリを確保したい

解決済

回答 2

投稿

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

sanchu52

score 130

下のコードでどこを、どのようにしたらいいか見当がつきません。
動けばいいんじゃないのという人もいると思いますが、今mallocの使い方を勉強しています。直しようがないというのであれば、教えていただきたいのです。
コードの書き方で直したほうがいいところがあれば、それも教えてください。
よろしくおねがいいたします。
コード
// ラックナンバーサーチ・トレーニング  正常動作

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

#define MAXCNT 100

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;   
}TIME_DATA;

//--- 前回までのトレーニング情報の最高得点を返す ---
void get_data2(int *count)
{
    FILE *fp;
    FILE *fp2;
    int i;
    int    year, mon, mday, hour, min, sec;
    double score;
    double bestscore;        // 最高得点 

    TIME_DATA stars[MAXCNT];  // 構造体配列の宣言

    if ((fp=fopen(dtfile,"rb"))==NULL){
        printf("本プログラムを実行するのは初めてですね。\n\n");
        bestscore = DBL_MAX;  /* float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX */
        exit(1);
    } else {
        for(i=0; i<MAXCNT; i++){
            if(fscanf(fp, "%d %d %d %d %d %d %lf\n" ,             // 構造体配列への読み込み
                 &stars[i].tm_year,&stars[i].tm_mon,&stars[i].tm_mday, 
                &stars[i].tm_hour,&stars[i].tm_min,&stars[i].tm_sec,&stars[i].score)!=7) break;

            (*count)++;
        }
        printf("\ncount01:%d\n\n",*count);

           printf("前回の終了は%d年 %d月 %d日 %d時 %d分 %d秒 で\n\n",            // 構造体配列への読み出し
            stars[*count-1].tm_year,stars[*count-1].tm_mon,stars[*count-1].tm_mday,stars[*count-1].tm_hour,
            stars[*count-1].tm_min,stars[*count-1].tm_sec,stars[*count-1].score);           

    fflush(stdout); 
    fclose(fp);
    }

    if ((fp2=fopen(dtfile2,"rb"))==NULL) {
        printf("本プログラムを実行するのは初めてですね。\n\n");
        bestscore=DBL_MAX;  /* float.hに定義されている。double型で表現できる最大値を表すマクロDBL_MAX */
        exit(1);
    } else {
        fscanf(fp2, "%d%d%d%d%d%d", &year, &mon, &mday, &hour, &min, &sec);
        fscanf(fp2, "%lf", &bestscore);   // stream(fp)が指すストリームから&bestに読み込む 
                                    //fscanf 関数は format が指す書式文字列に従って 
                                    //stream(fp) が指すストリームからデータを読込み,
                                    //format(&year, &month, &day, &h, &m, &s) に続く引数の指すオブジェクトに代入します.
        printf("前回までの最高得点(最短所要時間)は%d年%d月%d日%d時%d分%d秒で\n",
                                            year, mon, mday, hour, min, sec);    
        fflush(stdout); 

        printf("これまでの最高得点(最短所要時間)は%.1f秒です。\n\n", bestscore);

        // 画面が一瞬で消えてしまうのを防止 
        // 一瞬で画面が消えてしまう場合には、//getchar();
        // 以下の文を入力します。
        fflush(stdout); 
        fclose(fp2);
    }
}



//■過去の履歴は.
double kako_rireki(int* count,double* p,double* q)
{
    FILE *fp;
    int i;

    TIME_DATA stars[MAXCNT];  // 構造体配列の宣言

    if((fp=fopen(dtfile, "rb"))==NULL){
        printf( "ファイルがオープンできません\n" );
        exit( 1 );
    }
       for(i=0; i<MAXCNT; i++){
        if(fscanf(fp, "%d %d %d %d %d %d %lf\n"              // 構造体配列への読み込み
        , &stars[i].tm_year,& stars[i].tm_mon, &stars[i].tm_mday, 
            &stars[i].tm_hour, &stars[i].tm_min,&stars[i].tm_sec,&stars[i].score)!=7) break;
    }
    printf("\ncount0:%d\n\n",*count);
    printf("\n■過去の履歴は................\n\n");

    for(i=0; i<*count; i++){
        printf( "%d年 %d月 %d日 %d時 %d分 %d秒 \n所要時間(score)は%.1f\n\n",            // 構造体配列への読み出し
            stars[i].tm_year,stars[i].tm_mon,stars[i].tm_mday,stars[i].tm_hour,
            stars[i].tm_min,stars[i].tm_sec,stars[i].score);           
    }
    fflush(stdout);
    fclose(fp);
    printf("count1は%d\n\n", *count);  
    return *count;
}



int main(void)
{
    int     count=0;
    int  retry;    
    double score;                    // 今回の所要時間 
    double bestscore;
    double* p;
    double* q;

    get_data2(&count);

    kako_rireki(&count,p,q);        

    printf("count3:%d\n", count);                         

    return (0);
}


/* 実行結果
C:\MinGW\users\chap09\kadai>gcc -I. -o kadai9-1c kadai9-1c.c pdcurses.a

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

count01:29

前回の終了は2017年 10月 2日 17時 59分 31秒 で

前回までの最高得点(最短所要時間)は2017年9月14日10時21分18秒で
これまでの最高得点(最短所要時間)は6.0秒です。


count0:29


■過去の履歴は................

2015年 12月 7日 19時 9分 59秒
所要時間(score)は8.0

2016年 1月 4日 1時 9分 11秒
所要時間(score)は7.5

以下省略

C:\MinGW\users\chap09\kadai>
*/
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • t_obara

    2017/10/03 15:10

    構造体配列と記載の部分を必要に応じて動的に拡張したいという意図でしょうか? その通りであれば、「リスト構造」というキーワードを調べてみるとよろしいかと思います。

    キャンセル

  • sanchu52

    2017/10/03 15:18

    ありがとうございます。TIME_DATA stars[MAXCNT]のところで、MAXCNTを100に設定しています。これをmallocを使って、コードを書き直せますか。 &stars[i].tm_hour, &stars[i].tm_min,&stars[i].tm_sec,&stars[i].score)!=7) break;を使えば使う必要はないですか。ここではmllocは使う意味がないですか?

    キャンセル

回答 2

checkベストアンサー

+2

回答依頼ありがとうございます。

コードの書き方で直したほうがいいところがあれば、それも教えてください。

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

int print_time_datum(const TIME_DATA *datum) {
    return print_time_datum_w_format("%d年 %d月 %d日 %d時 %d分 %d秒: %f", datum);
}
int print_time_datum_w_format(const char *format, const TIME_DATUM *datum) {
    return printf(format,
        datum->tm_year, datum->tm_mon, datum->tm_mday,
        datum->tm_hour, datum->tm_min, datum->tm_sec, datum->score
    );
}

int fscan_time_datum(FILE *fp, TIME_DATUM *datum) {
    return fscanf(fp, "%d %d %d %d %d %d %lf\n",
        &datum->tm_year, &datum->tm_mon, &datum->tm_mday,
        &datum->tm_hour, &datum->tm_min, &datum->tm_sec, &datum->score         
    );
}

前々から言っているように、機能を抽象化することをお勧めします。
これはオブジェクト指向言語を学び始める際にも役立つことでしょう。

また、細かい話で恐縮なのですが...
『data』は複数形です。構造体のタグ名には単数形の『datum』を使いましょう。

追記
いまちょっと調べてみたら、dataを単数形として使うネイティブもいるようです。
ですので、必ずdatumを使わねばならないというわけではありませんが...

SCORE_DATUM data[HOGE];
for(int i = 0; i < HOGE; i++) {
    SCORE_DATUM datum = data[i];
}

こんな風に書けるので、けっこう便利です。この例だとコピーコストが生じますが。


malloc使って動的にメモリを確保したい

一応使い方としては、こんな感じです。
しばらく使ってないのでデバッグなしだとちょっと自信がないです。

TIME_DATA *stars;
stars = (TIME_DATA *)malloc(sizeof(TIME_DATA) * MAXCNT));
if(stars == NULL) {
    exit(1);
}

...

free(stars);

上記では面倒なのでMAXCNT個だけ要素を持てる領域を確保しています。
が。これなら静的配列で充分です。

動的確保の享受を得たいのなら、ランキング入りしている分だけ確保すればよいでしょう。
例えば、DATファイルのヘッダにランカー数を書くとか。


DATファイルをこちらで用意するのは面倒なので、動作確認はしていません。
適宜エラー等を潰しながら試してみてください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/03 17:22

    LouiS0616さんいつもありがとうございます。リストを勉強してから、またでなおしします。細かい指摘で助かります。来週中までかかりそうです。

    キャンセル

+2

依頼があったので回答を書いていたのですが、LouiS0616さんが既に回答されてますので、ちょこっと違うコメントをしてみます。

mallocを使って、コードを書き直せますか

とのことですが、このプログラムは配列を用いているので、

(A1) TIME_DATAとして実際に必要なデータ数が1個であっても無条件に100個メモリーが確保される
(A2) 101個以上必要だったとしてもこのコードのままではMAX_CNTを書き直してコンパイルしなおさない限り対応不能

上記に対して

(L1) 実際に必要な分だけメモリーを確保(1個なら1個分だけ、10個なら10個だけ)
(L2) プログラムの変更なしにかなり大きな個数まで(計算機のメモリーがある限り)柔軟に対応できる

ようにするためには配列ではなくリスト構造を用いるのが常とう手段です。リスト構造を用いると、必要になった時点で要素一つ分の領域を動的に確保することができ、その際にmallocを使うことになります。

より詳細には'C言語 データ構造 リスト'といったキーワードを指定してまずは検索するなり参考書を参照するなりすべきと思いました。つまり自分が申し上げたいことはt_obaraさんと同じです。

検索すると解説がいろいろとみつかります。例えばこんなページとか。こういった解説ページをご覧になれば、teratailの回答欄では書ききれないような丁寧な説明を読むことができます。

質問が「動的確保したい」といった漠然としたものであるうちはまずは手法について自分なりに知識を吸収し、その上で実際にコードを書くといった進め方がいいのではないでしょうか。手法を把握した上で書いたコードについての具体的質問をするというのがQ&Aサイトの典型的な活用法と思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/03 17:17

    ご回答ありがとうございます。t_obaraさんのおっしゃる通り構造体のリストに関するネットを収集していました。これからリストを勉強して戻ってきます。

    キャンセル

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

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

関連した質問

  • 解決済

    パイプとc言語

    前提・実現したいこと dateからパイプして、日付を他言語でターミナルに表示できるようにしたいです。フランス語とドイツ語で曜日と月が書いてあるファイルが存在しています(fr.tx

  • 解決済

    構造体のプログラム

    いつもお世話になっています。C言語初心者でただいま勉強中です。構造体について質問させていただきます。ファイルから構造体配列に読み込んで以下のように出力するプログラムを作りたいんです

  • 解決済

    結果の表示について

    課題で、 キーボードから入力された数値の平均を計算して表示し、平均以上の数値、平均より小さい数値を表示するプログラムを考えているのですが、 実行例 ./a.out

  • 解決済

    配列

    n個のデータを配列に読み込み、平均と分散を求めるプログラムを作成して、下記のデータで試せ、という問題です。 {3.9,10.4,9.5,7.5,2.8,4.8,2.9,8.1,3

  • 解決済

    プログラミング言語 テスト

    include <stdio.h> main(){ int data[10]; double ave;//平均点 int max, min, n, i =0;//nはデータ数に使用

  • 受付中

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

    正常に動くプルグラムを見やすく改良したい。 具体的に教えていただければありがたいです。セグメンテーションフォルトでベスト7まで表示して停止します。173行あたりだと思うのですが、よ

  • 解決済

    実行時間の表示がおかしい

    ラックナンバーリサーチの時間が過去の履歴は正常に表示されますが、 短い順に並べるところの年と月が2017年が3917年、10月が9月と表示され、そのほかの 時間は正常です。コードの

  • 解決済

    数字(文字)が何も書かれていない、を表現するのにNULLであってるのか

    前提・実現したいこと C言語を使って,「input.txtに1個以上の実数が1行に1つずつ改行を挟んで書かれているとき, 記載されている実数をすべて読み込み,数値の合計,数値の個数

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

  • C

    3465questions

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