0

ncurses でボールを左右にバウンドさせようとしています。通常の構造体を印刷し、その構造体のポインターを関数に渡すと、これを正常に機能させることができます。

次のコードを実行すると、構造体要素のメモリ アドレスと思われるものが出力され、それらのアドレスに含まれる実際の値は出力されません。私が理解していないのは、最初のコードが機能しないのに、2 番目のコードが機能する理由です。私はポインターを台無しにしていると確信していますが、どこにあるのかわかりません。

悪いコード、

typedef struct Ball ball;

int width=80, height=20; //screen height/width in characters

struct Ball{
    char shape;
    int x;
    int y;
    int velX; 
    int velY;
};

ball* initBall(int X, int Y, int velx, int vely, char shape){
    ball b;
    ball *p = &b;
    p->x = X;
    p->y = Y;
    p->velY = vely;
    p->velX = velx;
    p->shape = shape;

    return p;
}

void moveBall(ball *b){
    if(b->x +b->velX > width || b->x + b->velX < 0){
        b->velX *= -1;
    }

    if(b->y +b->velY > height || b->y +b->velY< 0){
        b->velY *= -1;
    }

    b->x += b->velX;
    b->y += b->velY;
}

int main(){
    ball *p = initBall(40,10,1,0, 'O');

    int counter=0;
    while(counter < 10){
        printf("%d, %d\n", p->x, p->y);

        moveBall(p);

        counter++;
    }

    return 0;
}

良いコード、

typedef struct Ball ball;

int width=80, height=20; //screen height/width in characters

struct Ball{
    char shape;
    int x;
    int y;
    int velX; 
    int velY;
};

ball initBall(int X, int Y, int velx, int vely, char shape){
    ball b;
    ball *p = &b;
    b.x = X;
    b.y = Y;
    b.velY = vely;
    b.velX = velx;
    b.shape = shape;

    return b;
}

void moveBall(ball *b){
    if(b->x +b->velX > width || b->x + b->velX < 0){
        b->velX *= -1;
    }

    if(b->y +b->velY > height || b->y +b->velY< 0){
        b->velY *= -1;
    }

    b->x += b->velX;
    b->y += b->velY;
}

int main(){
    ball b = initBall(40,10,1,0, 'O');
    ball *p = &b;

    int counter=0;
    while(counter < 10){
        printf("%d, %d\n", p->x, p->y);

        moveBall(p);

        counter++;
    }

    return 0;
}
4

4 に答える 4

1

悪いコードでは、 内のローカル変数へのポインタを返していますinitBall。から戻ると、このポインターは無効になりinitBall、別の関数を呼び出すと、構造体の内容が他のデータで上書きされる可能性が高くなります。

適切なコードでは、構造体へのポインターを返すのではなく、構造体全体 (つまり、構造体のコピー) を返すので、これは問題になりません。戻ったときに構造体全体をコピーしてもかまわない場合は、適切なコードに固執してください (非効率的である可能性があります)。それ以外の場合は、動的メモリ割り当てを使用します。

于 2013-11-01T09:07:05.320 に答える
1

悪いコードinitBall()

ball* initBall(int X, int Y, int velx, int vely, char shape){
    ball b;
    ball *p = &b;
    ...
    return p;
}

ローカル変数のアドレスを返していますが、これは正しくありません。関数が戻ると、そのメモリ位置の内容が変更されます。

適切なコードでは、構造体を値として返すため、値は にコピーされmain()ます。

修正は次のようになります。

ball* initBall(int X, int Y, int velx, int vely, char shape){
    ball b;
    ball *p = malloc(sizeo(*p));

    ...
    return p;
}

終わったら忘れずにfree()

于 2013-11-01T09:08:56.070 に答える
0

initBallローカル変数へのポインターを返すときの未定義の動作があります。変数のスコープはb関数で終わることに注意してください。そのため、関数がポインターを返した後は無効になります。

代わりに、構造体をヒープに割り当てたい場合があります。

于 2013-11-01T09:06:28.150 に答える
0

ローカル変数のアドレスを返していますが、変数が存在する関数が終了したため、すぐに無効になります。

これは有効なコードではありません。

割り当てを行うか、範囲外にならないヒープ メモリを割り当てるためにstatic使用する必要があります。malloc()

これ:

ball* initBall(int X, int Y, int velx, int vely, char shape){
  ball b;
  ball *p = &b;

次のようにする必要があります。

ball * initBall(int X, int Y, int velx, int vely, char shape){
  ball *b = malloc(sizeof *b);
  if(b != NULL) {
    b->x = X;
    /* and so on */
  }
  return b;
}
于 2013-11-01T09:06:34.307 に答える