1

ball という構造体、いくつかのボール、ボールの配列、および配列に新しいボールを追加する関数があります。

構造体:

typedef struct ball{
    BITMAP *image;
    int x;
    int y;
    int vector_x;
    int vector_y;
} ball;

(非動作機能):

void add_balls(int *num_balls, ball **myballs){
    num_balls++;
    *myballs = realloc(*myballs, *num_balls * sizeof(ball));
    *myballs[*num_balls-1]->x =  rand() % 640;
    *myballs[*num_balls-1]->y = rand() % 480;
    *myballs[*num_balls-1]->vector_x = rand() % 10;
    *myballs[*num_balls-1]->vector_y = rand() % 10;
    *myballs[*num_balls-1]->image = load_bitmap("blue_ball.bmp", NULL); 
 }

および main 内の関数呼び出し:

add_balls(&num_balls, &myballs);

関数の呼び出しが失敗し、次のエラー メッセージが表示されます。

p.c: In function ‘add_balls’:
p.c:19: error: invalid type argument of ‘unary *’
p.c:20: error: invalid type argument of ‘unary *’
p.c:21: error: invalid type argument of ‘unary *’
p.c:22: error: invalid type argument of ‘unary *’
p.c:23: error: incompatible types in assignment

何か助けはありますか?

それは役に立ちました。これでコンパイルできますが、実行時にセグメンテーション違反エラーが発生します。興味がある場合は、完全なコードを次に示します。

#include <allegro.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define NUM_BALLS 10

typedef struct ball{
    BITMAP *image;
    int x;
    int y;
    int vector_x;
    int vector_y;
} ball;

void add_balls(int *num_balls, ball **myballs){
    num_balls++;
    myballs = realloc(*myballs, *num_balls * sizeof(ball));
    myballs[*num_balls-1]->x =  rand() % 640;
    myballs[*num_balls-1]->y = rand() % 480;
    myballs[*num_balls-1]->vector_x = rand() % 10;
    myballs[*num_balls-1]->vector_y = rand() % 10;
    myballs[*num_balls-1]->image = load_bitmap("blue_ball.bmp", NULL);  
 }

int main() 
{
    allegro_init();
    install_keyboard();
    srand(time(0));

    install_timer();

    set_color_depth(32);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640,480,0,0);

    BITMAP *buffer = NULL;
    buffer = create_bitmap(640,480);

    ball *myballs;
    myballs  = malloc(NUM_BALLS * sizeof(ball));
    int num_balls = NUM_BALLS;

    BITMAP *bg = NULL;
    bg = load_bitmap("bg.bmp",NULL);

    int i;
    for(i=0;i<num_balls;i++){
        myballs[i].x =  rand() % 640;
        myballs[i].y = rand() % 480;
        myballs[i].vector_x = rand() % 10;
        myballs[i].vector_y = rand() % 10;
        myballs[i].image = load_bitmap("blue_ball.bmp", NULL);
    }

    int bg_vector_x;
    float bg_vector_y;

    while(!key[KEY_ESC]){
        vsync();
        for(i=0;i<num_balls;i++){

            if(myballs[i].x + myballs[i].vector_x > 640 || myballs[i].x + myballs[i].vector_x < 0){
                myballs[i].vector_x *= -1;
            }
            if(myballs[i].y + myballs[i].vector_y > 480 || myballs[i].y + myballs[i].vector_y < 0){
                myballs[i].vector_y *= -1;
            }

            myballs[i].x += myballs[i].vector_x;
            myballs[i].y += myballs[i].vector_y;
        }

        if(key[KEY_UP]){
            add_balls(&num_balls, &myballs);
        }

        clear_bitmap(buffer);

        int ii;     
        for(i=0;i<3;i++){
            for(ii=-1;ii<3;ii++){
                draw_sprite(buffer, bg ,(bg_vector_x%528)+(i*528),100*cos(bg_vector_y) + ii*353);       
            }
        }
        bg_vector_x++;
        bg_vector_y+=0.1;

        for(i=0;i<num_balls;i++){
            draw_sprite(buffer, myballs[i].image, myballs[i].x,myballs[i].y);
        }

        blit(buffer, screen, 0,0,0,0,640,480);
    }

    for(i=0;i<num_balls;i++){
        destroy_bitmap(myballs[i].image);
    }
    free(myballs);
    destroy_bitmap(buffer);
}

END_OF_MAIN()
4

5 に答える 5

4

変更した add_balls 関数では、ポインター num_balls を増やします。実際には、ポインターの内容 (*num_balls)++ を増やしたいと考えています。

于 2009-04-26T20:00:08.430 に答える
3

Adam Rosenfield と Baruch Even の回答に加えて、失敗したときに何が起こるかを検討する必要がありrealloc()ます。

p = realloc(p, s)失敗するとポインターが設定されますが、NULL以前に指していたメモリの割り当てが解除されないため、危険です。これが発生すると、プログラムはメモリの元のブロックをリークすることになります (最初にクラッシュしない場合)。代わりに、 の結果realloc()を別の変数に代入して、 が返されるケースを処理できるようにする必要がありますNULL

于 2009-04-26T23:04:05.240 に答える
3
*myballs[*num_balls-1]->x

これは何度も逆参照します - myballs はポインターの配列です (別の言い方をすれば、ポインターの配列の最初の要素へのポインターです) - myballs の前のアスタリスクを失うだけで、構造体にアクセスできます(または、 -> を . に変えます)。シンボル -> は、構造体への逆参照ポインターからではなく、その構造体へのポインターから構造体のメンバーにアクセスするための省略形です。

myballs[*num_balls-1]->x

また

(*myballs[*num_balls-1]).x
于 2009-04-26T19:10:40.390 に答える
2

あなたがやろうとしていることを私が理解していると仮定すると、次のような(テストされていない)方が良いです:

#include <assert.h>

void add_balls(int *num_balls, ball **myballs){
    int n = ++*num_balls;
    ball *pb = realloc(*myballs, n * sizeof(ball));

    /* fail loudly and early on lack of memory. */
    assert(pb); 
    *myballs = pb;

    /* note the pre-decrement of n here to make obvious the common n-1 */
    pb[--n]->x =  rand() % 640;
    pb[n]->y = rand() % 480;
    pb[n]->vector_x = rand() % 10;
    pb[n]->vector_y = rand() % 10;
    pb[n]->image = load_bitmap("blue_ball.bmp", NULL); 
 }

最初に記述された配列要素参照に十分な括弧を使用して、すべての演算子の優先順位を正しくすることは可能ですが、結果は基本的に人間には判読できません。以前のように、 の右から左への結合性->は の左から右への結合性と奇妙に混ざり合っており*、配列インデックスによってさらに混乱しています。

エラー処理を改善したい場合があります。特に、メモリが利用できない場合は、ボールの追加をまったく拒否するのが理にかなっています。realloc()その場合、新しいポインタ (または新しいカウント) が機能することがわかるまで、そのポインタ (または新しいカウント) を保存しない方がよいでしょう。

于 2009-04-26T23:33:52.423 に答える