0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

構造体配列への書き込みはアドレスを渡して行う

Last updated at Posted at 2019-07-22

自分用のメモです

構造体配列に書き込むときに
「アドレス渡しにしなかったことで書き込めていなかった」
というバグを何回かやらかしたのでメモ

以下の構造体bombを配列(キュー)として扱いたい

//爆弾の構造体 座標(x,y) と 残り時間time を保持する
typedef struct {
    int x, y;
    int time;
} bomb;

bomb bomb_queue[QUEUE_SIZE];  //bomb構造体の配列(キューとして扱う)
int bq_head;                  //キューの先頭要素の位置
int bq_num;                   //キューの要素数

この構造体配列に書き込むとき
以下のようにいちいち配列にアクセスしたくないので

//新しい爆弾を座標(x,y)にセット 
void set_new_bomb_1(int x, int y) {
    bomb_queue[bq_head+bq_num].x = x;
    bomb_queue[bq_head+bq_num].y = y;
    bomb_queue[bq_head+bq_num].time = 10000;
    bq_num++;
}

以下のように書いて エラーを起こした
tbomb に 構造体配列のアドレスを渡していないので
tbomb.x = x としても 構造体配列bomb_queueの要素に書き込めていない (コンパイルは通る)
tbomb.xに書き込んでもtbombはこの関数を抜けるときに消える

void set_new_bomb_bug(int x, int y) {
    bomb tbomb = bomb_queue[bq_head+bq_num];
    tbomb.x = x;
    tbomb.y = y;
    tbomb.time = 10000;
    bq_num++;
}

正しくは以下のようにする
bomb型のポインタtbombを宣言し, 書き込みたい構造体配列のアドレスを渡す

void set_new_bomb_2(int x, int y) {
    bomb *tbomb = &bomb_queue[bq_head+bq_num];
    tbomb->x = x;
    tbomb->y = y;
    tbomb->time = 10000;
    bq_num++;
}

まとめ

pointer_bug.c
//
//  pointer_bug.c
//
//  ポインタでやってしまったバグ
//

#include <stdio.h>
#include <string.h> //memcpy実装に必要

#define QUEUE_SIZE 100

//爆弾の座標(x,y)と残り時間timeを保持する構造体bomb
typedef struct {
    int x, y;
    int time;
} bomb;

bomb bomb_queue[QUEUE_SIZE];  //bomb構造体の配列(キューとして扱う)
int bq_head;                  //キューの先頭要素の位置
int bq_num;                   //キューの要素数

//新しい爆弾を座標(x,y)にセット 
void set_new_bomb_1(int x, int y) {
    bomb_queue[bq_head+bq_num].x = x;
    bomb_queue[bq_head+bq_num].y = y;
    bomb_queue[bq_head+bq_num].time = 10000;
    bq_num++;
}

//上のようにいちいち配列アクセスしたくないので以下のように書いた
//しかし tbomb に 構造体配列のアドレスを渡していないので
//tbomb.x = x としても 構造体配列bomb_queueの要素に書き込めていない    (コンパイルは通る)
void set_new_bomb_bug(int x, int y) {
    bomb tbomb = bomb_queue[bq_head+bq_num];
    tbomb.x = x;
    tbomb.y = y;
    tbomb.time = 10000;
    bq_num++;
}

//正しくは以下のようにする
//bomb型のポインタtbombを宣言し, 書き込みたい構造体配列のアドレスを渡す
void set_new_bomb_2(int x, int y) {
    bomb *tbomb = &bomb_queue[bq_head+bq_num];
    tbomb->x = x;
    tbomb->y = y;
    tbomb->time = 10000;
    bq_num++;
}


int main() {
    set_new_bomb_1(10, 20);
    printf("bomb x=%d, y=%d\n", bomb_queue[0].x, bomb_queue[0].y);
    /*  ↑   bomb x=10, y=20 と正しく表示される */
    set_new_bomb_bug(30, 40);
    printf("bomb x=%d, y=%d\n", bomb_queue[1].x, bomb_queue[1].y);
    /*  ↑   bomb x=0, y=0 と不正な値が表示される */
    set_new_bomb_2(50, 60);
    printf("bomb x=%d, y=%d\n", bomb_queue[2].x, bomb_queue[2].y);
    /*  ↑   bomb x=50, y=60 と正しく表示される */


}

0
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?