0

I'm hitting a wall with the last few steps of breakout, so all help appreciated.

When the pre-written updateScoreboard function is called (after the ball hits a brick), the program freezes and I get a segmentation fault (core dumped). Here's my code.

Also more generally, how does one go about debugging a segmentation fault? Is there any way to get hints about what's going wrong?

// prototypes
void initBricks(GWindow window);
GOval initBall(GWindow window);
GRect initPaddle(GWindow window);
GLabel initScoreboard(GWindow window);
void updateScoreboard(GWindow window, GLabel label, int points);
GObject detectCollision(GWindow window, GOval ball);
GLabel scoreboard;

int main(void)
{
    // seed pseudorandom number generator
    srand48(time(NULL));

    // instantiate window
    GWindow window = newGWindow(WIDTH, HEIGHT);

    // instantiate bricks
    initBricks(window);

    // instantiate ball, centered in middle of window
    GOval ball = initBall(window);

    // instantiate paddle, centered at bottom of window
    GRect paddle = initPaddle(window);

    // instantiate scoreboard, centered in middle of window, just above ball
    GLabel label = initScoreboard(window);

    // number of bricks initially
    int bricks = COLS * ROWS;

    // number of lives initially
    int lives = LIVES;

    // number of points initially
    int points = 0;

    // initial velocity
    double velocity_x = drand48() * 2;
    double velocity_y = 2;

    // keep playing until game over
    while (lives > 0 && bricks > 0)
    {
        // tracks cursor 
        GEvent event = getNextEvent(MOUSE_EVENT);

        // detect collision
        GObject object = detectCollision(window, ball);

        // move ball
        move(ball, velocity_x, velocity_y);

        // bounce off left or right edge of window
        if ((getX(ball) + getWidth(ball) >= WIDTH) || (getX(ball) <= 0))
        {
            velocity_x = -velocity_x;
        }

        // bounce off top or bottom edge of window
        if (getY(ball) <= 0)
        {
            velocity_y = -velocity_y;
        }

        // pause game and lose life if hits bottom edge
        if (getY(ball) + getHeight(ball) >= HEIGHT)
        {
            lives--;

            // pause the game untill mouse click, move ball to center
            waitForClick();
            addAt(window, ball, (WIDTH / 2) - RADIUS, (HEIGHT / 2) - RADIUS );
        }


        // if object is hit
        if (object != NULL)
        {
            // bounce object off paddle
            if (object == paddle)
            {
                if (velocity_y > 0)
                    velocity_y = -velocity_y;
            }
            // bounce object off of bricks and delete bricks
            else if (strcmp(getType(object), "GRect") == 0)
            {
                removeGWindow(window, object);
                velocity_y = -velocity_y;
                points++;
                updateScoreboard(window, scoreboard, points);
            }
        }    
        // linger before moving again
        pause(10);

        if (event != NULL)
        {
            // ensure paddle follows cursor
            double x = getX(event) - (PADDLE_WIDTH / 2);
            setLocation(paddle, x, HEIGHT - PADDLE_HEIGHT - 60);    
        }
    }

    // wait for click before exiting
    waitForClick();

    // game over
    closeGWindow(window);
    return 0;
}

/**
 * Initializes window with a grid of bricks.
 */
void initBricks(GWindow window)
{
    // build rows of bricks
    int spacer = (WIDTH / (COLS + 1)) / COLS;
    int brick_width = WIDTH / (COLS + 1);
    char* color[] = {"RED", "ORANGE", "YELLOW", "GREEN", "BLUE"};

    for (int n = 0, ybrick = 30; n < ROWS; n++, ybrick = ybrick + 23)
    {
        for (int i = 0, xbrick = 2 * spacer; i < COLS; i++, xbrick = xbrick + brick_width + spacer)
        {
            // instantiate a brick
            GRect brick = newGRect(xbrick, ybrick, brick_width, 15);
            setFilled(brick, true);
            setColor(brick, color[n]);
            add(window, brick);
        }
    }

}

/**
 * Instantiates ball in center of window.  Returns ball.
 */
GOval initBall(GWindow window)
{
    // Instantiates ball
    GOval ball = newGOval((WIDTH / 2) - RADIUS, (HEIGHT / 2) - RADIUS, RADIUS * 2, RADIUS * 2);
    setFilled(ball, true);
    add(window, ball);
    return ball;
}

/**
 * Instantiates paddle in bottom-middle of window.
 */
GRect initPaddle(GWindow window)
{
    // instantiates paddle
    GRect paddle = newGRect((WIDTH - PADDLE_WIDTH) / 2, HEIGHT - PADDLE_HEIGHT - 60, PADDLE_WIDTH, PADDLE_HEIGHT);

    // fills paddle
    setFilled(paddle, true);

    // adds paddle to window
    add(window, paddle);

    return paddle;
}

/**
 * Instantiates, configures, and returns label for scoreboard.
 */
GLabel initScoreboard(GWindow window)
{
    // Instantiates scoreboard
    GLabel scoreboard = newGLabel("");
    setFont(scoreboard, "SanSerif-36");
    add(window, scoreboard);
    setLocation(scoreboard, (getWidth(window) - getWidth(scoreboard)) / 2, (getHeight(window) - getHeight(scoreboard)) / 2);
    setLabel(scoreboard, "0");
    return scoreboard;
}

/**
 * Updates scoreboard's label, keeping it centered in window.
 */
void updateScoreboard(GWindow window, GLabel label, int points)
{
    // update scoreboard
    char s[12];
    sprintf(s, "%i", points);
    setLabel(label, s);

    // center label in window
    double x = (getWidth(window) - getWidth(label)) / 2;
    double y = (getHeight(window) - getHeight(label)) / 2;
    setLocation(label, x, y);
}

/**
 * Detects whether ball has collided with some object in window
 * by checking the four corners of its bounding box (which are
 * outside the ball's GOval, and so the ball can't collide with
 * itself).  Returns object if so, else NULL.
 */
GObject detectCollision(GWindow window, GOval ball)
{
    // ball's location
    double x = getX(ball);
    double y = getY(ball);

    // for checking for collisions
    GObject object;

    // check for collision at ball's top-left corner
    object = getGObjectAt(window, x, y);
    if (object != NULL)
    {
        return object;
    }

    // check for collision at ball's top-right corner
    object = getGObjectAt(window, x + 2 * RADIUS, y);
    if (object != NULL)
    {
        return object;
    }

    // check for collision at ball's bottom-left corner
    object = getGObjectAt(window, x, y + 2 * RADIUS);
    if (object != NULL)
    {
        return object;
    }

    // check for collision at ball's bottom-right corner
    object = getGObjectAt(window, x + 2 * RADIUS, y + 2 * RADIUS);
    if (object != NULL)
    {
        return object;
    }

    // no collision
    return NULL;
}
1

The problem is here: updateScoreboard(window, scoreboard, points); While scoreboard exists as a GLabel variable, it has never been assigned any value. The variable scoreboard is copied into updateScoreboard successfully, as the local variable label, but when you try to use it at setLabel(label, s);, the code is trying to access an unassigned memory location, triggering a seg fault.

Throughout the rest of the code, you are using the GLabel variable of label for the scoreboard. Make the change and it works fine.

As for how to resolve a seg fault in general, there are a number of techinques. First, you need to identify which line is causing the problem. Having done that, you need to break that statement down and determine which part of the statement is triggering it. One way to identify the offending line is to step through the program using gdb. Another is to selectively place printf statements in the code to locate the offending line of code.

BTW, you need to work on some code to end the program when all 50 bricks are deleted.

If this answers your question, please accept this answer to close the question. Let's keep up on forum maintenance. ;-)

3
  • I'm sorry, I don't completely understand. Hasn't scoreboard been declared with an assigned value of 0 at the top of main before the while loop? And that's certainly before updateScoreboard is called. Where is the unassigned memory issue? I'm sure this is something obvious, but I've staring at it so long I'm having trouble seeing it. – Jon Levin Jul 16 '15 at 19:55
  • No, scoreboard is not a number, it is a GLabel object. When you create it with GLabel scoreboard; you have allocated the variable, but you have not yet assigned an actual object to it. It is not initialized. That's what's causing the seg fault, trying to access a nonexistent object. BUT, that's not your real problem. scoreboard isn't your actual scoreboard object. label is the actual scoreboard object. You're confusing two vars for the same object, one of which isn't doing anything. – Cliff B Jul 16 '15 at 20:00
  • Got it. Thank you. – Jon Levin Jul 16 '15 at 20:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .