ポインタのポインタ

解決


pointer  2007-03-16 14:04:57  No: 64683  IP: 192.*.*.*

ポインタのポインタをmallocで確保するまではできたのですが、
ポインタのポインタをfreeする際にエラーになってしまいます。

それと、mallocで確保したアドレスとfree時に開放するアドレスは
同じなのになぜかエラーになります。どこかまちがえてるのでしょうか。

いろいろとWEBさがしても「ポインタのポインタ」はあまり情報がないので
ご教授お願いします。

void mymalloc(char **a,char **b)
{
 printf("malloc関数呼び出し前:%p\n",*a);
  *a=(char **)malloc(20);
  *b=(char **)malloc(20);
 printf("malloc関数呼び出し後:%p\n",*a);

 strcpy(*a,"ダブルポインタaが指す文字列");
 strcpy(*b,"ダブルポインタbが指す文字列");
}

void myfree(char **a,char**b)
{
 printf("free関数呼び出し前:%p\n",*a);
 free(*a);free(*b);
}

void main()
{
  char *a,*b;
  printf("宣言直後:%p\n",*a);

  mymalloc(&a,&b);
  printf("main()に復帰した時  :%p\n",a);
  
  printf("%s\n%s\n",a,b);
  myfree(&a,&b); 
}

編集 削除
Blue  2007-03-16 14:15:01  No: 64684  IP: 192.*.*.*

freeするのはポインタのポインタではないですよ?

なんでポインタのポインタにしているのかというのは理解できていますか?
まずポインタ無関係で

void hoge(int n){ n = 10; }

int main(){
    int n = 0;
    hoge(n);
    return 0;
}

でnが10にならないのは理解できますよね?
それをポインタ渡しにすることによって

void hoge(int* n){ *n = 10; }

int main(){
    int n = 0;
    hoge(&n);
    return 0;
}

nが10になってくれます。
そこでint を  char* に置き換えて考えて見ます。

void hoge(char* n){ n = (char*)10; } // サンプルなので実際に *n を参照しないように。

int main(){
    char* n = 0;
    hoge(n);
    return 0;
}

このときnの値は10にはなりません。
同様にnを10にするには

void hoge(char** n){ *n = (char*)10; } 

int main(){
    char* n = 0;
    hoge(&n);
    return 0;
}

となります。
実際に10になっているのは n であって &n の値ではありません。

で、(char*)10をmallocに変更すると、

void hoge(char** n){ *n = (char*)malloc(10); } 

int main(){
    char* n = 0;
    hoge(&n);
    return 0;
}

となります。
これは

int main(){
    char* n = 0;
    n = (char*)malloc(10); 
    return 0;
}

と意味合い的には同じなので freeするのは n で、&nではないのがわかります。

編集 削除
Blue  2007-03-16 14:19:35  No: 64685  IP: 192.*.*.*

よく見たら
>void myfree(char **a,char**b)
>{
> printf("free関数呼び出し前:%p\n",*a);
> free(*a);free(*b);
>}
になっていましたね。
freeでaの値を変えるわけではないのでポインタのポインタにする必要は内ですけど。
(それでも問題はない。)

問題は
>  *a=(char **)malloc(20);
>  *b=(char **)malloc(20);
なのかな。

a は char** です。
*a は char* です。

*a に char** にキャストしようとして入れています。
これは正しくはないでしょう。

編集 削除
Blue  2007-03-16 14:23:35  No: 64686  IP: 192.*.*.*

あ〜
ダブルポインタ全然関係ないところですね。

> strcpy(*a,"ダブルポインタaが指す文字列");
> strcpy(*b,"ダブルポインタbが指す文字列");
これが完全に間違っています。

*a, *b ともに 20バイト分しか領域を取っていません。
>ダブルポインタaが指す文字列
は文字数でこそ14文字ですが、WindowsのばあShift_JISコードで
全角文字は2バイト使うため27バイト(全角文字13*2+半角文字1*1)+1バイト(終端文字分)
必要になります。
このコードではstrcpy時では間違っているのに動いてしまっていて、
freeのときに発覚しているパターンなんでしょう。

編集 削除
pointer  2007-03-16 14:34:24  No: 64687  IP: 192.*.*.*

ありがとうございました。
今ちょうどポインタのポインタあたりを練習していまして、最近1週間ぐらいインフルエンザでバテていて頭が少し混乱していました。。

blueさんの言うとおり「ダブルポインタaが指す文字列」のサイズを適当に削ればうまくfreeできるようになりました。

めちゃくちゃ初歩的な事で、2時間ぐらい考えてたので本当に助かりました。
ようやくお昼たべれそうです(−−;

編集 削除
Blue  2007-03-16 14:40:02  No: 64688  IP: 192.*.*.*

ちなみにこういう場合は、strlenを使って文字列長を算出してから
mallocすれば適切な領域になります。

つまり
void mymalloc(char **a, char **b)
{
    printf("malloc関数呼び出し前:%p\n",*a);
    
    const char* x = "ダブルポインタaが指す文字列";
    const char* y = "ダブルポインタbが指す文字列";
    
    *a = (char*)malloc(strlen(x) + 1);
    *b = (char*)malloc(strlen(y) + 1);
    printf("malloc関数呼び出し後:%p\n",*a);

    strcpy(*a, x);
    strcpy(*b, y);
}

となります。

また、VC++には便利な関数があってmallocからstrcpyまでをやってくれる
_strdupというのがあります。


void mymalloc(char **a, char **b)
{
    printf("malloc関数呼び出し前:%p\n",*a);
    
    *a = _strdup("ダブルポインタaが指す文字列");
    *b = _strdup("ダブルポインタbが指す文字列");
    
    printf("malloc関数呼び出し後:%p\n",*a);
}

編集 削除
pointer  2007-03-16 14:43:09  No: 64689  IP: 192.*.*.*

Blueさんありがとう!

インフルエンザのときはプログラムはろくにできないということが判明しました(・・;

編集 削除