I had a job interview and I was asked the following question:
The free() function is too "expensive." We want to implement a function
named myFree() with the prototype void myFree( void* p ).
myFree needs to save the pointer p in some way, instead of what
the free() function would do.
At the moment, when the programmer decides to free the pointers which he saved by the myFree function, he use the function myFinalFree().
I have only one global pointer that I can use when implementing myFree, therefore I can't allocate any extra memory.
Any ideas for myFree?
You can manage the pointers in a linked-list:
Initialize a global head=0
Inside function myFree(p):
Set the value at the address pointed by p to the value of head
Set the value of head to the value of p
Inside function myFinalFree():
Start from head and free all pointers until reaching 0
Set the value of head back to 0
Here is a coding example:
typedef int t_ptr;
static t_ptr head = 0;
void myFree(void* p)
{
if (p)
{
*(t_ptr*)p = head;
head = (t_ptr)p;
}
}
void myFinalFree()
{
t_ptr* p = (t_ptr*)head;
while (p)
{
head = *p;
free(p);
p = (t_ptr*)head;
}
}
Notes:
You have to make sure that sizeof(t_ptr) == sizeof(void*)
The above code works under the assumption that malloc always allocates at least sizeof(void*) bytes, aligned to an address which is a multiple of sizeof(void*)
Related
I am implementing a Linked List using an array.It has a function Reverse
defined below
void Reverse(List *l)
{
List *m=CreateList(ListSize(l));
for(int i=0;i<l->count;i++)
{
m->array[i]=l->array[l->count-i-1];
m->count++;
}
free(l->array);
free(l);
l=m;
//Traverse(l); Here it prints the reversed List
}
It takes a List structure as a argument. I am calling it from main like this
int main()
{
size=5;
List *l=CreateList(size);
Reverse(l);
Traverse(l); //Here the list is not printing the reversed list !
}
Why are the changes I made to l in reverse not showing up in main() ?
Thanks !
You have to pass a double pointer to be possible to change where does the pointer points.
void Reverse(List **l);
Reverse(&l);
Its not possible in C to pass by reference, from www-cs-students.stanford.edu:
In C, Pass-by-reference is simulated by passing the address of a
variable (a pointer) and dereferencing that address within the
function to read or write the actual variable. This will be referred
to as "C style pass-by-reference."
When you do l = m, you are just setting l within Reverse. l is part of the argument list to Reverse. When you change the value, it only changes it for the duration of the call to Reverse. It never gets propagated to the caller.
You can use Filip's method to propagate the value.
Or, you can:
redefine Reverse as: List *Reverse(List *l)
add return m as the last statement in it
and call via: l = Reverse(l).
But, this is a bit wasteful. You can also do an in-place reversal:
void Reverse(List *l)
{
int left = 0;
int right = l->count - 1;
// NOTE: this should be whatever the type of array[0] is:
int tmp;
for (; left < right; ++left, --right) {
tmp = l->array[left];
l->array[left] = l->array[right];
l->array[right] = tmp;
}
}
UPDATE:
When I do *l=*m in the last line the code works but I dont know why !
Even that has a bug.
That is because you are replacing the entire contents of what l points to. Essentially, you created a new [reversed] list m, filled it, then copied it back to l.
Doing free(l) before doing *l = *m is a bug. You are dereferencing a pointer to freed memory.
You do want to do free(l->array), but not free(l).
Also, after doing *l = *m, you need to do free(m). Otherwise, you have a memory leak on the struct that m points to [but not what m->array points to because it gets saved in l->array].
This is needless complexity and error prone.
And you did twice as much work as needed. When you do *l = *m, you are really doing:
l->count = m->count;
for (int i = 0; i < m->count; ++i)
l->array[i] = m->array[i];
In other words, don't do the *l = *m, even if it seems to work. Use one of the three easier/correct ways.
UPDATE #2:
It seems to work fine though(*l=*m) even if the memory that l points to doesn't exist . Please tell me what does the function free() actually does in this case
Yes, it seems to work fine, but it does not work fine [in the general case].
After you do free(l), what l pointed to is unavailable. The memory allocator assumes that you have no further use for this memory [because when you do free(l), you are telling it so]. The allocator is at liberty to do whatever it wishes with that memory:
In a multithreaded environment, between the time you call free(l) and it returning control to you, another thread could have done a malloc and now you have two threads pointing to the same memory and using it for different purposes. Doing the subsequent *l = *m would corrupt the data that the other thread is storing there. This introduces a subtle, intermittent, hard to find bug.
In a single threaded environment, the memory allocator might use the memory to store metadata for its own [internal] purposes. Again, before it returns from free(l). So, when you do *l = *m, you could be corrupting the allocator's internal data structures (or vice versa). The next time you issue a malloc, the allocator might segfault.
The next time you issue a malloc, it might return a pointer to the same memory that l is/was pointing to (e.g. you create a second list [in main] by calling l2 = CreateList(10)). Now, l and l2 have the same value (i.e. they point to the same struct). So, instead of l and l2 being separate lists, they collide. Or, l2 might be different, but l2->array might overlap with l
Below is one example of a general resource allocation/release problem. Because you don't know what the allocate or release functions do internally, you can't be safe accessing anything inside the resource after it's been released/freed. The release function below adds one line to illustrate why it's unsafe to do what you did with *l = *m
#include <malloc.h>
struct resource {
int count;
int *array;
};
struct resource *
allocate_resource(int count)
{
struct resource *ptr;
ptr = malloc(sizeof(struct resource));
ptr->count = count;
ptr->array = malloc(sizeof(int) * count);
return ptr;
}
void
free_resource(struct resource *ptr)
{
free(ptr->array);
// prevents "*l = *m" from "seeming to work"
ptr->array = NULL;
free(ptr);
}
int
main(void)
{
while (1) {
struct resource *x = allocate_resource(20);
// x may be utilized here ...
free_resource(x);
// x may _not_ be utilized here ...
// this will segfault
x->array[0] = 23;
}
return 0;
}
In C, function arguments are always passed by value. This means that in the function ReverseList() l is a copy of the pointer to List that was passed in the function call. So, when the reversed List is created, and the address is assigned to l within the function, this has no effect on the original pointer to List in main() (since l within Reverse() is only a copy of l within main()). It may help to give variables in functions names that are different from their corresponding names in callers to help keep this sort of thing straight.
One solution is to pass a pointer to pointer to List into the Reverse() function:
void Reverse(List **lptr)
{
List *m=CreateList(ListSize(*lptr));
for(int i=0;i<(*lptr)->count;i++)
{
m->array[i]=(*lptr)->array[(*lptr)->count-i-1];
m->count++;
}
free((*lptr)->array);
free(*lptr);
*lptr=m;
//Traverse(l); Here it prints the reversed List
}
Call this function with Reverse(&l). Here, since a copy of a pointer to a pointer to List is used in Reverse(), and lptr points to the pointer l in main(), lptr can be dereferenced and the value of m can be assigned to the actual pointer to List (l) found in main().
An alternative solution is to change the Reverse() function to return a pointer to List to the caller. Then the returned value is assigned to l:
List * Reverse(List *l)
{
List *m=CreateList(ListSize(l));
for(int i=0;i<l->count;i++)
{
m->array[i]=l->array[l->count-i-1];
m->count++;
}
free(l->array);
free(l);
return m;
//Traverse(l); Here it prints the reversed List
}
int main(void)
{
size=5;
List *l=CreateList(size);
l = Reverse(l);
Traverse(l); //Here the list is not printing the reversed list !
return 0;
}
Also, if CreateList() is not already checking for allocation errors, the code should be checking for these before freeing the previous allocations.
I have a problem with adding data to my tree using this function.
I am using codeblocks and when I run my program it gives me windows error box
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct arb{
int data;
struct arb*FG;
struct arb*FD;
};
void remplit(struct arb*r,int i)
{
if (r==NULL)
{
r=malloc(sizeof(struct arb));
r->data=i;
r->FD=NULL;
r->FG=NULL;
}
else
{
if (i>(r->data))
{
remplit(r->FD,i);
}
else
{
remplit(r->FG,i);
}
}
}
struct arb * test=NULL;
int main()
{
remplit(test,5);
printf("%d",test->data);
return 0;
}
You are passing your pointer by value, not name.
remplit(test,5);
This sends the value of test to remplit.
r=malloc(sizeof(struct arb));
This points r, a local variable, to the allocated memory. This doesn't effect the value of test in main.
printf("%d",test->data);
test is still NULL, your attempt to de-reference it causes a seg fault.
You have a global pointer set to NULL. You then pass that pointer by value to another function that allocates dynamic memory to it with malloc.
The problem is that because the pointer is passed by value, the value of the global is unchanged (is still NULL) because the copy of your pointer now stores the address of the memory region allocated by malloc and not your global pointer.
Now when you dereference the pointer (after the call to remplit) it is giving you a segfault because test is still NULL.
If you want to use a function to allocate memory to a pointer that you pass to it, you need to make the function take a double pointer and assign the return value of malloc to the dereference of the pointer.
As a simple example, consider the following for creating a char array using double pointer and a utility function that does the allocation
void create_char_array(char** p, int size)
{
*p = NULL;
*p = malloc(size * (sizeof char));
/* *p now points to dynamically allocated memory */
}
int main()
{
char* my_array;
/* allocate memory for an array of 10 chars using above function
by passing the address of my_array */
create_char_array(&my_array,10);
if (my_array != NULL)
{
/* you can now safely assign values to valid the indices in the array */
}
/* release memory */
free (my_array);
return 0;
}
If you learn to use a debugger, you can step through your code at all steps. You should see that inside your function the memory is allocated to your r pointer (which is a copy of test), but that the value of the global test pointer is still NULL. Your code actually has a memory leak because the copy of the pointer inside your function is destroyed when the function exits. Memory has been allocated to it but there is no way to free it as the variable no longer exists.
I learned from this page: FAQ that, if you want to initialize a pointer inside a function, then you should pass a pointer to pointer, i.e, **p as foo1()
void foo1(int **p) {
*p = malloc(100*sizeof(int)); // caller can get the memory
}
void foo2(int *p) {
p = malloc(100*sizeof(int)); // caller cannot get the memory
}
However, a pointer means its value is the address it points to. Where does the memory allocated in foo2() go after leaving its scope?
I still can't figure out the different behavior between passing pointer to value and pointer to pointer? I search through SO but only found the solution or short description. Could anyone help in more detail?
The memory allocated in foo2 is lost. This creates a memory leak because you have no idea where to find and use the allocated memory after foo2 returns.
Consider:
int *mymemory = NULL;
foo2(mymemory);
//mymemory is still NULL here. Memory has been allocated,
//but you don't know at which address
//in particular, you will never be able to free() it
versus:
int *mymemory = NULL;
foo1(&mymemory);
//mymemory is now the address of the memory
//allocated by the function
dostuffwith(mymemory);
free(mymemory);
Maybe it helps if we start with only one level of indirection.
consider this:
void foo1(int *p) {
^^
//this p is local to the foo1 function
//p contains the address of an int
*p = 12;
//now we dereference the pointer, so we set what p points to , to 12
}
void func(void) {
int x;
^^
//here is the x
foo1(&x);
^^
//now we find the location (address of) x, we copy that address
//into the arguments for foo1()
//foo1 sets our x int to 12
}
Let's add one more indiretion:
void foo1(int **p) {
^^
//this p is local to the foo1 function
//p contains the address of a pointer to an int
*p = NULL;
//now we dereferenced the pointer, so we get an int*. We just
//set it to NULL
}
void func(void) {
int *x;
^^
//here is the x.
foo1(&x);
^^
///now we find the location (address of) x, we copy that address
//into the arguments for foo1()
//foo1() sets the x pointer to NULL.
}
In both cases we are able to manipulate the x variable inside func1(), since the location(address of)
the x variable is passed into func1().
In the last case, we did *p = NULL;. Which would make x == NULL. We could have set it
to something that malloc() returned: *p = malloc(100)
But if we alter the first case:
void foo1(int *p) {
^^
//this p is local to the foo1 function
//p contains the address of an int
p = NULL;
//now we just set the local `p` variable to NULL.
//the caller will not see that, since `p` is just our own copy
//of pointer.
}
void func(void) {
int x;
^^
//here is the x
foo1(&x);
//foo1 just set its own copy of the pointer we created by doing `&x` to NULL.
//we will not see any changes here
}
We just set p = NULL; in the last case here. If we used malloc instead:
void foo1(int *p) {
^^
p = malloc(100);
//now we just set the local `p` variable to what malloc returns.
//the caller will not see that, since `p` is just our own local copy
//of the pointer.
//When foo1() returns, noone has any way of knowing the location
//of the memory buffer that malloc returned, so this memory is lost (a memory leak)
}
In your second example the memory allocated is leaked - once foo2 ends, there is no variable left that contains the address that was allocated, so it can't be freed.
You could also consider
void foo3 (int bar) {
bar = 8;
}
int main (int argc, char *argv[]) {
int x = 0;
foo3(x);
printf("%d\n", x);
return 0;
}
when foo3 ends, x is still 0 - the change to the contents of bar in foo3 don't affect the outer variable that was passed in. You're doing exactly the same when you pass in a single pointer - you're assigning the address of some memory to it, but then losing that address when the function exits.
To better understand indirection levels in C, it can be instructive to look at how the compiler organizes its memory.
Consider the following example :
void function1 (int var1, int var2) { ... }
In this case, function1 will receive 2 variables. But how ?
These variables will be put into the call stack memory. This is a linear, LIFO (Last in, First Out) type of allocation strategy.
Before calling function1(), the compiler will put var1 then var2 into the call stack, and increment the position of the call stack ceil. Then it will call function1(). function1() knows it must get 2 arguments, and so it finds them into the call stack.
What happens after function1() finishes ? Well, the call stack is decremented, and all variables into it are simply "disregarded", which is almost the same as "being erased".
So it's pretty clear that whatever you do to these variables during function1() is going to be lost for the calling program. If anything has to remain available to the calling program, it needs to be provided into a memory space that will survive the call stack decrement step.
Note that the logic is the same for any variable inside function1() : it will be unavailable to the calling function after function1() finishes. In essence, any result still stored into function1() memory space is "lost".
There are 2 ways to retrieve a usable result from a function.
The main one is to save the result of the function into a variable of the calling program/function. Consider this example :
int* foo3(size_t n) { return (int*) malloc(n); }
void callerFunction()
{
int* p;
p = foo3(100); // p is still available after foo3 exits
}
The second, more complex, one is to provide as an argument a pointer to a structure which exists into the calling memory space.
Consider this example :
typedef struct { int* p; } myStruct;
void foo4(myStruct* s) { s->p = (int*) malloc(100); }
void callerFunction()
{
myStruct s;
foo4(&s); //p is now available, inside s
}
It is more complex to read, but also more powerful. In this example, myStruct contains a single pointer, but the structure could be a lot more complex. This open the perspective to offer myriad of variables as the result of a function, instead of being limited to basic types, as for the previous example with foo3().
So what happens when you know that your structure is in fact a simple basic type ? Well, you can just provide a pointer to it. And, by the way, pointer is itself a basic type. So if you want to get the result of a modified pointer, you can provide as an argument, a pointer to a pointer. And there we find foo1().
void foo1(int **p) {
*p = (int *) malloc(100); // caller can get the memory
}
The problem with foo2 is that the p which is passed in is only modified inside the foo2 function. This is the same as :
void bar(int x)
{
x = 42;
}
...
int a = 7;
bar(a);
...
In the above code, a doesn't change because of the call to bar. Instead, a copy of a is passed to bar, and the copy is modified in bar.
The exact same thing happens in foo2. The memory is allocated, stored in p, which is a copy of the pointer passed in. When the code returns, the original pointer retains its original value.
By passing the address of a pointer (&ptr) to foo1, we can modify the ORIGINAL pointer, and thus pass the address of the allocation back to the caller of foo1.
Of course, when there is no reference back to the originally allocated memory, as is the case after a call to foo2, it is called a memory leak - generally considered a bad thing.
Passing a pointer to value: A copy of the pointer(i.e. address of the value) is made in the function(on the stack frame). This allows you to modify the value.
Passing a pointer to a pointer: A copy of the pointer to a pointer(i.e. address of the pointer which in turn points to the value) is made in the function(on the stack frame). This allows you to modify the value as well as the pointer to this value.
The memory allocated using malloc, calloc, realloc and new resided on the heap which means that it exists even after a function returns(stack frame destroyed).
void foo2(int *p) {
p = (int *) malloc(100); // caller cannot get the memory
}
However, since the pointer p is lost after the function is returned, this memory cannot be accessed and will result in a leak.
As behaviour of all arguments is the same as local variables (they are passed by value), you can not modify pointer passed by value.
So in foo2() you allocate memory, but you can not use it outside the function, as you actually modify local variable.
The foo() function actually modifies the value pointed by **p, so pointer passed to function will be updated.
OK, this is the definition of the struct:
typedef struct {
int first;
int last;
int count;
char * Array [50];
} queue;
and I use another function to initialize it
void initialize(queue * ptr){
ptr=malloc(sizeof(queue));
ptr->first=0;
ptr->last=0;
ptr->count=0;
}
Then I use printf to print out first, last and count. All three should be zero. However, what I actually get is, count is 0 as I expected, but first&last are two very large strange numbers and they change every time I run the program. Can anybody tell me what's wrong here? Thank you.
You are passing your pointer by value. The function changes a copy of the argument it receives, but the caller's pointer is not modified and is probably unintialized.
You need to change your function to take a queue** and pass the address of the pointer you want to initialize.
Alternatively you could return a pointer instead of passing it in as an argument. This is a simpler approach.
Given:
void initialize(queue * ptr);
Pass it like this:
queue q; // caller allocates a queue
initialize(&q);
// now q is initialized
Also, it's allocated by the caller -- don't malloc it.
// bad
void initialize_bad(queue * ptr){
ptr=malloc(sizeof(queue)); << nope. already created by the caller. this is a leak
ptr->first=0;
ptr->last=0;
ptr->count=0;
}
// good
void initialize_good(queue * ptr){
ptr->first=0;
ptr->last=0;
ptr->count=0;
// ptr->Array= ???;
}
If you prefer to malloc it, then consider returning a new allocation by using this approach:
queue* NewQueue() {
// calloc actually works in this case:
queue* ptr = (queue*)calloc(1, sizeof(queue));
// init here
return ptr;
}
Ultimately, what is 'wrong' is that your implementation passes a pointer by value, immediately reassigns the pointer to a new malloc'ed allocation, initializes the malloc'ed region as desired, without ever modifying the argument, and introducing a leak.
Here is the smallest alteration to your program which should correct your problem:
void initialize(queue * * pptr) {
queue * ptr;
ptr=malloc(sizeof(queue));
if (ptr) {
ptr->first=0;
ptr->last=0;
ptr->count=0;
}
/* The assignment on the next line assigns the newly allocated pointer
into memory which the caller can access -- because the caller gave
us the address of (i.e. pointer to) such memory in the parameter
pptr. */
*pptr = ptr;
}
The most important change is to pass a queue ** to your initialize function -- otherwise you are changing a copy of the queue * supplied as the actual parameter when you call initialize(). By passing a pointer to the pointer, you can access the original variable which stores the pointer in your caller.
I couldn't resist and also added a check for NULL returned from malloc(). That doesn't address your problem, but I couldn't bring myself to post code that didn't do it.
How come the following code result in seg fault? Basically after I copy the head pointer to temp, the head pointer gone.
typedef struct address * paddress; // defines struct pointer
void addAddressToList(paddress head, int addr[])
{
if (head == NULL) {
//head->addrArray = addr; // if list is initially empty
} else {
paddress temp;
temp = head;
while (temp->right != NULL) {
temp = temp->right; // go to end of the list
}
paddress newAddress = (paddress)malloc(sizeof(paddress*));
newAddress->intAddr = addr;
newAddress->right = NULL;
newAddress->left = temp; // connect the new address
temp->right = newAddress;
}
}
main() {
paddress addressListHead;
addressListHead = (paddress)malloc(sizeof(paddress*));
int intAddr1[] = {1,2,3,4,5,6,7};
char hexAddr1[] = "123456";
int intAddr2[] = {16,14,13,12,11};
char hexAddr2[] = "fedcb";
addressListHead->intAddr = intAddr1;
addressListHead->hexAddr = hexAddr1;
addAddressToList(addressListHead, intAddr2);
}
paddress addressListHead;
addressListHead = (paddress)malloc(sizeof(paddress*));
It seems to get rid of the compilation error, you have type casted what malloc is returning to paddress. addressListHead is a pointer, which means it can hold the address of an object but not the address of a pointer. The malloc here statement doesn't create an object. You need to change this -
addressListHead = (paddress)malloc(sizeof(paddress*));
to
addressListHead = (paddress)malloc(sizeof(struct address));
in main and addAddressToList functions.
Segmentation fault :
else {
paddress temp;
temp = head;
while (temp->right != NULL) {
temp = temp->right; // go to end of the list
}
I understand paddress::right is a pointer with the fact you are comparing it to NULL. But what is temp::right is initialized to. It is pointing to some garbage address and so you cannot ask for it to compare with NULL. Make it point to a valid memory location.
There is more than one problem in your code.
Firstly, the usual advice: stop using sizeof with type names (as much as possible). Use sizeof with expressions, not types. Type names belong in declarations and nowhere else.
Your problem with memory allocation could have been prevented if you used this malloc idiom
T *p = malloc(n * sizeof *p);
i.e. sizeof should be applied to *p, where p is the pointer to the array you are allocating and n is the total number of elements in that array. That way you never have to guess what type name you should specify under sizeof (an that way your code becomes type-independent).
In your case you are allocating just one object, so the code should look as
paddress newAddress = malloc(sizeof *newAddress);
(And don't cast the result of malloc - there's absolutely no point in doing that).
Secondly, when you the head element of the list, you need to initialize all the fields. Yet you never initialize right (or left) in the head element. Hence the crash even when the correct amount of memory is allocated.
In main(), you want
addressListHead = (paddress)malloc(sizeof(address));
That makes sure you get enough bytes to hold an address.
First error:
addressListHead = (paddress)malloc(sizeof(paddress*));
paddress* means a pointer to paddress which itself is a pointer to struct address. Hence paddress* is a pointer to a pointer to struct address. You would want to do:
addressListHead = (paddress)malloc(sizeof(struct address));
Also, I see that you made a similar mistake yesterday. Why do I get a seg fault? I want to put a char array pointer inside a struct
It's important to understand the concept of pointers properly. I would definitely recommend you to go through some tutorials on pointers. If you need help with that, let me know.