Reputation: 513
I am trying to dynamically initializing a queue. Here is my function.
typedef struct{
int size;
int max_size;
short * eles;
} queue;
void dump_queue(queue *q)
{
//print a bunch of information
}
void init_queue(queue *q, int max_size)
{
q = (queue)malloc(sizeof(queue));
q->size = 0;
q->max_size = max_size;
q->eles = (short *)malloc(max_size * sizeof(short));
int i;
for(i = 0; i < max_size; i++)
q->eles[i] = -1;
dump_queue(q);
}
task_queue is a global variable. The structure of the routine is like:(not exact code)
//globally defined here but not initialized
queue * task_queue;
void init_scheduler()
{
init_queue(task_queue, 32);
dump_queue(task_queue);
//other staff
}
note that there are two dump_queue, one is init_queue(), the other is after init_queue. Since task_queue is malloced, I expect that two calls of dump_queue should give a same result. But the second one actually reported a SIG_FAULT.
After I checked, in the second call of dump_queue, task_queue is actually NULL. Why is that?
Upvotes: 1
Views: 165
Reputation: 363
if you use this function only to initialize task_queue you should do that
void init_global_queue(int max_size)
{
queue *task_queue = malloc(sizeof(queue));
task_queue->size = 0;
task_queue->max_size = max_size;
task_queue->eles = malloc(max_size * sizeof(short));
int i;
for(i = 0; i < max_size; i++)
task_queue->eles[i] = -1;
}
But unfortunately, this is not a good pattern because you can't use this function more than once
I think the best way of doing it is like this
queue *init_queue(int max_size)
{
queue *q = malloc(sizeof(queue));
q->size = 0;
q->max_size = max_size;
q->eles = malloc(max_size * sizeof(short));
int i;
for(i = 0; i < max_size; i++)
q->eles[i] = -1;
return q;
}
and when you want to initialize any queue you'll just have to call this function
queue * task_queue;
void init_scheduler()
{
task_queue = init_queue(32);
dump_queue(task_queue);
}
And 2 things :
-Casting the return value of a malloc call is not really bad, in fact it's casted anyway, explicitly or implicitly
-The best way of doing a malloc and (for this example) returning its value is like this :
type *my_pointer = NULL;
my_pointer = malloc(sizeof (type))
if (my_pointer == NULL)
return NULL;
my_pointer->foo = 0;
my_pointer->bar = NULL;
...
return my_pointer
So that if malloc doesn't work properly(i.e. for example : if your RAM is full, malloc will return NULL (and set errno to ENOMEM)), you can exit your program properly
and if you like minimalist programming, you can do it like this to ;)
type *my_pointer = NULL;
if (!(my_pointer = malloc(sizeof (type))))
return NULL;
more ? man malloc, man errno
Upvotes: 0
Reputation: 3272
Why not? you're allocating memory in the function local scope of init_queue()
.
The scope of the returned pointer is valid, but the assignment is not valid.
q = malloc(sizeof(queue));
this q
won't hold it's value outside init_queue()
function.
if queue * task_queue;
is global, is it really required to pass it as function parameter?
Also, as a note, please do not cast the return value of malloc()
.
EDIT:
No, there is no auto-free()
concept in c
. It will result in a memory leak, if not free()
-d by the application explicitly.
Upvotes: 5
Reputation: 4767
You never assign anything to task_queue
. Notice that you passed task_queue
to init_queue
by value instead of by reference. You should either modify init_queue
to return a queue *
, or modify its first argument to take a queue **
and pass in &task_queue
from init_scheduler
.
Or perhaps the easiest fix, since it is a global, just do task_queue = q;
at the end of init_queue
.
Upvotes: 2
Reputation: 6080
it should either be init_queue(&task_queue); or task_queue=init_queue();
Upvotes: 1