2009-04-26 6 views
1

私は配列に新しいボールを追加したいボールと呼ばれる構造体、ボールの数、ボールの配列と機能があります。のrealloc

構造体:

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); 
} 

とメイン内の関数呼び出し:

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() 
+3

もっと深くは見えませんでしたが、最初の関数行 "num_balls ++;" "* num_balls ++;"にする必要があります。例えば。アドレスの代わりに整数を増やす – Kamarey

+0

mallocとreallocの戻り値を常にチェックする必要があります。毎回結果をチェックするのが怠惰な場合は、プログラムを中止するラッパーを使用してください。 –

+0

'myballs = realloc(* myballs、* num_balls * sizeof(ball));を置き換えます。 '* myballs = realloc(* myballs、* num_balls * sizeof(ball));で' –

答えて

3
*myballs[*num_balls-1]->x 

これはあまりにも多くの1時間を逆参照 - myballsは、ポインタの配列された(または、別の言い方をすれば、ポインタの配列の最初の要素へのポインタ) - myballの前でアスタリスクを失うだけで、構造体にアクセスできるポインタが得られます(または - >をaに変換します)。シンボル - >は、逆参照ポインタから構造体へのポインタではなく、その構造体へのポインタから構造体のメンバにアクセスするための略語です。あなたの修正add_ballsで

myballs[*num_balls-1]->x 

または

(*myballs[*num_balls-1]).x 
+0

ポインタのない、myballs /である/アレイの前に(あるいは別の言い方をすれば、それはボールのポインタへのポインタだ)「*」とし、なしの両方のエラーが出ています。それがポインタの配列へのポインタだった場合、その宣言は次のようになります。ボール***マイボール; しかし、あなたが指定したコードは正しいです。このコメントを削除します。 –

+0

myballsがポインタの配列であると想定されている場合、その配列が大きくなるとその配列を再配置するために、別のレベルの間接指定が必要です。私のお金はオンです(* myballs [* num_balls-1])。 – bk1e

+0

よろしく、ありがとうございました。 –

4

あなたは++(* num_balls)、あなたが実際にポインタの内容を増やしたい、ポインタnum_ballsを高める機能。

3

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

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

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()が動作することがわかるまで、新しいポインタ(または新しいカウント)を保存しないほうがよいでしょう。

3

オリジナルのコードは正しいものに非常に近いものでした。最初の問題は比較的簡単に解決できます。ライン

num_balls++; 

はあなたがnum_ballsが指摘する場所をインクリメントするのではなく、それが指されている値をインクリメントした

(*num_balls)++; 

でなければなりません。後で逆参照すると、他のメモリを指していました。この特定の使用シナリオでは、スタックの次のローカル変数を指していた可能性があります。bgmain()です。

他の問題は操作の問題の順序です。ライン

*myballs[*num_balls-1]->x = rand() % 640; 

*(myballs[*num_balls-1]->x) = rand() % 640 

myballsと同等であるので、配列のインデックスは、逆参照よりも高い演算子の優先順位を有するballの配列へのポインタへのポインタです。 *num_balls-1が0以外の場合は、間違ったメモリにアクセスします。それにかかわらず、メンバ変数xはポインタではないので、逆参照することはできません。したがって、コンパイラは構文エラーでここに保存します。正しいコードは、配列のインデックスを取る前に、あなた間接参照を確認することです。

(*myballs)[*num_balls-1].x = rand() % 640; 

これはつまり、元の配列へのポインタを取得するためのポインタを参照解除したい要素を取って、とに割り当て、何をしたいんメンバ変数xadd_ball()の残りの行は、同様に書き換えなければなりません。

あなたのコードに関するもう1つの問題は、正確さよりもパフォーマンスに問題があることです。ボールごとにblue_ball.bmpイメージを再読み込みしています。 ビットマップを一度だけロードして、各ボールが毎回それをリロードするのではなく、その1つのインスタンスを参照するようにする方が良いでしょう。