ページ 11

構造体と配列とポインタ

Posted: 2012年2月24日(金) 22:29
by MAY
次のコードでコンパイルすると実行時にエラーになるのですが、原因がわかりません。
それと、何か突っ込みどころがあったらどんどん突っ込んでください。
コンパイラはbccです。

コード:

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

typedef struct{
	int n;
} Test;

void func(Test ***a)
{
	Test b;
	
	scanf("%d", &b.n);
	
	*a = (Test **)realloc(*a, sizeof(Test *) * (5 + 1));
	*a[5] = &b;
	printf("\n%d\n", (*a[5])->n);
}

int main(void)
{
	int i;
	Test **a;
	
	a = (Test **)malloc(sizeof(Test *) * 5);
	
	for(i = 0; i < 5; ++i){
		a[i] = (Test *)malloc(sizeof(Test));
		a[i]->n = i * 2;
	}
	
	for(i = 0; i < 5; ++i){
		printf("%d\n", a[i]->n);
	}
	
	func(&a);
	
	for(i = 0; i < 6; ++i){
		printf("%d\n", a[i]->n);
	}
	
	return 0;
}

Re: 構造体と配列とポインタ

Posted: 2012年2月24日(金) 22:42
by h2so5
10行目の変数 b の寿命を確認してみてください。

Re: 構造体と配列とポインタ

Posted: 2012年2月24日(金) 22:46
by MAY
bをグローバル変数にしてみても結果は同じでした……。

Re: 構造体と配列とポインタ

Posted: 2012年2月24日(金) 23:07
by h2so5
15,16行目の *a[5] ですが、演算子の優先順位の関係で正しい配列へのアクセスになっていません。

Re: 構造体と配列とポインタ

Posted: 2012年2月24日(金) 23:14
by softya(ソフト屋)
この場合Test b;はグローバル変数でもローカル変数でもなくmallocすべきだと思いますが。
他のポインタと一貫性がありませんのでfreeで解放する時にエラーになる可能性が高くなります。
ちなみにローカル変数は絶対に、こういう場合に使ってはいけません。

Re: 構造体と配列とポインタ

Posted: 2012年2月24日(金) 23:25
by MAY
次のようにするとうまくいきました。ありがとうございました!

コード:

void func(Test ***a)
{
	Test *b = (Test *)malloc(sizeof(Test));
	
	scanf("%d", &b->n);
	
	*a = (Test **)realloc(*a, sizeof(Test *) * (5 + 1));
	(*a)[5] = b;
}

Re: 構造体と配列とポインタ

Posted: 2012年2月24日(金) 23:36
by MAY
それとすみません、次のコードについてなんですが、この場合、
変数eがローカル変数でも正常に動作するようなのですが、
理由を教えてくれたら幸いです。

コード:

#include <stdio.h>

void f(int **d)
{
	int e;
	
	scanf("%d", &e);
	
	*d = &e;
}

int main(void)
{
	int *b, c = 777;
	
	b = &c;
	printf("%d\n", *b);
	
	f(&b);
	printf("%d\n", *b);
	
	return 0;
}

Re: 構造体と配列とポインタ

Posted: 2012年2月25日(土) 00:15
by h2so5
19行目の関数を抜けたときにローカル変数eの寿命は終わっていますが、
20行目のprintfの引数に渡した時点では、まだスタック領域が上書きされずにデータが残っていたためたまたま上手く動作したに過ぎません。

Re: 構造体と配列とポインタ

Posted: 2012年2月25日(土) 00:21
by MAY
何度もありがとうございます!

Re: 構造体と配列とポインタ

Posted: 2012年2月25日(土) 00:32
by softya(ソフト屋)
お使いのコンパイラの実装に依存します。
ローカル変数がスタック上の取られている実装の場合は値が破壊されるまで参照可能な場合が多いですが単なる偶然です。

例えばこうすると値が壊れるはずです。

コード:

#include <stdio.h>
 
void f(int **d)
{
    int e;
    
    scanf("%d", &e);
    
    *d = &e;
}
 
int main(void)
{
    int *b, c = 777;
    
    b = &c;
    printf("(1) %d\n", *b);
    
    f(&b);
    printf("(2) %d\n", *b);
    printf("(3) %d\n", *b);
    
    return 0;
}