I do not quite understand the difference between passing to a function *mode1 or **mode2.
I wrote some examples. (note: type can be any type)
[Code 1]
#include <stdio.h>
void function (type *vet)
{
/* other */
}
int main ()
{
type *vet;
function (vet)
/* other */
return 0;
}
[Code 2]
#include <stdio.h>
void function (type **vet)
{
/* other */
}
int main ()
{
type *vet;
function (&vet)
/* other */
return 0;
}
I know: in the first case is a pointer, in the second case is a pointer to a pointer. But why for example in the second case if I pass &vet can I allocate memory in function() and free it in main() and in the first one not?
I search someone who explain me the differences well. What can I do in the two cases? How and where to malloc or realloc? And free? And modify vet in the function?
Original questions
The main (most significant) difference is whether the value in the calling function can be changed.
In the first example, the called function gets a copy of the pointer in the calling code, and cannot modify the pointer in the calling code.
In the second example, the called function gets a pointer to the pointer, and by assigning to *vet in the called function, you can modify the value in the called function.
Why in the second case if I pass &vet can I allocate memory in function() and free it in main() and in the first one not?
In the second case, the code in function() can modify the actual pointer in main(), so the value of vet in main() ends up with the allocated pointer value, which can therefore be freed. In the first case, the value in main() is not modified by the called function, so the data can't be freed by main().
How and where to malloc or realloc? And free?
In the first case, you can use malloc() or realloc() in the function, but you should also free the allocated memory before return unless your code stores the value in a global variable (in which case you can delegate to some other code to handle the free(), but it had better be very clear which code has the responsibility, and in any case using global variables is probably not a good idea). Or unless you change the function signature and return a pointer to the allocated data which should be freed by the calling code.
In the second case, you can allocate or reallocate memory in the called function and leave it allocated to be used by other functions and to be freed by the calling function.
And modify vet in the function?
In both functions, you can modify the local vet variable as you see fit; this is true of any parameter to any function. What you can't necessarily do is modify values in the calling function; you have to have a pointer to value in the calling function to do that. In the first function, you can't change the value of vet in main(); in the second, you can. In both functions, you can change what vet points at. (One minor problem is the conflation of the name vet in the three contexts — the main() and the two different functions. The name vet in the two functions points at different types of things.)
Extension questions
But is it freed in function() like, for example, this?
#include <stdio.h>
#define NUM (10)
struct example
{
/* ... */
}
void dealloc (struct example *pointer)
{
free (pointer);
}
int main()
{
struct example *e;
e = malloc (NUM * sizeof(struct example));
if (e == NULL)
return -1;
struct example *e_copy = e;
dealloc (e_copy);
return 0;
}
This code is legitimate. You pass (a copy of) the value of the pointer to the dealloc() function; it passes that pointer to free() which releases the allocated memory. After dealloc() returns, the pointer values in e and e_copy are the same as before, but they no longer point to allocated memory and any use of the value leads to undefined behaviour. A new value could be assigned to them; the old value cannot be dereferenced reliably.
And what is the difference from this?
#include <stdio.h>
#define NUM (10)
struct example
{
/* ... */
}
int main()
{
struct example *e;
e = malloc (NUM * sizeof(struct example));
if (e == NULL)
return -1;
struct example *e_copy = e;
free (e_copy);
return 0;
}
The difference between this example and the last is that you call free() directly in main(), rather than from a function dealloc().
What would make a difference is:
void dealloc(struct example **eptr)
{
free(*eptr);
*eptr = 0;
}
int main()
{
...
dealloc(&e_copy);
return 0;
}
In this case, after dealloc() returns, e_copy is a null pointer. You could pass it to free() again because freeing the null pointer is a no-op. Freeing a non-null pointer twice is undefined behaviour — it generally leads to problems and should be avoided at all costs. Note that even now, e contains the pointer that was originally returned by malloc(); but any use of that pointer value leads to undefined behaviour again (but setting e = 0; or e = NULL; or e = e_copy; is fine, and using e = malloc(sizeof(struct example)); or such like also works.
As you said, the argument in the first case is a pointer, and a copy of the pointer vet is passed. We can modify the value that vet pointed to (e.g., *vet = new value). But we cannot modify the value of the pointer vet because it is just a copy of the original vet pointer. Therefore, after first function, value of *vet may be changed, but value of vet will not.
So how could we modify the value of the pointer vet? We use the pointer to pointer. In the second function, we can allocate memory for *vet, and this modified value will be kept after the second function. So we can free it in main.
We cannot do this in first case because if we try to allocate memory in function, we just allocate memory for the copy of the pointer vet, not the original vet.
You are correct in your understanding that type *var; is a pointer to data of type and type **var; is a pointer to a pointer to data of type.
The difference you asked about, allocating memory in the function and keeping track of it, is because of the ability to assign the value to the pointer.
In C, any time you want to modify a value in a function, you must provide it a pointer the data it is to modify.
If you want to allocate memory, you must know where it is in order to use it, and later free it. If you pass only a pointer to a function, and allocate memory to it, it cannot change the value of the pointer it is passed (rather, when your program returns to the function that called this allocation function, the stack will have unloaded the address you needed); it can only read from it (which in this use is rather pointless).
Consider this, the pointer variable
type *vet;
is created on the stack of function
main()
when "function_1()" is called from main, a stack for this new function is created. Any argument passed to this function is saved on the stack of this function. In this case, the argument is a pointer variable. Now function_1() can very well change the value of this pointer variable but as soon as the function returns the stack of this function is released and any changes are lost.
But when you are passing a pointer to pointer, what you pass is actually an address of a pointer variable and not a pointer variable. So when you work on this pointer variable inside the called function, you are actually working on the memory of the stack of the calling function. And since this memory is on the stack of the calling function, any changes made by the calling function will persist even after the stack of the called function is released.
First thing is, there is no garbage collector in C. So if you don't explicitely free an allocated memory block, it will eat up memory until the process exits. That is a mighty source of memory leaks.
So, once you've allocated a memory block using malloc or similar functions, you must keep a pointer to it in order to free it someday.
If you allocate a block within a function and you plan this block to remain useable after function termination, you must pass its value to some higher level piece of code that will eventually free it, long after the function that created it has exited.
To do so, you have three basic choices:
store the pointer in some global variable
return the pointer as the function's result
have one of the function arguments specify where the pointer is to be stored
case 1
void * global_address_of_buffer;
void alloc_a_buffer (int size)
{
global_address_of_buffer = malloc (size); // block reference in global var
}
alloc_a_buffer ();
// ...
free (global_address_of_buffer);
This is clearly impractical. If you call your function twice, you will lose the address of the first buffer.
One of the innumerable illustrations of why using globals will drag you screaming right into hell.
Nevertheless, it's a possibility.
case 2
void * alloc_a_buffer (int size)
{
return malloc (size); // block reference as return value
}
void * new_buffer;
new_buffer = alloc_a_buffer (10); // retrieve pointer through return value
// ...
free (new_buffer);
This is not always possible. For instance you might want all your functions to return a status indicating success or failure, in which case the return value will not be available for your pointer.
case 3
void alloc_a_buffer (int size, void ** buffer)
{
*buffer = malloc (size); // block reference set through 2nd parameter
}
void * new_buffer;
alloc_a_buffer (10, &new_buffer); // pass pointer address to the function
// ...
free (new_buffer);
Related
So i want to return an array of a size n (variable) which my function has as input. I know that in order to return arrays in C I have to define them static, but the problem is that n is a variable and thus I get an error. I thought of actually using malloc/calloc but then I won't be able to free them after the function returns the array. Please take note that I'm not allowed to change anything on main(). Are there any other alternatives which I could use? Thanks in advance.
float *Arr( int *a , int n ){
static float b[ n ];
return b
}
Got to point out that the function will only be called Once,I saw the solution you posted but i noticed you aren't freeing the allocated memory,is it not of much importance when the malloc is called inside a function?
The important thing to notice here is that this syntax:
float arr[n];
Allocates an array on the stack of the current function. In other words, that array is a local variable. Any local variable becomes invalid after the function returns, and therefore returning the array directly is undefined behavior. It will most likely cause a crash when trying to access the array from outside the function, if not anything worse.
In addition to that, declaring a variable-length array as static is invalid in any case.
If you want to write a function which creates and returns any kind of array (dynamically sized or not), the only option you have is to use dynamic allocation through malloc() and then return a pointer to the array (technically there's also alloca() to make dynamic stack allocations, but I would avoid it as it can easily break your program if the allocation is too large).
Here's an example of correct code:
float *create_array(size_t n_elements){
float *arr = malloc(sizeof(float) * n_elements);
if (arr == NULL) {
// Memory could not be allocated, handle the error appropriately.
}
return arr;
}
In this case, malloc() is reserving memory outside of the local stack of the function, in the heap. The result is a pointer that can be freely returned and passed around without any problem, since that area of memory keeps being valid after the function returns (until it is released). When you're done working with the data, you can release the allocated memory by calling free():
float *arr = create_array(100);
// ...
free(arr);
If you don't have a way to release the memory through free() after using malloc(), that's a problem in the long run, but in general, it is not a strict requirement: if your array is always needed, from its creation until the exit of the program, then there's no need to explicitly free() it, since memory is automatically released when the program terminates.
If your function needs to be called more than once or needs to create significantly sized arrays that are only useful in part of the program and should therefore be discarded when no longer in use, then I'm afraid there's no good way of doing it. You should use free() in that case.
To answer your question precisely:
Please take note that I'm not allowed to change anything on main(). Are there any other alternatives which I could use?
No, there are no other better alternatives. The only correct approach here is to dynamically allocate the array through malloc(). The fact that you cannot free it afterwards is a different kind of problem.
So i want to return an array of a size n(variable) which my function
has as input,
You can't, because C functions cannot return arrays at all. They can, and some do, return pointers, however, as your function is declared to do. Such a pointer may point to an element of an array.
i know that in order to return arrays in c i have to
define them static,
As long as I am being pedantic, the problem is to do with the lifetime of the object to which the returned pointer points. If it is an element of an automatically-allocated array, then it, along with the rest of the array, ceases to exist when the function returns. The caller must not try to dereference such a pointer.
The two other alternatives are
static allocation, which you get by declaring the variable static or by declaring it at file scope, and
dynamic allocation, which you get by reserving memory via malloc(), calloc(), or a related function.
Statically allocated objects exist for the entire lifetime of the program, and dynamically allocated ones exist until deallocated.
but problem is that n is a variable and thus i get
an error.
Yes, because variable-length arrays must be automatically allocated. Static objects exist for the whole run of the program, so the compiler needs to reserve space for them at compile time.
I thought of actually using malloc/calloc but then i won't be
able to free them after the function returns the array.
That's correct, but dynamic allocation is still probably the best solution. It is not unreasonable for a called function to return a pointer to an allocated object, thus putting the responsibility on its caller to free that object. Ordinarily, that would be a well-documented characteristic of the function, so that its callers know that such responsibility comes with calling the function.
Moreover, although it's a bit untidy, if your function is to be called only once then it may be acceptable to just allow the program to terminate without freeing the array. The host operating system can generally be relied upon to clean up the mess.
Please take
note that im not allowed to change anything on main(),are there any
other alternatives which i could use?
If you have or can impose a bound on the maximum value of n then you can declare a static array of that maximum size or longer, and return a pointer to that. The caller is receiving a pointer, remember, not an array, so it can't tell how long the pointed-to array actually is. All it knows is that the function promises n accessible elements.
Note well that there is a crucial difference between the dynamic allocation and static allocation alternatives: in the latter case, the function returns a pointer to the same array on every call. This is not inherently wrong, but it can be problematic. If implemented, it is a characteristic of the function that should be both intentional and well-documented.
If want an array of n floats where n is dynamic, you can either create a
variadic-length array (VLA):
void some_function(...)
{
//...
float b[ n ]; //allocate b on the stack
//...
}
in which case there would be no function call for the allocation, or you can allocate it dynamically, e.g., with malloc or calloc, and then free it after you're done with it.
float *b = malloc(sizeof(*b)*n);
A dynamic (malloc/calloc) allocation may be wrapped in a function that returns a pointer to the allocated memory (the wrapper may do some initializations on the allocated memory after the memory has been successfully allocated). A VLA allocation may not, because a VLA ends its lifetime at the end of its nearest enclosing block (C11 Standard - 6.2.4 Storage durations of objects(p7)).
If you do end up wrapping a malloc/calloc call in a "constructor" function like your float *Arr(void), then you obviously should not free the to-be-returned allocated memory inside Arr–Arr's caller would be responsible for freeing the result (unless it passed the responsibility over to some other part of the program):
float *Arr( int n, ...
/*some params to maybe initialize the array with ?*/ )
{
float *r; if (!(r=malloc(sizeof(*r)*n)) return NULL;
//...
//do some initializations on r
//...
return r; //the caller should free it
}
you could use malloc to reserve memory for your n sized array
Like this:
#include <stdlib.h>
#include <stdio.h>
float * arr(int * a, int n ) {
float *fp = malloc ( (size_t) sizeof(float)*n);
if (!fp) printf("Oh no! Run out of memory\n");
return fp;
}
int main () {
int i;
float * fpp = arr(&i,200);
printf("the float array is located at %p in memory\n", fpp);
return(0);
}
It seems like what you want to do is:
have a function that provides (space for) an array with a variable number of elements,
that the caller is not responsible for freeing,
that there only needs to be one instance of at a time.
In this case, instead of attempting to define a static array, you can use a static pointer to manage memory allocated and freed with realloc as needed to adjust the size, as shown in the code below. This will leave one instance in existence at all times after the first call, but so would a static array.
This might not be a good design (it depends on circumstances not stated in the question), but it seems to match what was requested.
#include <stdio.h>
#include <stdlib.h>
float *Arr(int *a , int n)
{
// Keep a static pointer to memory, with no memory allocated initially.
static float *b = NULL;
/* When we want n elements, use realloc to release the old memory, if any,
and allocate new memory.
*/
float *t = realloc(b, n * sizeof *t);
// Fail if the memory allocation failed.
if (!t)
{
fprintf(stderr, "Error, failed to allocate memory in Arr.\n");
exit(EXIT_FAILURE);
}
// Return the new memory.
return b;
}
I found some questions similar to this but there are some differences.
here is my code:
student.h:
#define NUM_GRADES 5
#define NAME_LENGTH 21
#define ADDRESS_LENGTH 21
typedef struct
{
char name[NAME_LENGTH]; //name of a student - up to 20 chars.
char add[ADDRESS_LENGTH]; //address - up to 20 chars.
int grades[NUM_GRADES]; //stores the grades of a student.
}student;
//the current size of the students array.
extern int currentTotal;
//add a new student space, return 0 if failed, 1 if succeeded.
int addStudent(student **studentClass);
student.c:
int addStudent(student **studentClass)
{
//adds the count for the new student.
currentTotal++;
//a temporary pointer to hold studentClass array in case realloc fails.
student *temp=NULL;
//reallocating space for the new student.
if (!(temp = (student*)realloc(*studentClass, currentTotal * sizeof(student))))
{
printf("Not enough memory.\n");
free(*studentClass);//free the original array.
currentTotal = 0;
return 0;
}
*studentClass = temp;//point class to the newly allocated space.
printf("Added space for a student.\n");
return 1;
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "student.h"
void main()
{
student *studentClass=NULL;
....
if(addStudent(&studentClass)
....
currentTotal is an external int variable.
Is the use of realloc correct?
And the use of free?
I always mix up whether I should use * or ** inside the function, once I send the address of a pointer to another function. (i.e. having a pointer like *studentClass and then sending &studentClass to another function).
if this is indeed correct then what happens to the original data that *studentClass pointed before the line
"*studentClass = temp;" (in student.c) ?
does it need to be freed?
edit:
Please don't be confused that initially *studentClass is NULL, it's only like that at the start, addStudent() is meant to be called in a loop, so after the first time, *studentClass is no longer NULL. addStudent() increase the size of *studentClass after each call.
Thanks.
It's "save" in the sense that it does not introduce undefined behaviour and it does not leak memory. You take care that if realloc fails, the original data is not freed (so you do it), and you store the result of realloc in a temp variable in order not to loose the pointer to the original data. So far everything is OK.
It contains, however, a pitfall for the caller of addStudent if realloc fails. In this case, you free the original memory block without providing a new one, but you do not reset the pointer to NULL. So the variable passed to addStudent still points to some memory, but this memory has been freed. A caller might attempt to free this memory a second time (yielding undefined behaviour then).
In case of realloc having failed, I'd suggest to do either of two options depending on who shall be responsible for freeing student's array memory:
a. addStudent is responsible: Free the original memory AND set the pointer to NULL, such that no one outside can attempt to free memory twice. So you'd add a *studentClass=NULL after the free.
b. the caller is responsible: Don't free original memory in case of realloc failure; return - as you do - a failure code and let the caller do the rest. So you'd remove the free.
This is all fine. Because *studentClass is NULL, realloc(3) behaves just like malloc(3). In the case that realloc(3) fails, it does not modify the passed pointer, meaning that *studentClass is still NULL. Calling free(3) on a NULL pointer is perfectly valid, but nothing will happen (a no-op). Then the function returns, and *studentClass is still NULL. You just need to check its value after the call to addStudent: if it's NULL the addition of a student failed, otherwise it succeeded.
Your use of double-pointers is also valid. One way to reason about this is like so. Pointers allow modification of the data at the pointed-to location. If one wants to pass an integer to a function to be modified, one can pass it as an int*. Inside the function, one dereferences it to modify it, such as *my_int = 0;. So if one wants to modify a student* inside a function, it must be passed as a student** and then dereferenced whenever one wants to change its contents.
In addition to the fact mentioned by Stephan Lechner that code should either leave the allocation alone or null out the pointer to it (as opposed to freeing the memory without nulling out the pointer) there are a couple of other issues I see:
If a caller isn't expected to recover from out-of-memory conditions, allocation functions shouldn't return when they occur. Instead they should signal the fault (perhaps by raising a signal) and then exit (if signalling the fault didn't already force an exit). Having a function guarantee that it will never return unsuccessfully can greatly simplify client code.
If the function is going to use a global variable to hold the size of the allocation, it should use a global pointer to the allocation. If it is going to use an object-pointer identified by a passed-in address, it should use an object count that is also identified by a passed-in address.
I can see four good approaches to fixing that second issue:
Pass in a double-indirect pointer as you do now, but also pass a pointer to an integer-type object holding the number of students.
Pass in a pointer to a structure which holds a student pointer and the number of students.
Define a structure which holds a count and a flexible array member of the student type, and keep a pointer to that rather than to the first student.
As above, but keep a pointer to the first student (as opposed to the start of the allocated region). This would require that any code that uses malloc/realloc/free be adjusted to offset the pointers exchanged with such functions.
Approaches #3 and #4 could have a slight advantage if the number of students can grow instead of shrink. If the size of the allocated region shrinks to zero, there would be no way to determine whether a request to realloc a region's size to zero bytes succeeds (if the region previously had a zero size, the Standard would allow realloc(prevPtr,0) to return null after having successfully released the previous allocation, but the Standard would also allow the realloc to fail (and return null) without having released the previous allocation.
I don't understand why this first version of my code is working and the second isn't.
First version :
#include <stdio.h>
#include <stdlib.h>
void procedure(int *t){
t = (int*)realloc(t, 4*sizeof(int));
t[3] = 4;
}
int main()
{
int *var;
var = (int*)malloc(sizeof(int));
procedure(var);
printf("%d\n\n", var[3]);
}
Second version:
#include <stdio.h>
#include <stdlib.h>
void procedure(int *t){
t = (int*)malloc(4*sizeof(int));
t[3] = 4;
}
int main()
{
int *var = NULL;
procedure(var);
printf("%d\n\n", var[3]);
}
In the second version, var is still a NULL pointer after the procedure execution. Why?
In the second version of your code, you are simply passing the address var points to. In procedure(...), you have, in essence, declared an int-pointer and on the first line (the malloc line), you are assigning that pointer a value. var is not updated with this value, because var is a separate entity entirely.
Essentially, you might as well be doing the following:
int *var = NULL;
int *t = malloc(4*sizeof(int));
t[3]=4;
printf("%d\n\n", var[3]);
var is never reassigned to anything, so var will always be null.
This can be corrected, though, like so:
#include <stdio.h>
#include <stdlib.h>
void procedure(int **t){
*t = malloc(4*sizeof(int));
(*t)[3] = 4;
}
int main()
{
int *var = NULL;
procedure(&var);
printf("%d\n\n", var[3]);
}
You can view this working at: https://ideone.com/aTY9Ok
EDIT: Also, it is worth noting that you should be doing the same thing in your first version because realloc(...) might return a different address than var which could lead to a memory leak.
You should remember that everything in C is passed by value, even pointers. So let's start with the second example.
You set var in main to NULL. Then you copy the address in it (NULL) to the varaible t in procedure. You proceed to malloc memory and assign that address to t. But t is just a copy of var, and any change to t is not reflected in var. Outside of procedure, the pointer retains the NULL address and the call to printf with var[3] is undefined behavior.
The second case features the same symptoms, but with a twist. realloc doesn't have to return a different address. It's memory allocator aware, so if it can just "extend" the block of memory being pointed to, it will. That's what you see happening. The call to realloc extends the memory and returns the same address it was given. So by sheer coincidence, t and var end up pointing to the same location, still.
That's why the modification to t[3] is visible using var[3]. This is not a behavior you can rely on.
Let's take it step by step here.
int *t means the "address of t", meaning that it is simply a number
Passing any number into a function means you are COPYING that data into that function (NOT LINKING IT)
Which means that number can change inside the function, but not outside (because it is a copy)
Even though t is a pointer, that pointer is still a number... setting equal to something else (ie. t = (int*)malloc(4*sizeof(int));) does not mean the value of var changed. (Because again, t is a copy of var)
If to read the description of the function realloc in the C Standard then you will know that
Returns 4
The realloc function returns a pointer to the new object
(which may have the same value as a pointer to the old object), or
a null pointer if the new object could not be allocated.
So in the first case it occured such a way that the value of the pointer was not changed. Though to rely on this results in undefined behavior.
In the second case when the standard function malloc was used the new extent with a different address was allocated. So the original pointer does not points to the new extent of memory because it was passed to the function by value.
Thus in the both cases the original pointer was not changed. The difference is that in the first case the system can just enlarge the memory extent keeping its original address unchanged while in the second case the system allocates a new extent with a different address.
I pass a pointer of a given type to a function.
In the function I allocate the memory needed:
Pointer = (mytype * ) malloc (N* sizeof (mytype));
And it all goes well. After the function ends another one calls pointer.
But the previously filled pointer is now without memory.
Shouldn't pointer have kept its filled memory?
Or does the ending of a function deallocate the memory?
Sorry but I am unable to paste my code because I work on a non connected PC.
No. Memory allocated by malloc is not deallocated at the end of a function.
Otherwise, that would be a disaster, because you would be unable to write a function that creates a data structure by allocating memory for it, filling it with data, and returning it to the caller.
No, but you're not returning the pointer to the caller. The argument inside the function is not the same as the value at the calling site, so changing it by assigning the return value from malloc() doesn't change the caller's value.
This:
Foo *foo;
AllocateAFoo(foo);
has no chance of changing the value of foo after the function returns, even if the argument is assigned to inside the function. This is why malloc() returns the new value.
You need to do that also:
mytype * Allocate(size_t num)
{
return malloc(num * sizeof (mytype));
}
This means that there's no point in sending the uninitialized pointer from the caller to the function, so don't.
Also, you shouldn't cast the return value of malloc() in C.
Also, you need to be aware that malloc() is just a function like any other. How would you write a function that reacts when execution leaves other functions? The answer is of course "you can't", and thus malloc() can't either.
You can use alloca(), but that's not supported on all architectures.
Consider the c code:
void mycode() {
MyType* p = malloc(sizeof(MyType));
/* set the values for p and do some stuff with it */
cleanup(p);
}
void cleanup(MyType* pointer) {
free(pointer);
pointer = NULL;
}
Am I wrong in thinking that after cleanup(p); is called, the contents of p should now be NULL? Will cleanup(MyType* pointer) properly free the memory allocation?
I am coding my college assignment and finding that the debugger is still showing the pointer to have a memory address instead of 0x0 (or NULL) as I expect.
I am finding the memory management in C to be very complicated (I hope that's not just me). can any shed some light onto what's happening?
Yes that will free the memory correctly.
pointer inside the cleanup function is a local variable; a copy of the value passed in stored locally for just that function.
This might add to your confusion, but you can adjust the value of the variable p (which is local to the mycode method) from inside the cleanup method like so:
void cleanup(MyType** pointer) {
free(*pointer);
*pointer = NULL;
}
In this case, pointer stores the address of the pointer. By dereferencing that, you can change the value stored at that address. And you would call the cleanup method like so:
cleanup(&p);
(That is, you want to pass the address of the pointer, not a copy of its value.)
I will note that it is usually good practice to deal with allocation and deallocation on the same logical 'level' of the software - i.e. don't make it the callers responsibility to allocate memory and then free it inside functions. Keep it consistent and on the same level.
cleanup will properly free p, but it won't change its value. C is a pass-by-value language, so you can't change the caller's variable from the called function. If you want to set p from cleanup, you'll need to do something like:
void cleanup(MyType **pointer) {
free(*pointer);
*pointer = NULL;
}
And call it like:
cleanup(&p);
Your code is a little bit un-idiomatic, can you explain a bit better why you want to write this cleanup function?
Yes
Yes
Yes: There is a block of memory magically produced by malloc(3). You have assigned the address of this memory, but not the memory itself in any meaningful way, to the pointer p which is an auto variable in mycode().
Then, you pass p to cleanup(), by value, which will copy the pointer and, using the copy local to cleanup(), free the block. cleanup() then sets it's own instance of the pointer to NULL, but this is useless. Once the function is complete the parameter pointer ceases to exist.
Back in mycode(), you still have pointer p holding an address, but the block is now on the free list and not terribly useful for storage until allocated again.
You may notice that you can even still store to and read back from *p, but various amounts of downstream lossage will occur, as this block of memory now belongs to the library and you may corrupt its data structures or the data of a future owner of a malloc() block.
Carefully reading about C can give you an abstract idea of variable lifetime, but it's far easier to visualize the near-universal (for compiled languages, anyway) implementation of parameter passing and local variable allocation as stack operations. It helps to take an assembly course before the C course.
This won't work as the pointer in cleanup() is local, and thus assigning it NULL is not seen by the calling function. There are two common ways of solving this.
Instead of sending cleanup the pointer, send it a pointer to the pointer. Thus change cleanup() as follows:
void cleanup(MyType** pointer)
{
free(*pointer);
*pointer = NULL;
}
and then just call cleanup(&p).
A second option which is quite common is to use a #define macro that frees the memory and cleans the pointer.
If you are using C++ then there is a third way by defining cleanup() as:
void cleanup(MyType& *pointer)
{
// your old code stays the same
}
There are two questions are here:
Am I wrong in thinking that after
cleanup(p); is called, the contents of
p should now be NULL?
Yes, this is wrong. After calling free the memory pointed by the pointer is deallocated. That doesn't mean that the content pointed by the pointer is set to NULL. Also, if you are expecting the pointer p to become NULL in mycode it doesn't happen because you are passing copy of p to cleanup. If you want p to be NULL in mycode, then you need a pointer to pointer in cleanup, i.e. the cleanup signature would be cleanup(MyType**).
Second question:
Will cleanup(MyType* pointer) properly
free the memory allocation?
Yes, since you are doing free on a pointer returned by malloc the memory will be freed.
It's not just you.
cleanup() will properly clean up your allocation, but will not set the pointer to NULL (which should IMHO be regarded as separate from cleanup.) The data the pointer points to is passed to cleanup() by pointer, and is free()ed properly, but the pointer itself is passed by value, so when you set it to NULL you're only affecting the cleanup() function's local copy of the pointer, not the original pointer.
There are three ways around this:
Use a pointer to a pointer.
void cleanup(struct MyType **p) { free(*p); *p = NULL; }
Use a macro.
#define cleanup(p) do { free(p); p = NULL; } while(0)
or (probably better):
void cleanup_func(struct MyType *p) { /* more complicated cleanup */ }
#define cleanup(p) do { cleanup_func(p); p = NULL; } while(0)
Leave the responsibility of setting pointers to NULL to the caller. This can avoid unnecessary assignments and code clutter or breakage.