int listLength(struct node *r) {
int *len = (int *)malloc(sizeof(int));
if(!r) {
free(len);
return *len;
}
while(r) {
r = r->next;
*len += 1;
}
free(len)
return *len;
}
I wrote this function to calculate the length of the linked list. I am still learning pointers by playing with them. I understand I could have used a simple len variable in the function,but I want to learn the basics of dynamic memory allocation. Why the length is always 0 after even though list has few elements? When should free() be called ?
You cannot use the memory once you free() it. So,
free(len);
return *len;
is wrong and undefined behavior.
Instead, you can use a local variable to hold the value and return it.
Also, FWIW,
int *len = (int *)malloc(sizeof(int));
if(!r) {
free(len);
return *len;
}
in the above code, you're trying to use the *len as return value, which is uninitialized. Even without the free()ing, you should not do that.
Also, you should always check for the success of malloc() vefore using the returned pointer.
A modified version:
int listLength(struct node *r) {
int *lenp = malloc(sizeof(int));
int len = 0;
if (!lenp) //check malloc success
exit(-1);
*lenp = len;
if(!r) {
free(lenp);
return len;
}
while(r) {
r = r->next;
*lenp += 1;
}
len = *lenp;
free(lenp);
return len;
}
EDIT:
In your case, there is no need to use dynamic memory allocation at all. AS suggested by Mr. # Barak Manos and Mr. # WhozCraig, you should use dynamic memory allocation only when the memory requirement is not known at compile time. Otherwise, in general, static (compile time) memory allocation should do just fine.
A better and cleaner approach to your code,
int listLength(struct node *r) {
int len = 0;
while(r) {
r = r->next;
len += 1;
}
return len;
}
In general: after you have free()'d a memory block, you must never access it anymore. Just think of have given that block away. It is not yours anymore!
From this follow that you have to free a block only if you don't want to access it anymore. That's a fundamental rule; never ever break it.
For this example, as others have stated, there is actually no need to use dynamic memory at all.
Oh, and: you really should never cast the result of malloc! It returns void * wich can be assigned to any other pointer type. Read the standard, section 6.5.16.1 .
Related
I've been stuck on this particular codewars exercise for a while now. Not because the puzzle itself is hard (no, I was able to print the correct results after only a few minutes), but because I can't seem to figure out how to return the result.
I'm supposed to return an array of structs. I know I can't just statically allocate it and then return it. I must dynamically allocate memory and return the pointer. I do this like this (n-m is the max amount of structs I might have to return):
Pair* res = malloc((n-m)*sizeof(Pair));
I then assign values as follows:
res[t].first = i;
res[t].snd = sum;
And then return the array:
return res;
If I print the whole array before returning it, it appears filled. But the codewars system says I returned an empty array?
I was able to fix this by adding an ampersand to return the address. By doing this, it returns the first struct properly (I was able to figure this out by adding manual checks), but the second struct would be rubbish data.
Anyone know what I might be doing wrong?
Here's the full function (removed the calculations because they're irrelevant to the problem, and also might spoil the puzzle for others who stumble upon this question while solving it):
Pair** listSquared(long long m, long long n, int* length) {
Pair* res = malloc((n-m)*sizeof(Pair));
int t = 0;
long long sum = 0;
for(int i = m; i<=n; i++)
{
if(sum = isSumSquare(i))
{
res[t].first = i;
res[t].snd = sum;
t++;
}
}
*length = t;
return res;
}
One more thing: I did notice that the return type is Pair**. I'm guessing this is what I'm doing wrong, but I also tried making the datatype of res Pair** (and then replacing the . with -> when assigning), and/or taking the sizeof(Pair*) instead of just Pair. I tried more combinations than I can count, but still haven't gotten anything that works. I have a feeling I'm missing something fundamental knowledge about pointers here...
Anyone who can tell me what I'm doing wrong?
edit: as requested by Gilles, the exact problem statement: https://i.imgur.com/gFdDJlz.png
As mentioned above, type controls everything. You were given a function prototype with Pair **listSquared (...). The function must return type Pair** (e.g. a pointer-to-pointer to type Pair)
Returning a pointer-to-pointer to dynamically allocated object requires first declaring the object of type Pair** within listSquared and allocating the number of pointers required, e.g.
Pair **res = malloc ((n-m) * sizeof *res);
(note: if you always set your typesize by using the dereferenced pointer, sizeof *res instead of sizeof (Pair*), there is no way you can get it wrong)
Then within your function in the loop where you fill each struct Pair, you first need to allocate a block of memory for each struct and assign the beginning address for that block to your pointer, e.g.
res[t] = malloc (sizeof *res[t]);
In each case, and with EVERY allocation, you need to validate that the allocation succeeded before attempting to make use of the pointers or block of memory. For example:
if (!res) { /* validate EVERY allocation */
perror ("malloc-res");
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
and in the case of failure allocating for res[t], you need to free() each previously allocated struct and the pointers before returning to avoid creating a memory leak, e.g.
if(sum = isSumSquare(i))
{ /* allocate for res[t] and validate, free all on failure */
if (!(res[t] = malloc (sizeof *res[t]))) {
perror ("malloc-res[t]");
while (t--) /* free previously allocated structs */
free (res[t]);
free (res); /* free pointers */
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
res[t].first = i;
res[t].snd = sum;
t++;
}
Based on my best understanding of what you needed to do, you could put it altogether with something like:
Pair **listSquared (long long m, long long n, int *length)
{
Pair **res = malloc ((n-m) * sizeof *res);
int t = 0;
long long sum = 0;
if (!res) { /* validate EVERY allocation */
perror ("malloc-res");
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
for(int i = m; i<=n; i++)
{
if(sum = isSumSquare(i))
{ /* allocate for res[t] and validate, free all on failure */
if (!(res[t] = malloc (sizeof *res[t]))) {
perror ("malloc-res[t]");
while (t--) /* free previously allocated structs */
free (res[t]);
free (res); /* free pointers */
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
res[t].first = i;
res[t].snd = sum;
t++;
}
}
*length = t;
return res;
}
In the case of allocation failure your function returns NULL and has freed any memory it had allocated up to the point of failure eliminating all potential memory leaks.
I'm glad you got things working and have submitted your code. If you have any questions about the reasoning above, just drop a comment and I'm happy to help further.
Disclaimer, this is help with a school assignment. That being said, my issue only occurs about 50% of the time. Meaning if I compile and run my code without edits sometimes it will make it through to the end and other times it will not. Through the use of multiple print statements I know exactly where the issue is occurring when it does. The issue occurs in my second call to hugeDestroyer(right after the print 354913546879519843519843548943513179 portion) and more exactly at the free(p->digits) portion.
I have tried the advice found here (free a pointer to dynamic array in c) and setting the pointers to NULL after freeing them with no luck.
Through some digging and soul searching I have learned a little more about how free works from (How do malloc() and free() work?) and I wonder if my issue stems from what user Juergen mentions in his answer and that I am "overwriting" admin data in the free list.
To be clear, my question is two-fold.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Secondly, how can I guard against this kind of behavior in my functions?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct HugeInteger
{
// a dynamically allocated array to hold the digits of a huge integer
int *digits;
// the number of digits in the huge integer (approx. equal to array length)
int length;
} HugeInteger;
// Functional Prototypes
int str2int(char str) //converts single digit numbers contained in strings to their int value
{
return str - 48;
}
HugeInteger *parseInt(unsigned int n)
{
int i = 0, j = 0;
int *a = (int *)calloc(10, sizeof(int));
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(n == 0)
{
p->digits = (int *)calloc(1, sizeof(int));
p->length = 1;
return p;
}
while(n != 0)
{
a[i] = n % 10;
n = n / 10;
i++;
}
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(i = 0; i <= p->length; i++, j++)
p->digits[j] = a[i];
return p;
}
HugeInteger *parseString(char *str) //notice datatype is char (as in char array), so a simple for loop should convert to huge int array
{
int i = 0, j = 0;
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(str == NULL)
{
free(p);
p = NULL;
return p;
}
else
{
for(i=0; str[i] != '\0'; i++)
;
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(; i >= 0; i--)
p->digits[j++] = str2int(str[i - 1]);
}
return p;
} //end of HugeInteger *parseString(char *str)
HugeInteger *hugeDestroyer(HugeInteger *p)
{
//printf("No problem as we enter the function\n");
if(p == NULL)
return p;
//printf("No problem after checking for p = NULL\n");
if(p->digits == NULL)
{
free(p);
p = NULL;
return p;
}
//printf("No Problem after checking if p->digits = NULL\n");
//else
//{
free(p->digits);
printf("We made it through free(p->digits)\n");
p->digits = NULL;
printf("We made it through p->digits = NULL\n");
free(p);
printf("We made it through free(p)\n");
p = NULL;
printf("We made it through p = NULL\n");
return p;
//}
//return NULL;
}//end of HugeInteger *hugeDestroyer(HugeInteger *p)
// print a HugeInteger (followed by a newline character)
void hugePrint(HugeInteger *p)
{
int i;
if (p == NULL || p->digits == NULL)
{
printf("(null pointer)\n");
return;
}
for (i = p->length - 1; i >= 0; i--)
printf("%d", p->digits[i]);
printf("\n");
}
int main(void)
{
HugeInteger *p;
hugePrint(p = parseString("12345"));
hugeDestroyer(p);
hugePrint(p = parseString("354913546879519843519843548943513179"));
hugeDestroyer(p);
hugePrint(p = parseString(NULL));
hugeDestroyer(p);
hugePrint(p = parseInt(246810));
hugeDestroyer(p);
hugePrint(p = parseInt(0));
hugeDestroyer(p);
hugePrint(p = parseInt(INT_MAX));
hugeDestroyer(p);
//hugePrint(p = parseInt(UINT_MAX));
//hugeDestroyer(p);
return 0;
}
First of all, really outstanding question. You did a lot of research on topic and generally speaking, solved this issue by yourself, I'm here mainly to confirm your findings.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Syntax is correct. #Shihab suggested in comments not to release p->digits and release p only, but such suggestion is wrong, it leads to memory leakages. There is a simple rule: for each calloc you must eventually call free, so your current approach in freeing p->digits and then p is totally fine.
However, program fails on a valid line. How is it possible? Quick answer: free can't do its work due to corruption of meta information responsible for tracking allocated/free blocks lists. At some point program corrupted meta information, but this was revealed only on attempt to use it.
As you already discovered, in most implementations memory routines such as calloc results into allocation of buffer with prepended meta-info. You receives pointer to buffer itself, but small piece of information right before this pointer is crucial for further buffer managing (e.g. freeing). Writing 11 integers into buffer intended for 10, you're likely to corrupt meta-info of block following the buffer. Whether corruption actually happens and what would be its consequences, is heavily dependent on both implementation specifics and current memory alignment (what block follows the buffer, what exactly meta-data is corrupted). It doesn't surprise me, that you see one crash per two executions, neither surprises me observing 100% crash reproduction on my system.
Secondly, how can I guard against this kind of behavior in my functions?
Let's start with fixing overflows. There are couple of them:
parseString: loop for(; i >= 0; i--) is executed length+1 times, so p->digits is overflown
parseInt: loop for (i = 0; i <= p->length; i++, j++) is executed length+1 times, so p->digits is overflown
Direct access to memory managing in C++ is error prone and troublesome to debug. Memory leakages and buffers overflows are the worst nightmare in programmers life, it's usually better to simplify/reduce direct usage of dynamic memory, unless you are studying to cope with it, of course. If you need to stick with a lot of direct memory managing, take a look at valgrind, it's intended to detect all such things.
By the way, there is also a memory leakage in your program: each call to parseInt allocates buffer for a, but never frees it.
Suppose this is a part of my code:
int foo()
{
char *p, *q ;
if((p = malloc(BUFSIZ)) == NULL) {
return ERROR_CODE;
}
if((q = malloc(BUFSIZ)) == NULL) {
free(p)
return ERROR_CODE;
}
/* Do some other work... */
free(p);
free(q);
}
Since it's possible that the first malloc is successful but the second one fails, I use free(p) in the second "error handler". But what if there are more malloc's and what if I want to modify the code (adjusting their orders, adding or deleting some malloc)?
I know in C++ there are things like RAII and exception safe, etc. But in general, what is the correct way to handle malloc failure in C? (maybe using some goto?)
Your code is fine, but for lots of variables, I'd prefer:
int
foo()
{
char *p = NULL;
char *q = NULL;
int ret = 0;
if (NULL == (p = malloc(BUFSIZ)))
{
ret = ERROR_CODE;
goto error;
}
// possibly do something here
if (NULL == (q = malloc(BUFSIZ)))
{
ret = ERROR_CODE;
goto error;
}
// insert similar repetitions
// hopefully do something here
error:
free (p);
free (q);
return ret;
}
Note that freeing NULL is defined as a no-op.
This avoids n levels of indent for n variables. You can clean up filehandles etc. similarly (though you'll have to put a condition around the close()).
Now, if you know you can allocate them all at once, then dasblinkenlight has a good answer, but here's another way:
int
foo()
{
int ret = 0;
char *p = malloc(BUFSIZ);
char *q = malloc(BUFSIZ);
char *r = malloc(BUFSIZ);
if (!p || !q || !r)
{
ret = ERROR_CODE;
goto exit;
}
// do something
exit:
free(p);
free(q);
free(r);
return ret;
}
Final possibility: if you actually want to exit the program on malloc fail, consider using mallopt's M_CHECK_ACTION option. This makes malloc() faults get checked, and calls abort(), possibly printing a helpful message.
From the man page:
NAME
mallopt - set memory allocation parameters
SYNOPSIS
#include <malloc.h>
int mallopt(int param, int value);
DESCRIPTION
The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that parameter.
The following values can be specified for param:
M_CHECK_ACTION
Setting this parameter controls how glibc responds when various kinds of programming errors are detected (e.g., freeing the same pointer twice). The 3 least significant bits (2, 1, and 0) of the value assigned to this parameter determine the glibc behavior, as follows:
Bit 0: If this bit is set, then print a one-line message on stderr that provides details about the error. The message starts with the string "*** glibc detected ***", followed by the program name, the name of the memory-allocation function in which the error was detected, a brief description of the error, and the memory address where the error was detected.
Bit 1: If this bit is set, then, after printing any error message specified by bit 0, the program is terminated by calling abort(3). In glibc versions since 2.4, if bit 0 is also set, then, between printing the error message and aborting, the program also prints a stack trace in the manner of backtrace(3), and prints the process's memory mapping in the style of /proc/[pid]/maps (see proc(5)).
Bit 2: (since glibc 2.4) This bit has an effect only if bit 0 is also set. If this bit is set, then the one-line message describing the error is simplified to contain just the name of the function where the error was detected and the brief description of the error.
Since it is perfectly OK to pass NULL to free(), you could allocate everything that you need in a "straight line", check everything in a single shot, and then free everything once you are done, regardless of whether or not you have actually done any work:
char *p = malloc(BUFSIZ);
char *q = malloc(BUFSIZ);
char *r = malloc(BUFSIZ);
if (p && q && r) {
/* Do some other work... */
}
free(p);
free(q);
free(r);
This works as long as there are no intermediate dependencies, i.e. you do not have structures with multi-level dependencies. When you do, it is a good idea to define a function for freeing such a structure, without assuming that all memory blocks are non-NULL.
For large numbers of allocations, I would invest the time in creating a memory manager that keeps track of the allocations. That way, you never have to worry about leaks, regardless of whether or not the function succeeds.
The general idea is to create a wrapper for malloc that records successful allocations, and then frees them on request. To free memory, you simply pass a special size to the wrapper function. Using a size of 0 to free memory is appropriate if you know that none of your actual allocations will be for 0 sized blocks. Otherwise, you may want to use ~0ULL as the request-to-free size.
Here's a simple example that allows up to 100 allocations between frees.
#define FREE_ALL_MEM 0
void *getmem( size_t size )
{
static void *blocks[100];
static int count = 0;
// special size is a request to free all memory blocks
if ( size == FREE_ALL_MEM )
{
for ( int i = 0; i < count; i++ )
free( blocks[i] );
count = 0;
return NULL;
}
// using a linked list of blocks would allow an unlimited number of blocks
// or we could use an array that can be expanded with 'realloc'
// but for this example, we have a fixed size array
if ( count == 100 )
return NULL;
// allocate some memory, and save the pointer in the array
void *result = malloc( size );
if ( result )
blocks[count++] = result;
return result;
}
int foo( void )
{
char *p, *q;
if ( (p = getmem(BUFSIZ)) == NULL ) {
return ERROR_CODE;
}
if ( (q = getmem(BUFSIZ)) == NULL ) {
getmem( FREE_ALL_MEM );
return ERROR_CODE;
}
/* Do some other work... */
getmem( FREE_ALL_MEM );
return SUCCESS_CODE;
}
it is matter of habit, but I prefer:
int returnFlag = FAILURE;
if ((p = malloc...) != NULL)
{
if ((q = malloc..) != NULL)
{
// do some work
returnFlag = SUCCESS; // success only if it is actually success
free(q);
}
free(p);
}
return returnFlag; // all other variants are failure
IF you are expecting to allocate a large number of items, it Can get messy. Try to avoid the 'goto' approach. Not because of the old 'goto is bad' ethic, but because that way really can lie madness and memory leaks.
It's a little overkill for small numbers of malloc, but you can consider something like this approach:
void free_mem(void **ptrs, size_t len)
{
for (size_t i = 0; i < len; ++i)
{
free(ptrs[i]);
ptrs[i] = NULL;
}
}
int foo(...)
{
void *to_be_freed[N];
int next_ptr = 0;
for (size_t i = 0; i < N; ++i) to_be_freed[i] = NULL;
p = malloc(..);
if (!p)
{
free_mem(to_be_freed,N);
return ERROR_CODE;
}
to_be_freed[next_ptr++] = p;
// Wash, rinse, repeat, with other mallocs
free_mem(to_be_freed,N)
return SUCCESS;
}
In reality, you can probably wrap malloc with something which tracks this. Put the array and array size in a structure and pass that in with the desired allocation size.
I think the first answer is the most general purpose as it can be used for errors other than those caused by malloc. However I would remove the gotos and use a single pass while loop like so.
int foo()
{
char *p = NULL;
char *q = NULL;
int ret = 0;
do {
if (NULL == (p = malloc(BUFSIZ)))
{
ret = ERROR_CODE;
break;
}
// possibly do something here
if (NULL == (q = malloc(BUFSIZ)))
{
ret = ERROR_CODE;
break;
}
// insert similar repetitions
// hopefully do something here
} while(0);
free (p);
free (q);
return ret;
}
I have a queue of set length implemented as a dynamic c array implemented like this:
typedef struct {
float* queue;
int size;
int pointer;
} QueueStruct;
void createQueue(QueueStruct* queueInstance, int size){
queueInstance->queue = malloc(sizeof(float)*size);
queueInstance->size = size;
queueInstance->pointer = 0;
}
void addElementToQueue(QueueStruct* queueInstance,float element){
queueInstance->queue[pointer] = element;
if (queueInstance->pointer == queueInstance.size - 1){
queueInstance->pointer = 0;
} else {
++queueInstance->pointer;
}
}
void freeQueue(QueueStruct* queueInstance){
free(queueInstance->queue);
}
And I want to implement this function:
float* returnQueue(QueueStruct queueInstance){
//I want this function to malloc a new float* and then put the queue in it in the
// correct order, from start to finish, as pointed too by the pointer.
//Im not sure how to do this.
}
Any help would be appreciated.
Edit: Corrected a silly programming mistake - this is a simplified version of what is actually in my program.
Let's see if I got that right.
float* returnQueue(QueueStruct *queueInstance){
int j = 0;
float *ret = malloc(sizeof(float)*queueInstance->size); //Allocates the memory you want.
//Copies the elements from pointer to End into the new buffer (assumes, that the array has been filled at least once, add a marker to make sure)
if(queueInstance->FilledOnce) { //Marker variable, explanation as above.
for(int i = queueInstance->pointer; i < queueInstance->size; ++i, ++j)
ret[j] = queueInstance->queue[i];
}
//Copies the newest elements (from beginning to pointer) into the buffer.
for(int i = 0; i < queueInstance->pointer; ++i, ++j)
ret[j] = queueInstance->queue[i];
return ret; //Returns the code in question.
}
To make this code work, you'd have to add 'FilledOnce' to your struct, and amend your 'Add' Code as follows:
void addElementToQueue(QueueStruct* queueInstance, float element){
queueInstance->queue[queueInstance->pointer] = element;
if (queueInstance->pointer == queueInstance.size - 1){
queueInstance->pointer = 0;
queueInstance->FilledOnce = 1;
} else {
++queueInstance->pointer;
}
}
I also advise you, to reset your variables, once you're done with it.
void freeQueue(QueueStruct* queueInstance){
free(queueInstance->queue); //Frees the queue
queueInstance->queue = NULL; //Nulls the reference
queueInstance->FilledOnce = 0;
queueInstance->pointer = 0;
queueInstance->size = 0;
}
This way, if you reuse the struct, you won't run into the problem of trying to access non-allocated memory. Just be sure to check for those variables.
I hope this helps.
I think you should allocate memory for your struct also.
You have made pointer of struct but forgot to allocate memory for that struct
use QueueStruct queuestruct= malloc(sizeof(Queuestruct))
then when you pass this to any of the function above then you can easily allocate
memory for queue poiter in which you can store element for your queue array
This implementation is insufficient. A pointer variable give us location of a tail of queue, but what points to it's head?
I've been trying to build a priority queue in C.
First of all, I do some initialization work such as allocating space.
The following is the Initialize routine and PriorityQueue is a pointer.
void Initialize(int MaxElement, PriorityQueue H)
{
if (MaxElement < MinPQSize)
printf("Priority queue size is too small");
if (!(H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
printf("Out of space!!!");
if (!(H->Elements = (ElementType *)malloc((MaxElement+1) * sizeof(ElementType))))
printf("Out of space!!!");
H->Capacity = MaxElement;
H->Size = 0;
H->Elements[0] = MinData;
}
Here is how the test code is like
int MaxElement = 15;
PriorityQueue myHeap;
Initialize(MaxElement, myHeap);
But when I try to insert elements into the heap, a segmentation fault pops out.
It can be solved by simply returning the PriorityQueue pointer from Initialize routine.
PriorityQueue Initialize(int MaxElement, PriorityQueue H)
{
...
return H;
}
myHeap = Initialize(MaxElement, myHeap);
So what's happening under the hood?
Is free() invoked when the function returns without a return value?
Thx in advance!
No, even though the H that you're passing in is a pointer, you're trying to change it within the function (with your first malloc). In order to change something, you need to pass a pointer to it. In this case, that means a pointer to a pointer:
void Initialize (int MaxElem, PriorityQueue *H) {
if (MaxElem < MinPQSize)
printf("Priority queue size is too small");
if (!(*H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
printf("Out of space!!!");
if (!((*H)->Elements = (ElemType *)malloc((MaxElem+1) * sizeof(ElemType))))
printf("Out of space!!!");
(*H)->Capacity = MaxElem;
(*H)->Size = 0;
(*H)->Elements[0] = MinData;
}
Without the extra level on indirection, the H that you change within the function is isolated to the function - it is not reflected back to the caller.
A couple of other points you may want to consider:
You shouldn't cast the return from malloc, it can hide certain errors that you really do want to know about.
If your second malloc fails, you should free the result of the first malloc.
If either of your malloc calls fail, you should return rather than continue, since continuing will cause undefined behaviour if you dereference the null pointer.
You probably don't want to print things from general purpose functions since that's probably an unwanted behaviour. If you must indicate a problem, you're better off passing back an indication to the caller to let them handle it in their own way.
Although to be honest, I actually like the versions that return a value (with no need to pass it in beforehand since you're clearly creating a new thing). Something like this should do:
PriorityQueue Initialize (int MaxElem) {
PriorityQueue H;
if (MaxElem < MinPQSize) {
printf("Priority queue size is too small");
return NULL;
}
if (!(H = malloc(sizeof(*H)))) {
printf("Out of space!!!");
return NULL;
}
if (!(H->Elements = malloc((MaxElem+1) * sizeof(ElementType)))) {
printf("Out of space!!!");
free (H);
return NULL;
}
H->Capacity = MaxElem;
H->Size = 0;
H->Elements[0] = MinData;
return H;
}
PriorityQueue myHeap = Initialize (MaxElement);
You are passing the pointer by value, allow me to illustrate:
char* c = 0;
void set_c(char* ptr)
{
ptr = (char*) malloc(sizeof(char) * 10);
}
// a copy of c is sent in,
set_c(c);
// c doesn't point to the newly allocated data!
To set it correctly, you have to pass your pointer BY pointer, like this:
void set_c_correctly(char** ptr)
{
*ptr = (char*) malloc(sizeof(char) * 10);
}
// a pointer to c is passed in
set_c_correctly(&c);
// now c points to the newly allocated data