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
Related
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 .
Apologies for the really bad question - I wasn't really sure how to word it.
I'm executing a piece of code where I'm trying to use a dynamic array. It is segfault-ing at this line:
void myFunction(....) {
// other code up here
Stack *s = stack_new(); //segfault here
}
The relevant header file for my struct is:
typedef struct {
void **A;
int size;
int top; // the index of the current top of the stack
} Stack;
and the function stack_new() is:
Stack
*stack_new() {
Stack *s;
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
I think I've included everything that is relevant, but please let me know if you need more code.
I think that the problem is with the way I'm using malloc, but have had a search online and have tried a few different options and am still getting the segfault. Is anyone able to offer some insight?
Thank you heaps
This is your problem:
Stack *s;
s->size = 1;
you're not actually allocating a Stack. s is uninitialized and points to an arbitrary location in the memory. s->size will obviously fail then.
Try:
Stack *s = malloc(sizeof(*s));
if (s == NULL)
{
fprintf(stderr, "Memory allocation error\n");
exit(1);
}
s->size = 1;
Note: you should also check if s->A is NULL. If so, return an error code (such as NULL) and before that remember to free the Stack you allocated, or alternatively print an error message and exit the program. If you exit the program, the operating system will reclaim all memory used so no need to do it explicitly then.
Another note: when doing
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
...you allocate 1 byte of memory even though you should be allocating sizeof(void*) bytes of memory. Try doing
s->A = (void **)malloc(s->size*sizeof(void*));
instead.
Here's your first problem:
Stack *s;
s->size = 1;
What do you actually expect the value of s is at this point? It could be literally anything. You can't set a field of a struct if the struct itself isn't already allocated.
Try:
Stack *s = malloc(sizeof(*s));
if(!s){
//... error checking / exiting ..
}
and then everything else you were doing.
You are accessing a not initialized pointer!
Stack
*stack_new() {
Stack *s = std::nullptr; // initialize this pointer with nullptr
// and then you will see later (one line
// beyond) that you will try to access a
// null pointer
s->size = 1; // the problem occurs here!!
// you are accessing a pointer, for which has never
// been allocated any memory
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
You will have to use "malloc" to allocate some memory for this pointer.
sth. like this is missing between those two lines, I commented:
Stack
*stack_new() {
Stack *s = (Stack*)malloc(sizeof(Stack));
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
This question already has an answer here:
free char*: invalid next size (fast) [duplicate]
(1 answer)
Closed 8 years ago.
I know there are tons of other realloc questions and answers and I have read almost all of them, but I still couldn't manage to fix my problem.
I decided to stop trying when I accidentaly discovered a very strange behaviour of my code.
I introduced a line to try something, but although I don't use the value of newElems in main, the line changes the behaviour.
When the line is commented, the code fails at first realloc. Including the line, the first realloc works. (it still crashes on the second one).
Any ideas on what might be happening?
int main(int argc, char** argv) {
Pqueue q = pqueue_new(3);
Node a = {.name = "a"}, b = {.name = "b"},
c = {.name = "c"}, d = {.name = "d"};
push(& q, & a, 3);
// the next one is the strange line: as you can see, it doesn't modify q
// but commenting it out produces different behaviour
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
push(& q, & b, 5);
push(& q, & c, 4);
char s[5];
Node* n;
for (int i = 1; i <= 65; ++i) {
sprintf(s, "%d", i);
n = malloc(sizeof *n);
n->name = strdup(s);
push(& q, n, i);
}
Node* current = NULL;
while ((current = pop(& q))) {
printf("%s ", current->name);
}
return 0;
}
and the push function:
void push(Pqueue* q, Node* item, int priority) {
if (q->size >= q->capacity) {
if (DEBUG)
fprintf(stderr, "Reallocating bigger queue from capacity %d\n",
q->capacity);
q->capacity *= 2;
Pqueue_elem* newElems = realloc(q->elems,
q->capacity * sizeof *newElems);
check(newElems, "a bigger elems array");
q->elems = newElems;
}
// append at the end, then find its correct place and move it there
int idx = ++q->size, p;
while ((p = PARENT(idx)) && priority > q->elems[p].priority) {
q->elems[idx] = q->elems[p];
idx = p;
}
// after exiting the while, idx is at the right place for the element
q->elems[idx].data = item;
q->elems[idx].priority = priority;
}
The pqueue_new function:
Pqueue pqueue_new(unsigned int size) {
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return *q;
}
realloc will change the amount of memory that is allocated, if needed. It is also free to move the data to another place in memory if that's more efficient (avoiding memory fragmentation).
The function, then, returns a new pointer to the new location in memory where your data is hiding. You're calling realloc, and allocating (probably) four times as much memory as before, so it's very likely that that allocated memory is situated elsewhere in memory.
In your comment, you said realloc works like free + malloc. Well, in some cases it can behave similarly, however: realloc and free are different functions, that do different tasks. Both are functions that manage the dynamic memory, so yes, obviously there are similarities, and in the case of realloc, sometimes they can seem to be doing the same thing, however: As I explained here, realloc and free are fundamentally different functions
However, by not assigning the return value of realloc to q.elems, you're left with a pointer to a memory address that is no longer valid. The rest of your program can, and probably does, exhibit signs of undefined behaviour, then.
Unless you show some more code, I suspect this will take care of the problem:
//change:
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
//to
q.elems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
Or better yet, check for NULL pointers:
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
if (newElems == NULL)
exit( EXIT_FAILURE );// + fprintf(stderr, "Fatal error...");
q.elems = newElems;//<-- assign new pointer!
Looking at your pqueue_new function, I would suggest a different approach. Have it return the pointer to Pqueue. You're working with a piece of dynamic memory, treat it accordingly, and have your code reflect that all the way through:
Pqueue * pqueue_new(size_t size)
{//size_t makes more sense
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return q;
}
Alternatively, pass the function a pointer to a stack variable:
void pqueue_new(Pqueue *q, size_t size)
{
if (q == NULL)
{
fprintf(stderr, "pqueue_new does not do NULL pointers, I'm not Chuck Norris");
return;//or exit
}
if (size < 4)
size = 4;
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
}
//call like so:
int main ( void )
{
Pqueue q;
pqueue_new(&q, 3);
}
Those would be the more common approaches.
Thank you all for the suggestions! I wouldn't have solved it without them,
The strange behaviour was caused by an off by one error. I was reallocating the queue only when q->size >= q->capacity, but since q was indexed from 0, it meant that before realloc I was writing in a forbidden location (q->elems[q->size]), which messed everything up.
So I'm very new to C, and I'm writing a matrix compression function for a trivial Bitmap Image recognition program. I have the following code, and Valgrind in telling me I have memory leaks at the following marked lines, although I have no idea what's causing it. Any advice would be appreciated.
/* Returns a NULL-terminated list of Row structs, each containing a NULL-terminated list of Elem structs.
* See sparsify.h for descriptions of the Row/Elem structs.
* Each Elem corresponds to an entry in dense_matrix whose value is not 255 (white).
* This function can return NULL if the dense_matrix is entirely white.
*/
Row *dense_to_sparse(unsigned char *dense_matrix, int width, int height) {
Row *result = NULL;
_Bool first_row;
for (int row = height - 1; row >= 0; row--) {
first_row = 0;
for (int elem = width - 1; elem >= 0; elem--) {
unsigned char curr_item = dense_matrix[(row*width) + elem];
if (curr_item!= 255) {
if (!first_row) {
(Memory Leak) Row *curr_row = (Row *) malloc(sizeof(Row));
if (curr_row == NULL) {
allocation_failed();
}
curr_row->next = result;
curr_row->y = row;
curr_row->elems = NULL;
result = curr_row;
//free(curr_row);
first_row = 1;
}
(Memory Leak) Elem *curr_elem = (Elem *) malloc(sizeof(Elem));
if (curr_elem == NULL) {
allocation_failed();
}
curr_elem->value = curr_item;
curr_elem->x = elem;
curr_elem->next = result->elems;
result->elems = curr_elem;
//free(curr_elem);
}
}
}
return result;
}
I believe it may be a problem with freeing curr_row and curr_elem, although when I try to free them at the end of each loop, it gives me a runtime error:
parsify(73897,0x7fff75584310) malloc: * error for object 0x7fbf81403a48: incorrect checksum for freed object - object was probably modified after being freed.
You need to call free on every pointer that you get from malloc. C doesn't automatically free up memory that you allocate, so you need to tell it "I'm done." Free is how you do this.
EDIT: You should also probably call free at the very end of the function, after you know you're done with the memory. If you do it at the end of the loop, you may run into problems with using memory you already freed.
EDIT EDIT: When you free it, note that you have put result in curr_row->next. You're probably accessing this later, post-free, which is a serious problem. You likely want to free all of them at the same time, as clearly you still need the memory (you still have pointers to it).
You cannot free the memory in dense_to_sparse because the whole point of the function is to create and return the newly allocated data structure. Presumably, the code that calls dense_to_sparse wants to use the result.
You will need a separate function to deallocate the memory that you should call once you no longer need it.
void free_sparse_matrix (Row *matrix)
{
Row *row = matrix;
while (row != NULL) {
Row *next_row = row->next;
Elem *elem = row->elems;
while (elem != NULL) {
Elem *next_elem = elem->next;
free (elem);
elem = next_elem;
}
free (row);
row = next_row;
}
}
My app is use in stlinux (sh4) and unfortunately valgrind does not support sh4 cpu.
since I saw memory leak with my app, I had used mtrace, and it confirmed that some memory is not free. The problem is, variable of malloc used in the return, therefore I do not have any idea, how could I free it (since if it would be free, then returning in the functions is meaningless)?
I had written cs_malloc (put bellow code from oscam-simple.c in above link), mtrace log says, that in line:
*tmp = malloc (size);
memory is not free
/* This function encapsulates malloc. It automatically adds an error message to the log if it failed and calls cs_exit(quiterror) if quiterror > -1.
result will be automatically filled with the new memory position or NULL on failure. */
void *cs_malloc(void *result, size_t size, int32_t quiterror){
void **tmp = result;
*tmp = malloc (size);
if(*tmp == NULL){
cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
if(quiterror > -1) cs_exit(quiterror);
} else {
memset(*tmp, 0, size);
}
return *tmp;
}
And then for malloc, I call it, like this:
// create the AES key entry for the linked list
if(!cs_malloc(&new_entry, sizeof(AES_ENTRY), -1)) return;
Please take a look at these 3 functions (which malloc is not free , and as other users said, valgrind claim that these codes cause memory leaks module-datastruct-llist.c
The memory leaks cause by 3 different parts:
in below codes "new" would never free , but since it use in return of that function, I don't have idea, how could I free it:
LL_NODE* ll_append_nolock(LLIST *l, void *obj)
{
if (l && obj) {
LL_NODE *new;
if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
new->obj = obj;
if (l->last)
l->last->nxt = new;
else
l->initial = new;
l->last = new;
l->count++;
return new;
}
}
also "l" use in below function, again since it use in return function, I have no idea how to free it. :
LLIST *ll_create()
{
LLIST *l = cs_malloc(&l, sizeof(LLIST), 0);
pthread_mutex_init(&l->lock, NULL);
return l;
}
same story with new :
LL_NODE *ll_prepend(LLIST *l, void *obj)
{
if (l && obj) {
LL_NODE *new;
if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
new->obj = obj;
ll_lock(l);
new->nxt = l->initial;
l->initial = new;
if (!l->last)
l->last = l->initial;
l->count++;
ll_unlock(l);
return new;
}
return NULL;
}
For more functions you could see module-datastruct-llist.c
Would highly appreciate, if any expert tell me, how could I fix that memory leak (if you feel, cs_malloc should be rewritten, or need to add new function, please write the source code you are meaning.
The most common implementations of malloc use heap memory, which is global, so it's very common to have storage allocated in one place passed around between a number of functions before it is finally freed.
Now, there are for instance calls to ll_append_nolock where you ignore the malloced return. I.e.
ll_append_nolock(it->l, obj);
so to avoid a leak you need to do what you do in other places, i.e let the calling function receive the allocated memory into a pointer:
LL_NODE *n = ll_append_nolock(l, obj);
/* do stuff with "n", which points to memory allocated under the name of "new" */
free(n);
And when you're through with n (which as noted above points to the storage allocted under the name "new", that is: same memory, different names), you free it.
HTH.
In your function cs_malloc the first parameter is result however you never assign to it in the function cs_malloc.
Later you use cs_malloc like this
if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
new->obj = obj;
which will not work since since "new" is left uninitialized
you should either assign to result in your cs_malloc or just return the block in cs_malloc, if you fail to allocate just return NULL instead.
e.g.
void *cs_malloc(size_t size, int32_t quiterror)
{
void* tmp = calloc(1,size);
if(tmp == NULL)
{
cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
if(quiterror > -1) cs_exit(quiterror);
}
return tmp;
}
and
if (new = cs_malloc(sizeof(LL_NODE),-1))
{
new->obj = obj;
}
else
{
return NULL;
}
#Anders
Thanks for reply , i would take consideration your note ,an would change it as u described to see memory leaks how it's goes...
How , this line should be change to the new cs_malloc function u had written:
1.
LLIST *l = cs_malloc(&l, sizeof(LLIST), 0);
pthread_mutex_init(&l->lock, NULL);
return l;
2.
if(!cs_malloc(¶,sizeof(struct read_thread_param), -1)) return FALSE;
para->id=i;