Hai all,

I ran into a strange issue I never experienced before. Pointers are passed to function, the function allocates memory to them with calloc, and right before the return sanity checks if the pointers still != NULL. That check succeeds, but upon returning and sanity checking in the calling function, all pointers == NULL.

The code is pretty big, so I won't copypaste it all in here but instead i've attached them.

For those unfamiliar with OpenGL: The compiler line for this is:
gcc.exe BowViceJet.c -o BowViceJet.exe -lopengl32 -lglu32 -lgdi32 -Wall

The function I'm talking about is loadObj. As you can see, right before returning it checks:

if(vertices == NULL || normals == NULL || verttext == NULL || triangleindex == NULL || trianglenormals == NULL || quadindex == NULL || quadnormals == NULL){
    printf("Failed to allocate enough memory, exiting...\n");
    exit(1);
  }
  return 0;
}

and in the calling function it checks again:

loadObj("C:\\ObjTest.obj", vertices, normals, triangleindex, quadindex, &trianglecount, &quadcount);
  if(vertices == NULL || normals == NULL || triangleindex == NULL || quadindex == NULL){
    printf("Error! One of the essential pointers == NULL!");
    exit(1);
  }

and there it happily prints the message and exits.

How come? :(

Thanks in advance,
Nick

PS: Also included "ObjTest.txt" so you can experience it in it's full glory. Heh. ;) Don't forget to either adjust source code to load "ObjTest.txt" or change extension to ".obj" so that it reads "ObjTest.obj".

Attachments
/*We don't need any more libraries.*/
#include <stdio.h>
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glext.h>
#include "loadObj.c"

int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow);
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

void dbgError(char *msg);
void MySetPixelFormat(HDC hDC);

void RenderScene();
void ChangeSize(int width, int height);
void initGL();
void pressKey(WPARAM key);

const static char className[] = "OpenGLClass";
const static char appName[]   = "OpenGL Window";

GLfloat xRot, yRot, zRot;
GLfloat xDis, yDis, zDis;

float *vertices, *normals;
int *triangleindex, *quadindex;
int quadcount, trianglecount;

void dbgError(char *msg){
  fprintf(stderr, "Error @ %s. GetLastError(): %d", msg, (int)GetLastError());
  return;
}

int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow){
  MSG msg;
  WNDCLASS wc;
  HWND hWnd;

  wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = instance;
  wc.hIcon         = NULL;
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = NULL;
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = className;

  if(RegisterClass(&wc) == 0){
    dbgError("RegisterClass()");
    return -1;
  }

  const DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  const int xPos   = 0;
  const int yPos   = 0;
  const int width  = 640;
  const int height = 480;

  hWnd = CreateWindow(className, appName, style, xPos, yPos, width, height, NULL, NULL, instance, NULL);

  if(hWnd == NULL){
    dbgError("CreateWindow()");
    return -1;
  }
  loadObj("C:\\ObjTest.obj", vertices, normals, triangleindex, quadindex, &trianglecount, &quadcount);
  if(vertices == NULL || normals == NULL || triangleindex == NULL || quadindex == NULL){
    printf("Error! One of the essential pointers == NULL!");
    exit(1);
  }

  ShowWindow(hWnd, SW_SHOW);
  UpdateWindow(hWnd);

  int ret;

  while((ret = GetMessage(&msg, NULL, 0, 0)) > 0){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  if(ret == -1){
    dbgError("GetMessage()");
    return -1;
  }

  return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
  static HGLRC hRC = NULL;
  static HDC   hDC = NULL;

  switch(msg){
    case WM_CREATE:
      hDC = GetDC(hWnd);
      MySetPixelFormat(hDC);
      hRC = wglCreateContext(hDC);
      wglMakeCurrent(hDC, hRC);
      
      initGL();
      break;

    case WM_DESTROY:
      wglMakeCurrent(hDC, NULL);
      wglDeleteContext(hRC);
      PostQuitMessage(0);
      break;

    case WM_PAINT:
      RenderScene();
      SwapBuffers(hDC);
      ValidateRect(hWnd, NULL);
      break;

    case WM_SIZE:
      ChangeSize(LOWORD(lParam), HIWORD(lParam));
      break;

    case WM_KEYDOWN:
      pressKey(wParam);
      InvalidateRect(hWnd, NULL, FALSE);
      break;

    default:
      return (DefWindowProc(hWnd, msg, wParam, lParam));
      break;
  }

  return 0;
}

void MySetPixelFormat(HDC hDC){
  int pixelFormat;

  static PIXELFORMATDESCRIPTOR pfd = {
    sizeof(PIXELFORMATDESCRIPTOR),  
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA,
    32,                           //depth of color
    0,0,0,0,0,0,0,0,0,0,0,0,0,
    16           ,               //depth of depthbuffer
    0,0,0,0,0,0,0};
    
  pixelFormat = ChoosePixelFormat(hDC, &pfd);
  SetPixelFormat(hDC, pixelFormat, &pfd);
  return;
}

void RenderScene(){
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glTranslatef(xDis, yDis, zDis-100);

  glRotatef(xRot, 1, 0, 0);
  glRotatef(yRot, 0, 1, 0);
  glRotatef(zRot, 0, 0, 1);

  glColor3f(1, 1, 1);
  printf("Enabling vertex and normal arrays...");
  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);
  printf("Done\n");

  printf("Vertices: %p\tNormals: %p\n", vertices, normals);
  glVertexPointer(3, GL_FLOAT, 0, vertices);
  glNormalPointer(GL_FLOAT, 0, normals);

  printf("Quadindex: %p\tTriangleindex: %p\n", quadindex, triangleindex);
  glDrawElements(GL_QUADS, quadcount, GL_UNSIGNED_INT, quadindex);
  glDrawElements(GL_TRIANGLES, trianglecount, GL_UNSIGNED_INT, triangleindex);

  glDisableClientState(GL_VERTEX_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
    
  glPopMatrix();
  return;
}

void ChangeSize(int width, int height){
  if (height == 0) height = 1;
  GLfloat aspect = (GLfloat)width/(GLfloat)height;
  
  glViewport(0, 0, width, height);
  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(60, aspect, 0.1, 1000);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  return;
}

void initGL(){
  xRot = yRot = zRot = 0;
  xDis = yDis = zDis = 0;

  vertices = normals = NULL;
  triangleindex = quadindex = NULL;
  quadcount = trianglecount = 0;


  glFrontFace(GL_CW);
  glEnable(GL_DEPTH_TEST);
  //glEnable(GL_CULL_FACE);
  glEnable(GL_LIGHTING);

  //lighting colors
  GLfloat ambient[] = {0.35, 0.35, 0.35, 1.0};
  GLfloat diffuse[] = {0.25, 0.25, 0.25, 1.0};
  GLfloat specular[] = {1, 1, 1, 1};
  GLfloat lightPos[] = {-60, 10, 10, 1};

  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
  glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
  glEnable(GL_LIGHT0);

  glEnable(GL_COLOR_MATERIAL);
  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

  GLfloat specref[] = {1, 1, 1, 1};
  glMaterialfv(GL_FRONT, GL_SPECULAR, specref);
  glMateriali(GL_FRONT, GL_SHININESS, 14);

  glClearColor(0.0, 0.0, 0.0, 1.0);
  return;
}

void pressKey(WPARAM key){

#define KEYPRESS(x, a, b, c){\
  case x:\
    a b c;\
    break;\
}

#define KEYPAIR(keyone, keytwo, var, val){\
  KEYPRESS(keyone, var, +=, val);\
  KEYPRESS(keytwo, var, -=, val);\
}

#define OPTION(key, optname){\
  KEYPRESS(key, optname, ^=, 1);\
}
  switch (key){
    //rotation
    KEYPAIR('Q', 'E', yRot, 5);
    KEYPAIR('A', 'D', xRot, 5);
    KEYPAIR('Z', 'C', zRot, 5);

    //displacement
    KEYPAIR(VK_RIGHT, VK_LEFT, xDis, 5);
    KEYPAIR(VK_UP, VK_DOWN, yDis, 5);
    KEYPAIR(VK_CONTROL, VK_NUMPAD0, zDis, 5);
  }

#define ROUNDTHREESIXTY(x) {  \
  if (x <= -360.0 || x >= 360.0){\
    x = 0;\
  }\
}
  ROUNDTHREESIXTY(yRot);
  ROUNDTHREESIXTY(xRot);
  ROUNDTHREESIXTY(zRot);

#undef ROUNDTHREESIXTY
#undef OPTION
#undef KEYPAIR
#undef KEYPRESS

  return;
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <ctype.h>
#include <math.h>

#define TIMEELAPSED {printf("\tTime elapsed: %lu\n", GetTickCount() - startTime);}

int countSpaces(char *str){
  int cnt = 0;
  while(*str != '\0'){
    if(*str == ' ') cnt++;
    str++;
  }

  //remove trailing spaces
  str--;
  while(isspace(*str)){
    if(*str == ' ') cnt--;
    str--;
  }

  return cnt;
}

int loadObj(char *loc,\
            float *vertices, float *gouraudnormals,\
            int *triangleindex, int *quadindex,\
            int *quadcount, int *trianglecount){
  float *normals, *verttext;
  int *trianglenormals, *quadnormals;

  unsigned int startTime = GetTickCount();
  int fileSize = 0;
  int n, i, j;
  printf("Openening file: %s\n", loc);

  HANDLE hFile = CreateFile(loc, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

  if (hFile == INVALID_HANDLE_VALUE){
    printf("File opening failed: error nr. %d", (int)GetLastError());
    return -1;
  }

  fileSize = GetFileSize(hFile, NULL);
  char *data = (char*) calloc(sizeof(char), fileSize + 1);

  int bytesRead;

  if(!ReadFile(hFile, data, fileSize, (DWORD*) &bytesRead, NULL)){
    printf("File reading failed: error nr. %d", (int)GetLastError());
  }

  CloseHandle(hFile);

  printf("Done reading, parsing file now.\n");
  TIMEELAPSED

  printf("Counting lines...");
  int maxLen = -1;
  int lenCount = 0;

  for (i = n = 0; i <= fileSize; i++){
    if (data[i] == '\n'){
      n++;
      lenCount++;
      if(lenCount > maxLen) maxLen = lenCount;
      lenCount = 0;
    }

    lenCount++;
  }
  int lines = n;
  printf("Counted %d lines, maxLen: %d\n", lines, maxLen);
  TIMEELAPSED

  printf("Allocating %d strings of %d chars...", lines, maxLen);
  char **parsedText = (char**) calloc(sizeof(char*), lines);
  for(n = 0; n < lines; n++){
    parsedText[n] = (char*) malloc(sizeof(char) * maxLen);
    if (parsedText[n] == NULL){
      printf("Malloc failed to allocate %d bytes for parsedText[%d].\n", maxLen, n);
      exit(1);
    }
  }
  printf("Done\n");
  TIMEELAPSED

  printf("Reading in 2D array...");
  for(i = n = j = 0; n < lines; i++){
    if(data[i] == '\n'){
      parsedText[n][j] = '\0';

      n++;
      j = 0;
      //puts(parsedText[n]);
      continue;
    }
    //printf("parsedText[%d][%d] = textTree[%d] = %c\n", n, j, i, data[i]);
    parsedText[n][j] = data[i];
    j++;
  }
  printf("Done\n");
  TIMEELAPSED

  //free the data, we don't need it anymore since it's stored in parsedText
  free(data);

/*   for(i = 0; i < lines; i++){
    puts(parsedText[i]);
  } */

  printf("Counting...");

  int vertlines, normallines, facelines, texturelines;
  vertlines = normallines = facelines = texturelines = 0;

  int faceverts, maxFaceverts, trianglecnt, quadcnt;
  faceverts = maxFaceverts = trianglecnt = quadcnt = 0;

  //stores for every face line how many verts it has.
  int *facevertcnt = calloc(sizeof(int), lines);
  for(i = 0; i < lines; i++){
    if(parsedText[i][0] == '#') continue;

    if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){
      vertlines++;
    }

    else if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){
      normallines++;
    }

    else if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){
      facelines++;
      for(n = 2; !isdigit(parsedText[i][n]); n++);
      faceverts = countSpaces(&parsedText[i][n]);
      if(faceverts == 2){
        trianglecnt++;
        //printf("triangle: %s\n", parsedText[i]);
      }
      else if(faceverts == 3){
        quadcnt++;
        //printf("quad: %s", parsedText[i]);
      }
      if(faceverts > maxFaceverts) maxFaceverts = faceverts;
      facevertcnt[i] = faceverts;
      //getchar();
    }

    else if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){
      texturelines++;
    }
  }
  int vertvals = vertlines * 3;
  int normalvals = normallines * 3;
  int texturevals = texturelines * 2;
  int triangleverts = trianglecnt * 3;
  int quadverts = quadcnt * 4;
  
  *trianglecount = trianglecnt;
  *quadcount = quadcnt;

  printf("Counted:\n\t%d vertlines\n\t%d vertvals\n\t%d normals\n\t%d faces (%d triangles, %d quads)\n", vertlines, vertvals, normallines, facelines, trianglecnt, quadcnt);
  TIMEELAPSED
  if(maxFaceverts > 4){
    printf("WARNING:\n  Model won't be imported correctly due to polygons with more than 4 vertices.\n");
  }
  
  printf("Allocating memory for data...");
  vertices = calloc(sizeof(float), vertvals);
  normals = calloc(sizeof(float), normalvals);
  verttext = calloc(sizeof(float), texturevals);
  triangleindex = calloc(sizeof(int), triangleverts);
  trianglenormals = calloc(sizeof(int), triangleverts);

  quadindex = calloc(sizeof(int), quadverts);
  quadnormals = calloc(sizeof(int), quadverts);
  if(vertices == NULL || normals == NULL || verttext == NULL || triangleindex == NULL || trianglenormals == NULL || quadindex == NULL || quadnormals == NULL){
    printf("Failed to allocate enough memory, exiting...\n");
    exit(1);
  }


  int vertcount, normalcount, textcount, tricnt, quacnt;
  
  printf("Done\n");
  TIMEELAPSED

  printf("Reading in data...");
  for(vertcount = normalcount = textcount = tricnt = quacnt = i = 0; i < lines; i++){
    //comment
    if(parsedText[i][0] == '#') continue;

    //vertex
    if(vertlines)
    if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){
      sscanf(&parsedText[i][2], "%f%f%f", (vertices+vertcount), (vertices+vertcount+1), (vertices+vertcount+2));
      vertcount += 3;
    }

    //normal
    if(normallines)
    if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){
      sscanf(&parsedText[i][2], "%f%f%f", (normals+normalcount), (normals+normalcount+1), (normals+normalcount+2));
      normalcount += 3;
    }

    //texture
    if(texturelines)
    if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){
      sscanf(&parsedText[i][2], "%f%f", (verttext+textcount), (verttext+textcount+1));
      textcount += 2;
    }

    //faces
    if(trianglecnt || quadcnt)
    if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){
      if(facevertcnt[i] == 2){
        //skip all leading spaces
        for(n = 2; isspace(parsedText[i][n]); n++);
        //read in the vertexnr
        sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+1));
        n++;

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+1));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+2));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+2));
        }

        tricnt += 3;
      }
      if(facevertcnt[i] == 3){
        //skip all leading spaces
        for(n = 2; isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+1));
        n++;

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+1));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+2));
        n++;

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+2));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+3));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+3));
        }

        quacnt += 4;
      }
    }
  }
  printf("Done\n");
  TIMEELAPSED

  if(normallines){
     printf("Calculating Gouraud normals for each vertex...");
      //Find a face the vertex is in
      //From there, fetch its normalnr,
      //Look up the normal, add x, y, z to the stored sum.
      //find the next face.

    gouraudnormals = calloc(sizeof(float), normalvals);
    //for every vertex, start=1 cuz in file it's also refered to as 1 not as 0
    //find its faces and its normals
    if(trianglecnt != 0){
      for(i = 0; i < triangleverts; i++){
        float normalx = normals[(trianglenormals[i]-1)*3];
        float normaly = normals[(trianglenormals[i]-1)*3+1];
        float normalz = normals[(trianglenormals[i]-1)*3+2];

        gouraudnormals[(triangleindex[i]-1)*3]   += normalx;
        gouraudnormals[(triangleindex[i]-1)*3+1] += normaly;
        gouraudnormals[(triangleindex[
# Blender3D v245 OBJ File: <memory>
# www.blender3d.org
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 1.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
f 1//1 2//1 3//1 4//1
f 5//2 8//2 7//2 6//2
f 1//3 5//3 6//3 2//3
f 2//4 6//4 7//4 3//4
f 3//5 7//5 8//5 4//5
f 5//6 1//6 4//6 8//6

That's because the memory address contained in the pointer is lost when the function is popped off the stack. In other words, you can modify the value that the pointer points to, but you can't modify the memory address that the pointer holds (well, you can, but the change won't have any effect on the pointer in the parent function).

The solution to this would be to use a pointer of a pointer.

Ooooooooooh, really newb mistake right there, haha. Thanks for *pointing* it out. No pun intended ofc. ;)

This question has already been answered. Start a new discussion instead.