

研究の一環である形式のファイルからデータを抽出するプログラムを書いています。  
3Dムービー作成用のファイルでモデルデータ(名前やファイルパスなど)の抽出はできているのですが、ボーンのデータを抽出する際に突然プログラムが終了します。  
データの形式は先頭4バイトがボーン総数、その後ボーンの総数分だけボーンデータの長さ、ボーンデータが続きます。  
gdbを起動して確認したところ、どうやら1度目のループを抜けて2回目のループの際に第2引数のunsigned int
*lenがアクセスできないメモリ領域を指しています。  
こういった場合、どのように初期化するのが適切、またはエラーが出にくいのでしょうか?  
教えていただけると幸いです。よろしくおねがいします。

dataextract.c

[code]

    #include"integrated.h"
    
    extern cdata content;
    extern mdata *mod;
    
    void dataextract()
    {
        int i = 0, j = 0;
        unsigned int *len;
        unsigned char temp,buff;
        int state = 0;
        int flag = 1;
        FILE *pmm;
    
        //Define variables for extraction data
        int mnmb = 0;
        int numbone = 0;
        int numik = 0;
        int nummorph = 0;
        int numop = 0;
        int numfold = 0;
        int numkf = 0;
        int nummorphkf = 0;
        int numconfigkf = 0;
        int configdataindex = 0;
    
        pmm = fopen(PMMDATA, "rb");
        if (pmm == NULL)
        {
            printf("Failed to open file.\n");
        }
    
        //Initialize temporary variables
        memset(&temp,0x00,sizeof(temp));
        memset(&buff, 0x00, sizeof(buff));
        memset(len, 0x00, sizeof(*len));
    
        printf("Try to extract data from %s.\n\n",PMMDATA);
        //Skip data header
        fseek(pmm, 54, SEEK_CUR);
    
        //Extract total number of models
        fread(&content.nummodel, sizeof(unsigned char), 1, pmm);
        printf("Total number of models:%d\n",content.nummodel);
    
        //Dynamic allocation for structure
        mod =(mdata *) malloc(sizeof(mdata)*content.nummodel);
        mnmb = content.nummodel;
    
        //Execute each model
    for (i = 0; i < mnmb; i++)
    {
        //Extract model ID
        fread(&mod[i].modelid, 1, 1, pmm);
        printf("Model ID:%d\n", mod[i].modelid);
    
        //Get length of name and Extract model name
        fread(len, 1, 1, pmm);
        fread(&mod[i].janame, *len, 1, pmm);
        printf("Model's ja name:%s\n", mod[i].janame);
        fread(len, sizeof(unsigned char), 1, pmm);
        fread(&mod[i].enname, *len, 1, pmm);
        printf("Model's en name:%s\n", mod[i].enname);
    
        //Get file path to model data
        fread(&mod[i].filepath, 256, 1, pmm);
        printf("File path to model data:%s\n", mod[i].filepath);
    
        //Skip unknown  
        fseek(pmm, 1, SEEK_CUR);
    
        //Initialize
        len = memset(len, 0x00, sizeof(*len));
    
        //Extract bone data
        fread(&numbone, 4, 1, pmm);     //Total number of bones
        for (j = 0; j < numbone; j++)
        {
            fread(len, 1, 1, pmm);
            fread(&temp, *len, 1, pmm);
            len = memset(len, 0x00, sizeof(unsigned int));
        }
        printf("check bone data");
    
        //Initialize
        memset(&temp, 0x00, sizeof(temp));
        //memset(len, 0x00, sizeof(*len));
    
        //Extract morph data
        fread(&nummorph, 4, 1, pmm);        //Total number of morphs
        for (j = 0; j < nummorph; j++)
        {
            fread(len, 1, 1, pmm);
            fread(&temp, *len, 1, pmm);
            memset(len, 0x00, sizeof(unsigned int));
        }
        printf("check morph");
    
        //Initialize
        memset(&temp, 0x00, sizeof(temp));
        //memset(len, 0x00, sizeof(*len));
    
        //Extract ik count data
        fread(&numik, 4, 1, pmm);       //Total ik counts
        for (j = 0; j < numik; j++)
        {
            fread(&temp, 4, 1, pmm);
        }
        printf("check ik");
    
        //Initialize
        memset(&temp, 0x00, sizeof(temp));
    
        //Extract OP index data
        fread(&numop, 4, 1, pmm);       //Total OP counts
        for (j = 0; j < numop; j++)
        {
            fread(&temp, 4, 1, pmm);
        }
        printf("check op");
    
        //Intialize
        memset(&temp, 0x00, sizeof(temp));
    
        //Skip unknown
        fseek(pmm, 22, SEEK_CUR);
    
        //Skip fold status
        fread(&numfold, 1, 1, pmm);
        for (j = 0; j < numfold; j++)
        {
            fseek(pmm, 1, SEEK_CUR);
        }
        printf("check fold status");
    
        //Skip unknown
        fseek(pmm, 8, SEEK_CUR);
        fseek(pmm, numbone * 58, SEEK_CUR);
    
        //Extract and skip key frame data
        fread(&numkf, 4, 1, pmm);
        fseek(pmm, 62 * numkf, SEEK_CUR);
    
        //Skip unknown
        fseek(pmm, 17 * nummorph, SEEK_CUR);
    
        //Extract and skip morph key frame data
        fread(&nummorphkf, 4, 1, pmm);
        fseek(pmm, 21 * nummorphkf, SEEK_CUR);
    
        //Skip unknown
        fseek(pmm, 13, SEEK_CUR);
        fseek(pmm, numik, SEEK_CUR);
        fseek(pmm, 8 * numop, SEEK_CUR);
        fseek(pmm, 1, SEEK_CUR);
    
        //Extract and skip configuration keyframe data
        fread(&numconfigkf, 4, 1, pmm);
        for (j = 0; j < numconfigkf; j++)
        {
            fread(&configdataindex, 4, 1, pmm);
            fseek(pmm, configdataindex, SEEK_CUR);
        }
    
        //Skip various data
        fseek(pmm, 31 * numbone, SEEK_CUR);
        fseek(pmm, 4 * nummorph, SEEK_CUR);
        fseek(pmm, 1 * numik, SEEK_CUR);
        fseek(pmm, 16 * numop, SEEK_CUR);
        fseek(pmm, 7, SEEK_CUR);
    
        printf("check skip");
    
        //Initialize
        memset(&temp, 0x00, sizeof(temp));
        flag = 1;
    
        //Skip until next model
        while (flag == 1)
        {
            fread(&buff, 1, 1, pmm);
    
            switch (state)
            {
                case 0:
                    if (buff == 0x00)   state = 1;
                    break;
                case 1:
                    if (buff == 0x00)   state = 2;
                    else state = 0;
                    break;
                case 2:
                    if (buff == 0x00)   state = 3;
                    else state = 0;
                    break;
                case 3:
                    if (buff == 0x80)   state = 4;
                    else if (buff == 0x00) state = 3;
                    else state = 0;
                    break;
                case 4:
                    if (buff == 0x3F) state = 5;
                    else state = 0;
                    break;
                case 5:
                    if (buff == 0x01) state = 6;
                    else state = 0;
                    break;
                case 6:
                    if (buff != 0xFF) state = 7;
                    else state = 0;
                    break;
                case 7:
                    flag = 0;
                    break;
            }
        }
        printf("check next model");
    }
    
    printf("Finished data extraction!\n");
    fclose(pmm);
    free(mod);
    
    printf("dataextract.c Finished.\n\n");
    }
    
[/code]

gdbのデバッグ情報  
[![gdbのデバッグ情報](https://i.stack.imgur.com/HIFj7.png)](https://i.stack.imgur.com/HIFj7.png)


CC BY-SA 4.0
2019-01-19T09:23:12.243
52116
2019-01-20T10:38:03.403
2019-01-20T09:13:17.647
31611
31611
question
c gcc cygwin
freadを利用したforループのエラー


ループの2回目で影響が現れると言うことで他にも原因がある可能性は非常に高いのですが、現在表示されているコードだけで確実にまずいところはこちらになります。

[code]

        unsigned int *len;                  // <- ポインタが初期化されていない
        unsigned char temp,buff;            // <- `temp`には最大255バイトのデータが書き込まれるのに1バイト分しか宣言していない
    
[/code]

なぜ、`temp`や`buff`はポインタとして宣言していないのに`len`だけポインタにされたのかは不明ですが、あなたのコードの他の部分を見ても、`len`をポインタとして宣言する必要性は全く感じられません。従って、ポインタとして宣言したまま初期化する(`malloc`などで)よりも、通常の整数型にした方が良いでしょう。

そこらへんを直すとこんな感じになります。

[code]

    void dataextract()
    {
        int i = 0, j = 0;
        unsigned int len = 0;               // <- ポインタにせず宣言時に初期化しておく
        unsigned char temp[255] = {0};      // <- `temp`には最大255バイトのデータが書き込まれる
        unsigned char buff = 0;
        int state = 0;
        int flag = 1;
        FILE *pmm;
    
        //Define variables for extraction data
        int mnmb = 0;
        int numbone = 0;
        int numik = 0;
        int nummorph = 0;
        int numop = 0;
        int numfold = 0;
        int numkf = 0;
        int nummorphkf = 0;
        int numconfigkf = 0;
        int configdataindex = 0;
    
        pmm = fopen(PMMDATA, "rb");
        if (pmm == NULL)
        {
            printf("Failed to open file.\n");
        }
    
        //Initialize temporary variables
        memset(temp, 0x00, sizeof(temp)); // <-
    //    memset(&buff, 0x00, sizeof(buff)); // <- 宣言時に初期化しているんだから、こんなものが不要
    //    memset(len, 0x00, sizeof(*len)); // <- `len`もポインタではないので、こんなものも不要
    
        printf("Try to extract data from %s.\n\n",PMMDATA);
        //Skip data header
        fseek(pmm, 54, SEEK_CUR);
    
        //Extract total number of models
        fread(&content.nummodel, sizeof(unsigned char), 1, pmm);
        printf("Total number of models:%d\n",content.nummodel);
    
        //Dynamic allocation for structure
        mod =(mdata *) malloc(sizeof(mdata)*content.nummodel);
        mnmb = content.nummodel;
    
        //Execute each model
        for (i = 0; i < mnmb; i++)
        {
            //Extract model ID
            fread(&mod[i].modelid, 1, 1, pmm);
            printf("Model ID:%d\n", mod[i].modelid);
    
            //Get length of name and Extract model name
            fread(&len, 1, 1, pmm); // <-
            fread(&mod[i].janame, len, 1, pmm); // <-
            printf("Model's ja name:%s\n", mod[i].janame);
            fread(&len, sizeof(unsigned char), 1, pmm); // <-
            fread(&mod[i].enname, len, 1, pmm); // <-
            printf("Model's en name:%s\n", mod[i].enname);
    
            //Get file path to model data
            fread(&mod[i].filepath, 256, 1, pmm);
            printf("File path to model data:%s\n", mod[i].filepath);
    
            //Skip unknown
            fseek(pmm, 1, SEEK_CUR);
    
            //Initialize
            //len = 0; //<- 毎回使う直前で値を読み込んでいるので不要
    
            //Extract bone data
            fread(&numbone, 4, 1, pmm);     //Total number of bones
            for (j = 0; j < numbone; j++)
            {
                fread(&len, 1, 1, pmm); // <-
                fread(temp, len, 1, pmm); // <-
                //len = 0; //<- 同上で不要
            }
            printf("check bone data");
    
            //Initialize
            memset(temp, 0x00, sizeof(temp)); // <-
            //memset(len, 0x00, sizeof(*len)); // <- 不要
    
            //Extract morph data
            fread(&nummorph, 4, 1, pmm);        //Total number of morphs
            for (j = 0; j < nummorph; j++)
            {
                fread(&len, 1, 1, pmm); // <-
                fread(temp, len, 1, pmm); // <-
                //len = 0; // <-
            }
            printf("check morph");
    
            //Initialize
            memset(temp, 0x00, sizeof(temp)); // <-
            //memset(len, 0x00, sizeof(*len)); // <- 不要
    
            //...        
            printf("check skip");
    
            //Initialize
            memset(temp, 0x00, sizeof(temp)); // <-
            flag = 1;
    
            //...        
            printf("check next model");
        }
    
        printf("Finished data extraction!\n");
        fclose(pmm);
        free(mod);
    
        printf("dataextract.c Finished.\n\n");
    }
    
[/code]

  * 今のCではブロックの先頭でなくても変数宣言できるのになぜ先頭にまとめているのか
  * 1バイトだけデータを読むのに`fread` ?
  * `int`が4バイトであること、little endianであることに依存している部分がある

辺りの、諸々気になるところはとりあえず置いておきます。

書き直さなきゃいけないところがあっちこっちに広がっています。上記のコードはそのままでも良い(現在の情報では修正がいるかどうかわからない場合を含めて)ところの一部を`//...`に置き換えてありますので、注意して書き換えた上でおためしください。2つの変数の宣言

[code]

        unsigned int len = 0;               // <- ポインタにせず宣言時に初期化しておく
        unsigned char temp[255] = {0};      // <- `temp`には最大255バイトのデータが書き込まれる
    
[/code]

を書き換えた後、コンパイル時に警告もエラーも出ないようにしていけば、修正漏れにはならないだろうと思います。

* * *

ちなみに手元にgccはないのですが、clangですと`unsigned int
*len;`なんて初期化なしの変数宣言の後、一度も値をセットせずにそのポインタを使うと「ポインタ変数が初期化されていない」旨の警告が出ます。gccでも同様の警告が出るはずだと思うのですが?

**_どのように初期化するのが適切、またはエラーが出にくいのでしょうか?_**

に対しては、いろいろなことが考えられますが、

  * そもそもポインタにする必要のない変数をポインタにしてはいけない
  * コンパイラの出す警告は無視しない

と言う点に注意されるべきだろうと思います。

* * *

最初に書いたように、上記の修正をしてもまだうまくいかない点が出てくる可能性があります。その場合には、コメント等でお知らせください。その際には、まだお示しいただいていない情報も開示していただく必要があると思いますが。


CC BY-SA 4.0
2019-01-20T10:38:03.403
52134
2019-01-20T10:38:03.403
13972
52116
answer