C言語関係掲示板

過去ログ

No.1209 >reallocが返すアドレスについて

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

reallocが返すアドレスについて
投稿者---kokoko(2004/07/26 23:31:54)


以下のプログラムにおいて、main関数でtest関数内で行われた処理の結果(構造体の中身)を表示させたいのですが、
reallocの返すアドレスがtest関数に渡したアドレスと異なるために上手くいきません。
実際には、test関数に複数の構造体を渡し、動的にメモリを確保する処理をさせたいので、return文で返すこともできません。
何かtest関数を抜けた後でも構造体にアクセスする方法はないでしょうか。

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

typedef struct{
    int a;
    int b;
}TEST;

void test(TEST* test){
    int i;
    
    for(i=0;i<100;i++){
        test=(TEST *)realloc(test,sizeof(TEST)*10*i);
        
        test[i].a=1;
        test[i].b=2;
        printf("i:%d %d\n",test[i].a,test[i].b);
    }
    
}

int main(){
    TEST* tes;
    int i;
    
    tes=(TEST *)malloc(sizeof(TEST));
    
    test(tes);
    
    for(i=0;i<100;i++){
        printf("i:%d %d\n",tes[i].a,tes[i].b);
    }
    return(0);
}




No.15894

Re:reallocが返すアドレスについて
投稿者---シャノン(2004/07/26 23:40:31)


>以下のプログラムにおいて、main関数でtest関数内で行われた処理の結果(構造体の中身)を表示させたいのですが、
>reallocの返すアドレスがtest関数に渡したアドレスと異なるために上手くいきません。
>実際には、test関数に複数の構造体を渡し、動的にメモリを確保する処理をさせたいので、return文で返すこともできません。
>何かtest関数を抜けた後でも構造体にアクセスする方法はないでしょうか。

test 関数が再確保した後のアドレスを返しゃいいだけのような気がしますが。

ところで、2つほど指摘を。
1. test 中で 100 回も再確保を行っていますが、無駄だと思います。
回数といい容量といい。というか、数が固定なら main で確保しちゃえ
ばいいじゃん、と。
2. main が終わる前に、free で解放するのを忘れずに。


No.15895

Re:reallocが返すアドレスについて
投稿者---kokoko(2004/07/26 23:51:41)


>>何かtest関数を抜けた後でも構造体にアクセスする方法はないでしょうか。
>
>test 関数が再確保した後のアドレスを返しゃいいだけのような気がしますが。

test関数は、説明上作った関数なのですが、実際に作りたいプログラムとしては、返す値が複数で、確保するメモリの回数も固定ではありません。
再確保した後のアドレスはどのようにかえしたらよいでしょうか。
よろしくお願いします。

>
>ところで、2つほど指摘を。
>1. test 中で 100 回も再確保を行っていますが、無駄だと思います。
> 回数といい容量といい。というか、数が固定なら main で確保しちゃえ
> ばいいじゃん、と
>2. main が終わる前に、free で解放するのを忘れずに。

freeに関しては、付け忘れていました。


No.15897

Re:reallocが返すアドレスについて
投稿者---円零(2004/07/27 00:54:48)


ポインタのポインタを渡しましょう。

test関数内で、TEST構造体へのポインタtestは、最初はmain関数のtesとおなじアドレスを指しています。
でもすぐにreallocされて、新しく確保された別の領域へのポインタになってしまいます。
これって、ポインタの指す先だけを変更したわけではなくてポインタの値自体が変わってますよね?
引数に起こった値の変化を呼び出し元に反映したい時はどうすればいいんでしょうか。
そうです。その値へのポインタを渡すようにしてください。
つまりこの場合はポインタのポインタを渡せば解決するはずです。

あと、reallocに失敗すると元の領域は開放されないまま戻り値でNULLが帰ってきてしまうので、
チェックしないでそのまま代入してしまうと失敗だった時に参照できなくなってしまいます。
一旦別のポインタ変数に受けた方が良いのではないかと。


No.15896

Re:reallocが返すアドレスについて
投稿者---nop(2004/07/27 00:37:19)


>void test(TEST* test){
>test=(TEST *)realloc(test,sizeof(TEST)*10*i);

ここの変数「test」は「TEST*」型のローカル変数。
いくら値を変更してもmain()には何も影響しません。

void test(TEST** test){
*test=(TEST *)realloc(test,sizeof(TEST)*10*i);

と、すれば?


No.15898

Re:reallocが返すアドレスについて
投稿者---kokoko(2004/07/27 01:29:10)


>>void test(TEST* test){
>>test=(TEST *)realloc(test,sizeof(TEST)*10*i);
>
>ここの変数「test」は「TEST*」型のローカル変数。
>いくら値を変更してもmain()には何も影響しません。
>
>void test(TEST** test){
>*test=(TEST *)realloc(test,sizeof(TEST)*10*i);
>
>と、すれば?

nopさん円零さんありがとうございます。
つまりアドレスを関数に値渡ししてあげればよいということですね。
しかし、上記のことを踏まえ以下のように修正して実行してみましたが、
三回目のループにおいて

test[i]->a=1;

のところでSegmentation faultが発生してしまいます。
これはなぜ起こるのでしょうか。


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

typedef struct{
    int a;
    int b;
}TEST;

void test(TEST** test){
    int i;
    
    for(i=0;i<100;i++){
        *test=(TEST *)realloc(*test,sizeof(TEST)*10*i);
        
        test[i]->a=1;
        test[i]->b=2;
        
        printf("i:%d %d\n",test[i]->a,test[i]->b);
    }
}

int main(){
    TEST* tes;
    int i;
    
    tes=(TEST *)malloc(sizeof(TEST));
    
    test(&tes);
    
    for(i=0;i<100;i++){
        printf("i:%d %d\n",tes[i].a,tes[i].b);
    }
    return(0);
    free(tes);
}





No.15899

Re:reallocが返すアドレスについて
投稿者---円零(2004/07/27 02:34:53)


とりあえずiがゼロから始まってるのはまずくないですか?
i = 0の時、割り当てられるメモリブロックのサイズがゼロになるので
*testはNULLポインタになりますが、
test[i]->a=1;などと代入しちゃってます。これはマズイ。

それと、構造体へのアクセスは(*test)[i].aのように書くべきですね。
test[i]->aはTEST型のポインタ配列へのアクセスでしょう。
今回の場合TEST配列へのポインタに整数値を足す形式ですのでそうは書けません。