ページ 1 / 1
ポインタの削除
Posted: 2009年11月13日(金) 09:40
by ひよこ
リストを勉強しているのですが、サイトのを書き直していますが、
ポインタエラーになってしまいます。どうすればいいでしょうか?
あくまで勉強なので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;
}
Re:ポインタの削除
Posted: 2009年11月13日(金) 10:20
by softya
back->next=now->next;
からステップ実行してみれば原因は分かりますよ。
Re:ポインタの削除
Posted: 2009年11月13日(金) 10:32
by ひよこ
あれ、なんかfreeを通ったらおかしくなりました。
back->next=now->next;で代入はきちんとできていると
思ったのですが、これはどうしてでしょうか?
Re:ポインタの削除
Posted: 2009年11月13日(金) 10:38
by softya
free(now);でnowのメモリ空間は解放されますよね。
その次のnow=now->next;でnow->nextは解放された未定義のメモリ空間の参照ですので、動作は保障されません。
Re:ポインタの削除
Posted: 2009年11月13日(金) 10:54
by ひよこ
確かに未定義ですね。よく考えたらできました。ありがとうございます。
この前の、龍神録リスト化の続きなのですがdel_effectを作っていたのですが、
二つ条件があるときのリストはどのようにできるのですか?
Re:ポインタの削除
Posted: 2009年11月13日(金) 17:42
by ひよこ
すみません、説明が悪かったですね。
今敵の消滅エフェクトを作っていたのですが、条件が二つありまして、どのように書けばいいのかと
思って質問します。下のソースで実行すると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;
}
}
Re:ポインタの削除
Posted: 2009年11月14日(土) 10:22
by softya
見て思ったのが、
1.削除条件が良く分からない。
2.before_del_effectの代入が2箇所ある。
>before_del_effect = check_del_effect;
3.前回と同じ問題がある。
解放済みの領域を参照しているコードがあります。
ステップ実行すれば分かる問題なので、もう少し念入りに調査するクセを付けてくださいね。
私の答えを待っているだけでは、プログラミング能力は向上しませんよ。
4.2つのコードが混じってややこしいなら関数を分けてください。
head_effectの処理は別関数に分けれます。
Re:ポインタの削除
Posted: 2009年11月14日(土) 13:54
by ひよこ
なるほど、別関数にまとめるのですか、ありがとうございます。
ポインタエラーも出なくなり、実行してみたのですが消滅エフェクトが出ません。
ブレークポイントで登録の部分も通っているようなのですが、どこが悪いのでしょうか?
消滅エフェクト登録時のソースを置きます。
//消滅エフェクトを登録する
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();
}
Re:ポインタの削除
Posted: 2009年11月14日(土) 17:27
by softya
あまり私が調べすぎるのも、本人の成長の阻害になる気がするのでヒントだけにとどめます。
1.ブレークで登録が出来ているとの事ですが、リストがちゃんと出来ているかOutputDebugStringなどで確認しましたか?
2.消滅エフェクトの処理側でリストがちゃんと処理されていますか?消滅エフェクトの何処まで処理されているかトレースしてみてください。
Re:ポインタの削除
Posted: 2009年11月14日(土) 18:53
by ひよこ
おそらくこれが悪いのだと思いますが、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
Re:ポインタの削除
Posted: 2009年11月14日(土) 19:02
by softya
またズレてませんか?
リビルドしてみてください。
Re:ポインタの削除
Posted: 2009年11月14日(土) 20:13
by ひよこ
ズレてるの意味がわかりませんが、リビルドして下のようになりました。
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);
としています。
Re:ポインタの削除
Posted: 2009年11月15日(日) 14:26
by softya
nextが何処で1になるかステップ実行して確認してください。
p->ang,p->brtは表示する型が違っています。
Re:ポインタの削除
Posted: 2009年11月15日(日) 15:44
by ひよこ
あ、こんなところに原因がありました。graph_effect(0);//敵が死ぬエフェクトがないのが原因のようです。
いろいろとすみません。ただいま消滅エフェクトの拡大現象を修正中です。
Re:ポインタの削除
Posted: 2009年11月15日(日) 15:54
by ひよこ
よくみたら、初期化忘れでcntの値がおかしかったようです。
softyaさん、いろいろとありがとうございました。また、おかしくて直らない場所があったら
質問します、その時はよろしくお願いします。
Re:ポインタの削除
Posted: 2009年11月15日(日) 15:55
by ひよこ
解決にします。
Re:ポインタの削除
Posted: 2009年11月15日(日) 22:43
by softya
とりあえず、アドバイスを。
・落ち着いてよく調べる事を心がけてください。
・ステップ実行は、自分のプログラムの気づかないバグを気づかせてくれるので、作ってすぐはなるべく実行するようにしてくださいね。
・バグは自分の理解度を深めるチャンスです。粘り強く調べてください。
・ポインタ系のバグはOutputDebugStringなどを多用して情報を収集すること。
・特にリストは作ってすぐの時は必ずちゃんと情報が格納されているか確認する事。大抵は失敗があります。
以上です。
では、プログラミングを楽しんでください。
Re:ポインタの削除
Posted: 2009年11月16日(月) 17:25
by ひよこ
いろいろとありがとうございます。
できるだけ努力します。