0

I'm trying to make a program to move a box based on keyboard input, but at the moment it's only set up to render a green rectangle on the screen. However, the program seems to initialize the window, then return nothing more than "Segmentation fault (core dumped)" before terminating. I get no compiler errors at all, and a fair bit of the code matches tutorials I've found online. If it makes a difference, I'm running Code::Blocks on Ubuntu using GCC.

main basically calls functions called init, drawRect, and close (all shown below) in that order, printing statements based on success or failure.

EDIT: Narrowed it down to close, shown below. In particular, it's SDL_FreeSurface and SDL_Quit giving me issues. I've also cleaned up close (and other parts of the program) in regards to pointer handling and made a new pastebin file.

close:

void close()
{
   // Deallocate gScreenSurface
   SDL_FreeSurface(gScreenSurface);
   gScreenSurface=NULL;

   // Destroy renderer
   SDL_DestroyRenderer(gRenderer);
   gRenderer=NULL;

   // Destroy gWindow
   SDL_DestroyWindow(gWindow);
   gWindow=NULL;

   SDL_Quit();
}

Here's the new full sourcecode, complete with pointer initializations, includes, and pseudocode:

/* === Includes === */
#include <cstdlib>
#include <stdio.h>
#include "SDL2/SDL.h"

using namespace std;

/* === Constants === */
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

/* === Enums === */
/*enum Keys {KEY_DEFAULT,
           KEY_UP,
           KEY_DOWN,
           KEY_LEFT,
           KEY_RIGHT,
           KEY_TOTAL};*/

/* === Prototypes === */

bool init();
bool drawRect(SDL_Renderer* pRenderer, SDL_Rect* pRect, int pX, int pY, int pW, int pH, int pR, int pG, int pB, int pA);
void close();

/* === Pointer Initialization === */
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
SDL_Renderer* gRenderer = NULL;
SDL_Rect* gRect = NULL;

/**==================================================
Box Mover

This was intended to be a learning activity to
teach myself how to use SDL, in particular basic
"block" graphics and keyboard inputs.

Unfortunately, I can't figure out why it's always
returning seg fault. I think it's outside of main,
but I can't be sure.
==================================================**/

int main()
{
   if(!init())
      printf("Failed to initialize!\n");
   else
   {
      if(!drawRect(gRenderer, gRect, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 255, 0, 255))
         printf("Failed to draw rectangle!\n");
      else
      {
         /*SDL_BlitSurface( gImage, NULL, gScreenSurface, NULL);
         SDL_UpdateWindowSurface(gWindow);
         SDL_Delay(2000);*/
         printf("Success in main!\n"); // Placeholder until I figure out why I'm getting a seg fault, then I can fix the contents.
      }
   }
   close();

   return 0;
}

/*=========================
Init

Initializes SDL
Returns true for success, false for failure
Prints error on failure
=========================*/
bool init()
{
   //Initialization flag
   bool success = true;
   if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
   {
      printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
      success = false;
   }
   else
   {
      gWindow = SDL_CreateWindow( "Box Mover", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 );
      if( gWindow == NULL )
      {
         printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
         success = false;
      }
      else
      {
         gScreenSurface = SDL_GetWindowSurface( gWindow );
      }
   }
   return success;
}

/*=========================
Draw Rectangle

Draws a rectangle of specified color and location

TO DO:
Check to see if renderer needs to be deallocated here.

Inputs:
>> pRenderer:     SDL_Renderer pointer which can be thought of as a drawing tool
>> pRect:         SDL_Rect pointer which holds location and size data
>> pX, pY:        X-Y location of the upper left corner of the rectangle
>> pR, pG, pB:    Color values (technically Uint8, 0-255)
>> pA:            Alpha (transparency) value of the rectangle (also technically Uint8)
=========================*/
bool drawRect(SDL_Renderer* pRenderer, SDL_Rect* pRect, int x, int y, int w, int h, int r, int g, int b, int a)
{
   bool success = true;

   pRenderer=SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_SOFTWARE);
   if(pRenderer==NULL)
   {
      printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
      success=false;
   }
   else
   {
      pRect = new SDL_Rect;
      if(pRect == NULL)
      {
         printf("Could not create rectangle! SDL Error: %s\n", SDL_GetError());
         success=false;
      }
      else
      {
            pRect->x = x;
            pRect->y = y;
            pRect->w = w;
            pRect->h = h;

         SDL_SetRenderDrawColor(pRenderer, r, g, b, a);

         if(SDL_RenderDrawRect(pRenderer, pRect) < 0)
         {
            printf("Rectangle could not be rendered! SDL Error: %s\n", SDL_GetError());
            success=false;
         }
      }
   }
   return success;
}

/*=========================
Close

Closes the SDL systems cleanly, deallocating memory.

Found the seg fault! It's this fucker!
In particular, SDL_FreeSurface and SDL_Quit
=========================*/
void close()
{
   // Deallocate gScreenSurface
   SDL_FreeSurface(gScreenSurface);
   gScreenSurface=NULL;
   printf("Surface closed. Working on renderer...\n");

   // Destroy renderer
   SDL_DestroyRenderer(gRenderer);
   gRenderer=NULL;
   printf("Renderer closed. Working on window...\n");

   // Destroy gWindow
   SDL_DestroyWindow(gWindow);
   gWindow=NULL;
   printf("Window closed. Working on SDL...\n");

   SDL_Quit();
   printf("SDL closed.\n");
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
Alex G.
  • 1
  • 1
  • 2
  • 4
    Build with extra warnings enabled, and fix them if you get any. And build with debug information, and run in a debugger to catch the crash in action to locate where it happens. – Some programmer dude Apr 04 '17 at 17:44
  • 1
    Y'all need some RAII in your life. – jaggedSpire Apr 04 '17 at 17:52
  • Did you test this example first? https://wiki.libsdl.org/SDL_CreateWindow – Rama Apr 04 '17 at 18:09
  • @Someprogrammerdude I have all warnings enabled, including -Wextra and -pedantic. Nothing pops up. – Alex G. Apr 08 '17 at 01:08
  • @jaggedSpire Can you point me in the direction of some learning material? I get the idea, I'm just not sure how to implement it. – Alex G. Apr 08 '17 at 01:16
  • For a c-style API like SDL2? boy are you [in luck](http://stackoverflow.com/questions/39176805/). You'll also want to follow the link in the question to the related question--it asks for a more complete encapsulation – jaggedSpire Apr 08 '17 at 01:52

2 Answers2

1

You're passing the SDL_Renderer *renderer pointer to your drawRect function by value, and initialising it in that function. That's not initialising the pointer you have in global scope, it's initalising a copy of it which is lost when you exit the function. You're then in close calling SDL_DestroyRenderer on the pointer from global scope, which is NULL.

If you want to initialise the global inside your drawRect function you need to pass a pointer to a pointer (SDL_Renderer **) to the function.

In your drawRect function you're calling SDL_RenderDrawRect, this is rendering the rectangle onto a back buffer, to then draw it on the screen you need to use a call to SDL_RenderPresent

Colin
  • 3,394
  • 1
  • 21
  • 29
  • This was probably at least part of my problem. Unfortunately, I now have more. (Story of my life tbh.) – Alex G. Apr 08 '17 at 01:16
0

Don't try to free the surface returned from SDL_GetWindowSurface(), SDL manages the lifetime of the returned pointer itself:

gScreenSurface = SDL_GetWindowSurface( gWindow );
...
SDL_FreeSurface(gScreenSurface);

See the docs for SDL_GetWindowSurface() (emphasis mine):

Remarks

A new surface will be created with the optimal format for the window, if necessary. This surface will be freed when the window is destroyed. Do not free this surface.

genpfault
  • 51,148
  • 11
  • 85
  • 139