2013-11-01 52 views
0

我想在ncurses中將球反彈到一邊。如果我打印普通結構並通過函數傳遞所述結構的指針,我可以很好地工作。使用帶指針的結構的問題

當我運行下面的代碼時,它會打印出我認爲是結構元素的內存地址,而不是這些地址中包含的實際值。我不明白的是爲什麼第一段代碼不起作用,但第二段代碼不起作用。我很確定我搞亂了指針,但我不知道在哪裏。

的惡意代碼,

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; 
} 
+2

如果你編譯的時候啓用了警告,你會得到這樣的警告:'「警告:返回局部變量的地址」'......應該響鈴。 – 2013-11-01 09:07:14

回答

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()完成它的時候。

0

當您返回一個指針指向一個局部變量您已經initBall未定義的行爲。請記住變量b的作用域以該函數結束,所以在函數返回指向它的指針不再有效之後。

您可能想要在堆上分配結構。

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

在糟糕的代碼,你在裏面initBall返回一個指針到一個局部變量。一旦從initBall返回,此指針將無效,並且在調用另一個函數時,結構的內容很可能會被其他數據覆蓋。

在良好的代碼中,您沒有返回指向結構體的指針,而是返回整個結構體 - 也就是結構體的副本,所以這不是問題。如果您不介意在返回時複製整個結構(可能效率低下),請堅持使用優秀的代碼;否則,使用動態內存分配。