ポインタの削除

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ひよこ

ポインタの削除

#1

投稿記事 by ひよこ » 15年前

リストを勉強しているのですが、サイトのを書き直していますが、
ポインタエラーになってしまいます。どうすればいいでしょうか?
あくまで勉強なのでnewは使っていません。
#include <stdio.h>
#include <malloc.h>

typedef struct cell_t
{
  struct cell_t *next;
  int data;
};

cell_t *g_cell;//セルの先頭

int setList(int data)
{
  cell_t *tmp;
  tmp = (cell_t*)malloc(sizeof(cell_t));
  
  if(tmp == NULL)
  {
    return(-1);
  }
   
  tmp->next =NULL;
  
  if(g_cell==NULL)//先頭が存在しないなら
	g_cell=tmp;//先頭にする
  else
  {
	cell_t *end_cell=g_cell;//NULLになる
	cell_t *now_end_cell=NULL;//最後の要素
	while(end_cell!=NULL){
		now_end_cell=end_cell;
		end_cell=end_cell->next;
	}
	now_end_cell->next=tmp;//一番最後のリストに新しい要素のポインタをつなぐ。
  } 
  tmp->data = data;
  return 0;
}
void show_rist(){
	cell_t *p=g_cell;
	while(p!=NULL){
		printf("ptr=%p,data=%d\n",p,p->data);
		p=p->next;
	}
}
void deleteList()
{
  cell_t *now=g_cell;//削除されるポインタ
  cell_t *back=NULL;//削除されるポインタの後ろ
  while(now!=NULL){
	  if(now->data%10==0){
		  if(back==NULL){//最初に引っかかったら
			  g_cell=now->next;
		  }
		  else
		  {
			  back->next=now->next;
			  free(now);
		  }
	  }
	  else
		back=now;

	  now=now->next;
  }
}

int main()
{
	g_cell= NULL;//先頭のセルの初期化
	for(int i=0;i<100+1;i++)
		setList(i);
	deleteList();
	show_rist();

  return 0;
}

softya

Re:ポインタの削除

#2

投稿記事 by softya » 15年前

back->next=now->next;
からステップ実行してみれば原因は分かりますよ。

ひよこ

Re:ポインタの削除

#3

投稿記事 by ひよこ » 15年前

あれ、なんかfreeを通ったらおかしくなりました。
back->next=now->next;で代入はきちんとできていると
思ったのですが、これはどうしてでしょうか?

softya

Re:ポインタの削除

#4

投稿記事 by softya » 15年前

free(now);でnowのメモリ空間は解放されますよね。
その次のnow=now->next;でnow->nextは解放された未定義のメモリ空間の参照ですので、動作は保障されません。

ひよこ

Re:ポインタの削除

#5

投稿記事 by ひよこ » 15年前

確かに未定義ですね。よく考えたらできました。ありがとうございます。
この前の、龍神録リスト化の続きなのですがdel_effectを作っていたのですが、
二つ条件があるときのリストはどのようにできるのですか?

ひよこ

Re:ポインタの削除

#6

投稿記事 by ひよこ » 15年前

すみません、説明が悪かったですね。
今敵の消滅エフェクトを作っていたのですが、条件が二つありまして、どのように書けばいいのかと
思って質問します。下のソースで実行するとcalc_del_effectでポインタエラーとなります。
head_del_effectのnextが
いけないとわかりました。
どうすればいいのでしょうか?
//消滅エフェクトを登録する
void enter_del_effect(enemy_t *p){
    del_effect_t *new_del_effect; 	
	new_del_effect = new del_effect_t;	
	new_del_effect->next=NULL;
			
	//	最初の処理なら。
	if( head_del_effect==NULL ) {
		//	最初の敵データ
		head_del_effect = new_del_effect;
	} 
	else
	{
		//	リストの最後を探す。
		del_effect_t *now_del_effect = head_del_effect;
		while( now_del_effect->next!=NULL ) {	
			now_del_effect = now_del_effect->next;	
		}	
		//	リストの最後に接続する。		
		now_del_effect->next = new_del_effect;
	}
	new_del_effect->flag=1;//フラグを立てる
	new_del_effect->cnt=0;
	new_del_effect->col=p->back_col;//敵の背景色を消滅色に設定する
	new_del_effect->x=p->x;//敵の座標を消滅位置にセット
    new_del_effect->y=p->y; 
}

//消滅エフェクトを計算・エフェクトを計算する
void calc_del_effect(){
    del_effect_t *check_del_effect = head_del_effect;
	del_effect_t *before_del_effect = NULL;
	while( check_del_effect != NULL ) {
		del_effect_t *next_del_effect = check_del_effect->next;//head_del_effect->next
		
			if(check_del_effect->cnt%2==0){
			effect_t *new_effect; 
			new_effect = new effect_t;
			new_effect->next=NULL;
			//	最初の処理なら。
			if( head_effect==NULL ) {
				//	最初の敵データ
				head_effect = new_effect;
			} 
			else
			{
				//	リストの最後を探す。
				effect_t *now_effect = head_effect;
				while( now_effect->next!=NULL ) {
					now_effect = now_effect->next;
				}
				//	リストの最後に接続する。
				now_effect->next = new_effect;
			}
                new_effect->flag=1;
				new_effect->brt=255;
				new_effect->ang=rang(PI);
				new_effect->col=check_del_effect->col;
				new_effect->eff=1;
				new_effect->img=img_del_effect[new_effect->co[/url];//消滅する画像をセット
				new_effect->knd=0;
				new_effect->x=check_del_effect->x;
				new_effect->y=check_del_effect->y;
				new_effect->spd=0;
			}
			else
			{
			//条件にひっかからなかったらそのアドレスをbefore_ememy
			before_del_effect = check_del_effect;	
		}
		if(check_del_effect->cnt>8) {
			//	削除
			if( before_del_effect == NULL ) {//先頭か
				head_del_effect = next_del_effect;//一回目だったら、NULLを、2回目以上はアドレスへつなぐ
			} else {
				before_del_effect->next = next_del_effect;
			}
			delete check_del_effect;
		}
		else {//条件にひっかからなかったらそのアドレスをbefore_ememy
			before_del_effect = check_del_effect;	
		}
		check_del_effect->cnt++;
		check_del_effect = next_del_effect;
	}
}

softya

Re:ポインタの削除

#7

投稿記事 by softya » 15年前

見て思ったのが、
1.削除条件が良く分からない。

2.before_del_effectの代入が2箇所ある。
>before_del_effect = check_del_effect;

3.前回と同じ問題がある。
解放済みの領域を参照しているコードがあります。
ステップ実行すれば分かる問題なので、もう少し念入りに調査するクセを付けてくださいね。
私の答えを待っているだけでは、プログラミング能力は向上しませんよ。

4.2つのコードが混じってややこしいなら関数を分けてください。
head_effectの処理は別関数に分けれます。

ひよこ

Re:ポインタの削除

#8

投稿記事 by ひよこ » 15年前

なるほど、別関数にまとめるのですか、ありがとうございます。
ポインタエラーも出なくなり、実行してみたのですが消滅エフェクトが出ません。
ブレークポイントで登録の部分も通っているようなのですが、どこが悪いのでしょうか?
消滅エフェクト登録時のソースを置きます。
//消滅エフェクトを登録する
void enter_del_effect(enemy_t *p){
    del_effect_t *new_del_effect; 	
	new_del_effect = new del_effect_t;	
	new_del_effect->next=NULL;
			
	//	最初の処理なら。
	if( head_del_effect==NULL ) {
		//	最初の敵データ
		head_del_effect = new_del_effect;
	} 
	else
	{
		//	リストの最後を探す。
		del_effect_t *now_del_effect = head_del_effect;
		while( now_del_effect->next!=NULL ) {	
			now_del_effect = now_del_effect->next;	
		}	
		//	リストの最後に接続する。		
		now_del_effect->next = new_del_effect;
	}
	new_del_effect->flag=1;//フラグを立てる
	new_del_effect->cnt=0;
	new_del_effect->col=p->back_col;//敵の背景色を消滅色に設定する
	new_del_effect->x=p->x;//敵の座標を消滅位置にセット
    new_del_effect->y=p->y; 
}

void del_effect_enter(){
	del_effect_t *check_del_effect = head_del_effect;
	del_effect_t *before_del_effect = NULL;
	while( check_del_effect != NULL ) {
		del_effect_t *next_del_effect = check_del_effect->next;//head_del_effect->next
		
			if(check_del_effect->cnt%2==0){//2カウントに一度エフェクトを登録
			effect_t *new_effect; 
			new_effect = new effect_t;
			new_effect->next=NULL;
			//	最初の処理なら。
			if( head_effect==NULL ) {
				//	最初の敵データ
				head_effect = new_effect;
			} 
			else
			{
				//	リストの最後を探す。
				effect_t *now_effect = head_effect;
				while( now_effect->next!=NULL ) {
					now_effect = now_effect->next;
				}
				//	リストの最後に接続する。
				now_effect->next = new_effect;
			}
                new_effect->flag=1;
				new_effect->brt=255;
				new_effect->ang=rang(PI);
				new_effect->col=check_del_effect->col;
				new_effect->eff=1;
				new_effect->img=img_del_effect[new_effect->co[/url];//消滅する画像をセット
				new_effect->knd=0;
				new_effect->x=check_del_effect->x;
				new_effect->y=check_del_effect->y;
				new_effect->spd=0;
			}
			else
			{
			//条件にひっかからなかったらそのアドレスをbefore_ememy
			before_del_effect = check_del_effect;	
			}
			//check_del_effect->cnt++;	
			check_del_effect = next_del_effect;
	}
}
void delete_del_effect(){
	del_effect_t *check_del_effect = head_del_effect;
	del_effect_t *before_del_effect = NULL;
	while( check_del_effect != NULL ) {
		del_effect_t *next_del_effect = check_del_effect->next;//head_del_effect->next
		if(check_del_effect->cnt>8) {//登録されてから8カウントで消去
			//	削除
			if( before_del_effect == NULL ) {//先頭か
				head_del_effect = next_del_effect;//一回目だったら、NULLを、2回目以上はアドレスへつなぐ
			} else {
				before_del_effect->next = next_del_effect;
			}
			delete check_del_effect;
		}
		else {//条件にひっかからなかったらそのアドレスをbefore_ememy
			before_del_effect = check_del_effect;	
		}
		check_del_effect = next_del_effect;
	}
}
//消滅エフェクトを計算・エフェクトを登録する
void calc_del_effect(){
	if( head_del_effect!= NULL ) {
		del_effect_enter();
		delete_del_effect();
		del_effect_t *p=head_del_effect;
		while(p!=NULL){
			p->cnt++;
			p=p->next;
		}
	}
}
void effect_main(){
	dn_calc();//ドガーンとゆれる画面の処理
	calc_effect();//エフェクトの計算
    calc_del_effect();//消滅エフェクトの計算
	bom_calc();//ボム計算
	enter_crybom_effect();
}

softya

Re:ポインタの削除

#9

投稿記事 by softya » 15年前

あまり私が調べすぎるのも、本人の成長の阻害になる気がするのでヒントだけにとどめます。
1.ブレークで登録が出来ているとの事ですが、リストがちゃんと出来ているかOutputDebugStringなどで確認しましたか?
2.消滅エフェクトの処理側でリストがちゃんと処理されていますか?消滅エフェクトの何処まで処理されているかトレースしてみてください。

ひよこ

Re:ポインタの削除

#10

投稿記事 by ひよこ » 15年前

おそらくこれが悪いのだと思いますが、del_effect_enter()で作ったエフェクトがおかしくなってます。
effect_ptr=01F71760 cnt=-842150451 col=3 flag=1 x=86.000000 y=385.000000 ang=1610612736 brt=1070944260 eff=0 knd=1081073664 ,next=00000001
effect_ptr=01F71698 cnt=-842150451 col=3 flag=1 x=86.000000 y=385.000000 ang=-536870912 brt=1073352384 eff=0 knd=1081073664 ,next=00000001
effect_ptr=01F71378 cnt=-842150451 col=3 flag=1 x=86.000000 y=385.000000 ang=-536870912 brt=-1075045437 eff=0 knd=1081073664 ,next=00000001
effect_ptr=01F71410 cnt=-842150451 col=3 flag=1 x=86.000000 y=385.000000 ang=536870912 brt=-1074664265 eff=0 knd=1081073664 ,next=00000001
effect_ptr=06D52610 cnt=-842150451 col=3 flag=1 x=86.000000 y=385.000000 ang=-536870912 brt=1073726605 eff=0 knd=1081073664 ,next=00000001

消滅エフェクト登録自体はできているようです。
del_effect_ptr=06D4A218 cnt=0 col=3 flag=1 x=86.000000 y=385.000000 next=00000000

softya

Re:ポインタの削除

#11

投稿記事 by softya » 15年前

またズレてませんか?
リビルドしてみてください。

ひよこ

Re:ポインタの削除

#12

投稿記事 by ひよこ » 15年前

ズレてるの意味がわかりませんが、リビルドして下のようになりました。
del_effect_ptr=06E726D0 cnt=0 col=1 flag=1 x=96.000000 y=365.000000 next=00000000
effect_ptr=06E727F0 cnt=-842150451 col=1 flag=1 x=96.000000 y=365.000000 ang=-1610612736 brt=-1075933256 eff=0 knd=1081073664 ,next=00000001
effect_ptr=003E1760 cnt=-842150451 col=1 flag=1 x=96.000000 y=365.000000 ang=-536870912 brt=1073047341 eff=0 knd=1081073664 ,next=00000001
effect_ptr=06E69FC8 cnt=-842150451 col=1 flag=1 x=96.000000 y=365.000000 ang=536870912 brt=1072025778 eff=0 knd=1081073664 ,next=00000001
effect_ptr=06E6A060 cnt=-842150451 col=1 flag=1 x=96.000000 y=365.000000 ang=-1610612736 brt=-1075972787 eff=0 knd=1081073664 ,next=00000001
effect_ptr=06E6A1E8 cnt=-842150451 col=1 flag=1 x=96.000000 y=365.000000 ang=1610612736 brt=-1075443376 eff=0 knd=1081073664 ,next=00000001
出力用の関数です
void Rist_Debug_String(del_effect_t *p){
	TCHAR str[256];
	_stprintf(str,TEXT("del_effect_ptr=%p cnt=%d col=%d flag=%d x=%f y=%f next=%p \n"),
		p,p->cnt,p->col,p->flag,p->x,p->y,p->next
		);
		OutputDebugString( str );
}
void Rist_Debug_String2(effect_t *p){
	TCHAR str[256];
	_stprintf(str,TEXT("effect_ptr=%p cnt=%d col=%d flag=%d x=%f y=%f ang=%d brt=%d eff=%d knd=%d ,next=%p \n"),
		p,p->cnt,p->col,p->flag,p->x,p->y,p->ang,p->brt,p->eff,p->knd,p->next
		);
		OutputDebugString( str );
}
エフェクトの追加の仕方del_effect_enter()内で
new_effect->spd=0;
Rist_Debug_String2(new_effect);
としています。

softya

Re:ポインタの削除

#13

投稿記事 by softya » 15年前

nextが何処で1になるかステップ実行して確認してください。
p->ang,p->brtは表示する型が違っています。

ひよこ

Re:ポインタの削除

#14

投稿記事 by ひよこ » 15年前

あ、こんなところに原因がありました。graph_effect(0);//敵が死ぬエフェクトがないのが原因のようです。
いろいろとすみません。ただいま消滅エフェクトの拡大現象を修正中です。

ひよこ

Re:ポインタの削除

#15

投稿記事 by ひよこ » 15年前

よくみたら、初期化忘れでcntの値がおかしかったようです。
softyaさん、いろいろとありがとうございました。また、おかしくて直らない場所があったら
質問します、その時はよろしくお願いします。

ひよこ

Re:ポインタの削除

#16

投稿記事 by ひよこ » 15年前

解決にします。

softya

Re:ポインタの削除

#17

投稿記事 by softya » 15年前

とりあえず、アドバイスを。
・落ち着いてよく調べる事を心がけてください。
・ステップ実行は、自分のプログラムの気づかないバグを気づかせてくれるので、作ってすぐはなるべく実行するようにしてくださいね。
・バグは自分の理解度を深めるチャンスです。粘り強く調べてください。
・ポインタ系のバグはOutputDebugStringなどを多用して情報を収集すること。
・特にリストは作ってすぐの時は必ずちゃんと情報が格納されているか確認する事。大抵は失敗があります。
以上です。
では、プログラミングを楽しんでください。

ひよこ

Re:ポインタの削除

#18

投稿記事 by ひよこ » 15年前

いろいろとありがとうございます。
できるだけ努力します。

閉鎖

“C言語何でも質問掲示板” へ戻る