PDA

View Full Version : Declaring a global array, and give the size later when assigning values?



crazyfuturamanoob
November 12th, 2008, 02:00 PM
Title says it all. How?

Edit: In C, of course. Forgot.

dwhitney67
November 12th, 2008, 02:29 PM
For example:

Main.c:


#include <stdlib.h>
#include <stdio.h>

extern void function();

// global variable declaration
int* array = 0;

int main()
{
const size_t num_items = 10;

// global variable initialization
array = malloc(sizeof(int) * num_items);

function();

printf("array[5] = %d\n", array[5]);

free(array);

return 0;
}


Other.c:


extern int* array;

void function()
{
array[5] = 10;
}


P.S. It is an accepted belief (almost fact) that using global variables leads to poor programming technique and to bad software designs. If you must use a global variable, ensure that it is declared static, and thus only accessible within the module in which it is defined. Avoid defining global variables within header files.

For example, the following header file provides the basic interface for a queue:

Queue.h:


#ifndef QUEUE_H
#define QUEUE_H

#include <unistd.h>
#include <stdbool.h>

typedef int Q_DATA_TYPE;

void init_queue(const size_t q_depth);
void destroy_queue();

void insert_item(const Q_DATA_TYPE item);
Q_DATA_TYPE pop_item();

bool is_empty();

#endif


With this interface, a program can employ the use of a queue. If this queue is needed by more than one function, then the queue object should be passed around as a function-parameter; not declared global. Back to the header file above, note that there are no global variables defined. The variables will be defined (as static), but only within the implementation file of queue.c.

crazyfuturamanoob
November 12th, 2008, 02:40 PM
For example:

Main.c:


#include <stdlib.h>
#include <stdio.h>

extern void function();

// global variable declaration
int* array = 0;

int main()
{
const size_t num_items = 10;

// global variable initialization
array = malloc(sizeof(int) * num_items);

function();

printf("array[5] = %d\n", array[5]);

free(array);

return 0;
}


Other.c:


extern int* array;

void function()
{
array[5] = 10;
}


Is that other.c really needed? Can't I just use array[5] = 10; inside my main program?

dwhitney67
November 12th, 2008, 02:56 PM
Is that other.c really needed? Can't I just use array[5] = 10; inside my main program?
You could, but then what is the point of having a global variable?

crazyfuturamanoob
November 12th, 2008, 03:34 PM
You could, but then what is the point of having a global variable?

I am coding an SDL/OpenGL graphics library for my upcoming game, which can do a lot useful things, including texture loading.

Here is how the library works:

/* now, when importing
graphics.c, one of the first lines declares
GLuint array "texture", but doesn't declare it's size.

also, a linked list for filenames is declared */
#include "graphics.c"

/* init opengl */
initGL();

/* now, this function adds string to the filename list
and returns the texture index, which is saved in a & b */
int a = addTexture( "data/file.bmp" );
int b = addTexture( "data/file2.png" );

/* this function gives the texture array a size, which is
the amount of strings in the filename array.

it also calls glGenTextures(amountOfFiles, &texture)

finally, it loads textures and saves them in that array */
LoadTextures();

/* now it is easy to switch between textures, when
we got them loaded & created in texture, and again,
a & b are the indexes of textures. with these indexes,
we can find the correct textures from the list */
glBindTexture(GL_TEXTURE_2D, texture[a]);



glGenTextures is the reason, why I need to do this.

crazyfuturamanoob
November 12th, 2008, 04:00 PM
Damn, glGenTextures accepts only real GLuint arrays, not mallocated things.

How to make it a real array? A real, global array, that glGenTextures could use?

Tony Flury
November 12th, 2008, 04:08 PM
Can you post the quote or site link from where you get the idea that


Damm, glGenTextures accepts only GLuint arrays not mallocated things.


In C once you have the space malloced, there is no difference between a "real" array, and a malloced array.

A code library should be unable to tell the difference - unless it makes some significant (and probably dangerous) assumptions of where memory might be getting allocated.

After all when you pass an array to a library function, what you actually pass is a pointer to a block of memory.

All you need to do is ensure that you allocate the memory in the same way - so take care if it is a mult dimensional array.

crazyfuturamanoob
November 12th, 2008, 04:16 PM
Perhaps you might be able to fix this? Just scroll down and see LoadTextures() function. That's what makes the error.
I also got another file, main.c, which includes everything needed and initializes a window, does some other stuff, but it doesn't make errors.

/* initialize a linked list for texture filenames to load */
struct string
{
struct string *next;
int index;
char *chars;
};
struct filelist
{
struct string *filenames;
};
struct filelist *textures_to_load;
int num_textures2load = 0;

/* now some functions to edit the linked list */
struct string *create_string( char stuff[] )
{
struct string *str;
str = malloc( sizeof(struct string) );

if (str == NULL)
return NULL;

memset( str, 0, sizeof(struct string) );

str->chars = (char *) stuff;

static int index = 0;
str->index = index;
index += 1;

return str;
}

void link_string( struct string *str )
{
str->next = textures_to_load->filenames;
textures_to_load->filenames = str;
}

/* this function adds texture to the list of textures to load */
int add_texture( char filename[] )
{
struct string *str = create_string( filename );
link_string( str );

num_textures2load += 1;

return str->index;
}

/************************************************** **************************/

/* This is our SDL surface */
SDL_Surface *surface;

GLuint* texture = 0;

/* general OpenGL initialization function */
int initGL( GLvoid )
{
/* Enable Texture Mapping ( NEW ) */
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glEnable( GL_TEXTURE_2D );

/* Enable smooth shading, you can see this when using lightning */
glShadeModel( GL_SMOOTH );

/* Set the background black */
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

/* Depth buffer setup */
/* glClearDepth( 1.0f ); */

/* Disables Depth Testing, this is 2D */
glDisable( GL_DEPTH_TEST );

/* The Type Of Depth Test To Do */
/* glDepthFunc( GL_LEQUAL ); */

/* Really Nice Perspective Calculations */
/* glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); */

/* enable blending */
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

/* enable alpha transparency */
glEnable( GL_ALPHA_TEST );
glAlphaFunc( GL_NOTEQUAL, 0.0f );

/* init list of tex filenames to load */
textures_to_load = malloc( sizeof(struct filelist) );
textures_to_load->filenames = NULL;

glDisable( GL_TEXTURE_2D );

return( TRUE );
}


/* function to reset our viewport after a window resize */
int resizeWindow( int width, int height )
{
/* Protect against a divide by zero */
if ( height == 0 )
height = 1;

/* Setup our viewport. */
glViewport( 0, 0, ( GLint )width, ( GLint )height );

/*
* change to the projection matrix and set
* our viewing volume.
*/
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );

/* Set our perspective */
gluOrtho2D(0, width, height, 0);

/* Make sure we're chaning the model view and not the projection */
glMatrixMode( GL_MODELVIEW );

/* Reset The View */
glLoadIdentity( );

return( TRUE );
}

void LoadTextures( )
{
/* num_textures2load is an integer, which indicates the amount of textures added */

/** initialize the real list **/
texture = malloc( sizeof(GLuint) * num_textures2load );

/* debugging help */
printf("all good for now\n");

/** generate the textures **/
glGenTextures( num_textures2load, (GLuint *) &texture );

/* storage for each image file */
SDL_Surface *TexImg;

struct string *str;
for (str = textures_to_load->filenames; str; str = str->next)
{
/** printf("Texture %i filename: %s\n", str->index, str->chars); **/

/* load the current image */
TexImg = IMG_Load(str->chars);

/* color format of image */
GLenum SourceFormat=GL_BGR; /* GL_RGB */
if (TexImg->flags&SDL_SRCALPHA)
SourceFormat=GL_RGBA;
else if (TexImg->format->BitsPerPixel==8)
SourceFormat=GL_COLOR_INDEX;

/* select the correct texture slot */
glBindTexture( GL_TEXTURE_2D, texture[ str->index ] );

/* Generate The Texture */
glTexImage2D( GL_TEXTURE_2D, 0, TexImg->format->BytesPerPixel,
TexImg->w, TexImg->h, 0, SourceFormat, GL_UNSIGNED_BYTE, TexImg->pixels );

/* Linear Filtering */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}

SDL_FreeSurface( TexImg );

}

I don't think anyone will even read that code, but there's always hope. :)

And when I try to compile it, I get Segmentation Fault right after "all good for now".

Edit:

To save you from a lot reading, here's the place where I declare the "array":

GLuint* texture = 0;
Perhaps that's the place where it goes wrong?

Or then it's the LoadTextures function. I put it here too, although it is already there above.

void LoadTextures( )
{
/* num_textures2load is an integer, which indicates the amount of textures added */

/** initialize the real list **/
texture = malloc( sizeof(GLuint) * num_textures2load );

/* debugging help */
printf("all good for now\n");

/** generate the textures **/
glGenTextures( num_textures2load, (GLuint *) &texture );

/* storage for each image file */
SDL_Surface *TexImg;

struct string *str;
for (str = textures_to_load->filenames; str; str = str->next)
{
/** printf("Texture %i filename: %s\n", str->index, str->chars); **/

/* load the current image */
TexImg = IMG_Load(str->chars);

/* color format of image */
GLenum SourceFormat=GL_BGR; /* GL_RGB */
if (TexImg->flags&SDL_SRCALPHA)
SourceFormat=GL_RGBA;
else if (TexImg->format->BitsPerPixel==8)
SourceFormat=GL_COLOR_INDEX;

/* select the correct texture slot */
glBindTexture( GL_TEXTURE_2D, texture[ str->index ] );

/* Generate The Texture */
glTexImage2D( GL_TEXTURE_2D, 0, TexImg->format->BytesPerPixel,
TexImg->w, TexImg->h, 0, SourceFormat, GL_UNSIGNED_BYTE, TexImg->pixels );

/* Linear Filtering */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}

SDL_FreeSurface( TexImg );

}

Tony Flury
November 12th, 2008, 04:19 PM
What error do you get ?

is a compiler or a run time error ?

crazyfuturamanoob
November 12th, 2008, 04:23 PM
What error do you get ?

is a compiler or a run time error ?

Hard to say, Segmentation Fault. Doesn't anyhow relate to my compiler, it's the code which makes the error.

Tony Flury
November 12th, 2008, 04:28 PM
Have you tried to use gdb to debug the code - step through it one line at a time in order to find where it actually fails.

One thing though



GLuint* texture = 0;
.....
.....
.....
texture = malloc( sizeof(GLuint) * num_textures2load );

/* debugging help */
printf("all good for now\n");

/** generate the textures **/
glGenTextures( num_textures2load, (GLuint *) &texture );


in the first few lines above - texture already is of type (GLuint *) - so on the last line, you don't need to cast it - and you don't need the &

I think that line should probably be :


glGenTextures( num_textures2load, texture );


try that -

crazyfuturamanoob
November 12th, 2008, 04:43 PM
Have you tried to use gdb to debug the code - step through it one line at a time in order to find where it actually fails.

One thing though



GLuint* texture = 0;
.....
.....
.....
texture = malloc( sizeof(GLuint) * num_textures2load );

/* debugging help */
printf("all good for now\n");

/** generate the textures **/
glGenTextures( num_textures2load, (GLuint *) &texture );


in the first few lines above - texture already is of type (GLuint *) - so on the last line, you don't need to cast it - and you don't need the &

I think that line should probably be :


glGenTextures( num_textures2load, texture );


try that -

No, doesn't work. Still same Segmentation Fault right after "all good for now".

Tried gdb, and found it way too complicated for me. I never used debuggers, I always fixed the bugs by hand.

dwhitney67
November 12th, 2008, 05:08 PM
I am coding an SDL/OpenGL graphics library for my upcoming game, which can do a lot useful things, including texture loading.

Would it not be prudent to start off writing smaller applications so that you fully understand the C language before branching into something complicated (e.g. a game).

I've look further down at your other post, and I question the need for the "string" structure.

As for the rest of your code, it is a pain in the rear to read because you have enclosed it in those ridiculous color-coding tags.

It seems to me that you need to provide the openGL library function a list of filenames that represent textures. Thus why are you not declaring a local array of strings in your main() function?

For example, would the following suffice and hence be easier? (Btw, I do not know/use openGL, but its interface, as from what you have shown, seems pretty straighforward.)


int main()
{
char* textures[] = { "filename1.bmp",
"file2.png",
"F3.png"
};

const size_t numTextures = sizeof(textures) / sizeof(char*);

for (int i = 0; i < numTextures; ++i)
{
/* load the current image */
SDL_Surface* texImg = IMG_Load(textures[i]);

/* color format of image */
GLenum sourceFormat = GL_RGB; /* initially assume GL_RGB */

if (texImg->flags &S DL_SRCALPHA)
{
sourceFormat = GL_RGBA;
}
else if (texImg->format->BitsPerPixel == 8)
{
sourceFormat = GL_COLOR_INDEX;
}

/* select the correct texture slot */
glBindTexture( GL_TEXTURE_2D, i );

/* Generate The Texture */
glTexImage2D( GL_TEXTURE_2D, 0, texImg->format->BytesPerPixel,
texImg->w, texImg->h, 0, sourceFormat,
GL_UNSIGNED_BYTE, texImg->pixels );

/* Linear Filtering */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

SDL_FreeSurface( texImg );
}
}

Tony Flury
November 12th, 2008, 05:16 PM
Well I can guarantee you that the error you are getting is nothing to do with the library rejecting malloced data in favour of an array.

did you put any other debug lines in your application. So far you know that you get to "all good for now" - how do you know if you get any point past that ?

Also if you are going to develop complex programs i would strongly suggest that you learn gdb - it is not that complicated.

crazyfuturamanoob
November 12th, 2008, 05:26 PM
I was using that linked list thing for list of strings, because I didn't know it is possible to make a char list having invidual strings.

And there is a HUGE problem with dwhitney67 example code about the function.

glGenTextures gets an empty memory slot from video memory, with given name.

And because every loop time it gets an empty texture slot with same name,
all texture data will be filled with the last loaded texture. That how all
textures look same than the last loaded, which means you can load only ONE
texture at a time. And that's ridiculous! Only one texture, the game would suck.

dwhitney67
November 12th, 2008, 05:32 PM
I was using that linked list thing for list of strings, because I didn't know it is possible to make a char list having invidual strings.

And there is a HUGE problem with dwhitney67 example code about the function.

glGenTextures gets an empty memory slot from video memory, with given name.

And because every loop time it gets an empty texture slot with same name,
all texture data will be filled with the last loaded texture. That how all
textures look same than the last loaded, which means you can load only ONE
texture at a time. And that's ridiculous! Only one texture, the game would suck.
Like I stated earlier, I do not know openGL (nor care to at this time). If the openGL library function can handle an array of strings, then give it the entire array at one time.

I did not get the impression that is what you were doing in your code, hence the rationale for the code I presented.

crazyfuturamanoob
November 12th, 2008, 05:36 PM
But actually the whole problem is about glGenTextures().

...

Whatever... I'll try to make up a workaround for it.

dwhitney67
November 12th, 2008, 05:57 PM
But actually the whole problem is about glGenTextures().

...

Whatever... I'll try to make up a workaround for it.
Surprise, surprise... I actually have the manpage for glGenTextures() on my system. However it is written poorly; there is no indication of what header file(s) or library I must link in to use it. There also isn't a specification as to what GLsizei nor GLuint represents.

I will assume GLsizei represents a size_t, and GLuint represents an unsigned int.

The interface is specified as:


void glGenTextures( GLsizei n,
GLuint *textures )


Maybe something like the following will suffice:


...

int main()
{
GLsizei num_textures = 10;
GLuint textures[10];

...

glGenTextures(num_textures, textures);

...
}

Tony Flury
November 12th, 2008, 05:57 PM
When you do the malloc call what return value are you getting ?

you code is assuming that the malloc is working, and it actually might not be.

you should always follow a malloc with



if pointer == NULL
{
<error handling code>
}