C言語関係掲示板

過去ログ

No.1126 構造体配列のメモリ領域動的確保と、関数の引数について

[戻る] [ホームページ]
No.2077

構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---kazu37(2004/06/17 20:47:55)


構造体配列を引数にして、呼び先の関数で要素数を動的に確保。
値を設定して返して、呼び元でその値を参照したいのですが、
うまくできません。
メモリ領域の確保はできていて、呼び先の関数の中では値を設定した
後の構造体の中身は参照できます。
しかし、呼び元に帰ってきた後、参照できません。
引数やポインタの見方がまずいと思うのですが、何が悪いのか
ご指摘して頂けませんか?よろしくお願い致します。


struct info {
        char id[10];
        char name[10];
};

int main_proc(void)
{
        struct info *info_ary;

        /* 画面一覧ファイル情報取得 */
        if ( set_info( info_ary ) != 0 )  goto error;

        free(scrinfo_ary);

        return(NO_ERROR);

error:
        if ( scrinfo_ary != NULL ) free(scrinfo_ary);
        return(ERROR);
}

static int set_info(struct info *in)
{
        /* 10個分確保 */
        in = (struct info *) malloc(10 * sizeof(struct info));
        if ( in == NULL ) {
                return 1;
        }

        strncpy(in[0].id, "A001");
        strncpy(in[0].name, "北海道");
        strncpy(in[1].id, "B001");
        strncpy(in[1].name, "青森");

        return 0;

}




No.2079

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---YuO(2004/06/17 21:42:34)


>引数やポインタの見方がまずいと思うのですが、何が悪いのか
>ご指摘して頂けませんか?よろしくお願い致します。

ポインタというのは値です。
よって,

> if ( set_info( info_ary ) != 0 ) goto error;
> static int set_info(struct info *in)

この二行でやっていることは,
int n;
if ( set_info( n ) != 0) goto error;

/* (snip) */

int set_info (int n)

と何ら変わりがありません。


T型の値を変更するために引数でポインタを利用する場合,
その型は常にT *型になります。

今回の場合,Tはstruct info *ですから,set_infoではstruct info **型を受ける必要があります。



No.2080

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---円零(2004/06/17 22:21:09)


ちょっといじってしまいましたが、これを実行してみてはどうでしょう。

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

#define NO_ERROR 0
#define ERROR -1
struct info {
    char id[10];
    char name[10];
};

static int set_info(struct info *in);

int main(void){
    struct info *info_ary;
    /* 画面一覧ファイル情報取得 */
    printf("現在、info_aryが指し示すアドレスは %p。\n今からset_infoを呼び出します。\n\n", info_ary);
    if(set_info(info_ary) != 0) goto error;
    printf("現在、info_aryが指し示すアドレスは %p。\n終了します。", info_ary);
    free(info_ary);
    return(NO_ERROR);
    error:
        if(info_ary != NULL) free(info_ary);
        return(ERROR);
}

static int set_info(struct info *in){
    /* 10個分確保 */
    printf("現在、in[0]が指し示すアドレスは    %p。\n今からmallocを行います。\n\n", &in[0]);
    in = (struct info *)malloc(10 * sizeof(struct info));
    if(in == NULL){
        return 1;
    }
    strcpy(in[0].id, "A001");
    strcpy(in[0].name, "北海道");
    strcpy(in[1].id, "B001");
    strcpy(in[1].name, "青森");
    printf("現在、in[0]が指し示すアドレスは    %p。\n今から呼び出し元に返ります。\n\n", &in[0]);
    return 0;
}



No.2082

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---kazu37(2004/06/17 23:47:38)


YuOさん、円零さん、ご回答ありがとうございます。
記述したソースがdefine定義やらなにやらいろいろ抜けの多くて
申し訳ございませんでした。

YuOさんのご指摘の通りに引数の設定をしてみましたが、その後の値の
設定の記述の仕方がわからず、コンパイルが通りません。
strcpy(in[0].id, "A001");
で「struct または union を使用してください。」と言われてしまいます。

また円零さんのソースはコンパイルは通りますが、呼び元での
値の参照がわかりません。
printf("id : %s,name :%s\n",scrinfo_ary[i].id,scrinfo_ary[0].name);
のように画面に出力しても、文字化けしています。

他に何が足りないのでしょうか?


No.2084

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---YuO(2004/06/17 23:58:17)


>YuOさんのご指摘の通りに引数の設定をしてみましたが、その後の値の
>設定の記述の仕方がわからず、コンパイルが通りません。

意味をちゃんと理解してください。
  • int型の値を関数側で変更したい場合,関数はint *型の引数を受け取ります。
  • struct info型の値を関数側で変更したい場合,関数はstruct info *型の引数を受け取ります。
  • struct info *型の値を関数側で変更したい場合,関数はstruct info * *型の引数を受け取ります。


そして,渡したい型の値の型は,常に(*obj)の形でアクセスできます。


No.2085

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---kazu37(2004/06/18 00:15:28)


>
>意味をちゃんと理解してください。
>
  • int型の値を関数側で変更したい場合,関数はint *型の引数を受け取ります。
  • struct info型の値を関数側で変更したい場合,関数はstruct info *型の引数を受け取ります。
  • struct info *型の値を関数側で変更したい場合,関数はstruct info * *型の引数を受け取ります。

>
>そして,渡したい型の値の型は,常に(*obj)の形でアクセスできます。


ご回答ありがとうございます。
やはり、ポインタやアドレスと言ったところで、理解が滞っているようです。
上記の例のint型の場合は大丈夫なのですが、それ以外がだめです。
理解していないまま、いろいろ試しましたが、うまくいきませんでした。
時間がないため、安全策を取って先に進め、後で勉強し直したいと思います。


No.2087

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---円零(2004/06/18 09:24:17)


正直話がよく見えませんが、私は、「このコードを使ってください」と言ってる訳ではなくて、
「途中のアドレスの値を表示してみたら理解が深まるのでは?」という趣旨で書きこんでます。
私のコードに何か悪い点があるようでしたら、すみませんが趣旨だけ汲み取ってください。

時間がないのであれば致し方ありませんが。


No.2090

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---kazu37(2004/06/18 11:18:26)


確かにアドレスを表示させることは出来ました。
ただ、勉強不足でまだ理解できるところまで至ることが出来ませんでした。
しかし、教えて頂きたいことを手がかりに、後から見直したいと思います。
ありがとうございました。


No.2163

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---kazu37(2004/06/25 11:46:18)


前の投稿から時間が経ちましたが、ようやく見直す時間ができ、
目的の結果が得られるようになりましたので、ご報告します。
まだ、だめな点がありましたら、ご指摘お願いします。

struct info {
        char id[10];
        char name[10];
};

int main_proc(void)
{
        struct info *info_ary;
        int i;

        if ( set_info( &info_ary ) != 0 )  goto error;

        for (i=0; i<10; i++) {
               printf("id:%s name:%s\n",info_ary[i].id, info_ary[i].name);
        }

        free(info_ary);

        return(NO_ERROR);

error:
        if ( scrinfo_ary != NULL ) free(scrinfo_ary);
        return(ERROR);
}

static int set_info(struct info **in)
{
        /* 10個分確保 */
        *in = (struct info *) malloc(10 * sizeof(struct info));
        if ( *in == NULL ) {
                return 1;
        }

        strncpy((*in)[0].id, "A001");
        strncpy((*in)[0].name, "北海道");
        strncpy((*in)[1].id, "B001");
        strncpy((*in)[1].name, "青森");
        /* 以下省略 */

        return 0;

}




No.2164

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---RAPT(2004/06/25 21:55:28)


strncpy((*in)[0].id, "A001");
strncpy((*in)[0].name, "北海道");
引数が足りないのでは?

それから、ソース中でマジックナンバー(意味のある数字)は、
マクロにしておくといいでしょう。後々の変更も楽ですし。

例えば、
#define ARRAY_COUNT  10
(snip)
for (i=0; i<ARRAY_COUNT; i++) {
(snip)
*in = (struct info *) malloc(ARRAY_COUNT * sizeof(struct info));
(snip)
strncpy((*in)[0].id, "A001", sizeof((*in)[0].id));

strncpy()については、
#define ID_SIZE    10
#define NAME_SIZE  10
struct info {
    char id[1 + ID_SIZE];
    char name[1 + NAME_SIZE];
};
(snip)
strncpy((*in)[0].id, "A001", ID_SIZE);
strncpy((*in)[0].name, "北海道", NAME_SIZE);

のようにすると良いと思います。



No.2180

Re:構造体配列のメモリ領域動的確保と、関数の引数について
投稿者---kazu37(2004/06/28 10:46:53)


><pre><blockquote>strncpy((*in)[0].id, "A001");
strncpy((*in)[0].name, "北海道");</blockquote>
引数が足りないのでは?

申し訳ございません。
実際のソースを手で書き換えて、抜けてしまいました。

>それから、ソース中でマジックナンバー(意味のある数字)は、
マクロにしておくといいでしょう。後々の変更も楽ですし。

なるほど。今後は気をつけて、そういう心構えでやっていきたいと思います。

ご指摘ありがとうございました。