Reputation: 12195
I have some code in a couple of different functions that looks something like this:
void someFunction (int *data) {
data = (int *) malloc (sizeof (data));
}
void useData (int *data) {
printf ("%p", data);
}
int main () {
int *data = NULL;
someFunction (data);
useData (data);
return 0;
}
someFunction ()
and useData ()
are defined in separate modules (*.c files).
The problem is that, while malloc works fine, and the allocated memory is usable in someFunction
, the same memory is not available once the function has returned.
An example run of the program can be seen here, with output showing the various memory addresses.
Can someone please explain to me what I am doing wrong here, and how I can get this code to work?
EDIT: So it seems like I need to use double pointers to do this - how would I go about doing the same thing when I actually need to use double pointers? So e.g. data is
int **data = NULL; //used for 2D array
Do I then need to use triple pointers in function calls?
Upvotes: 41
Views: 68289
Reputation: 24140
You want to use a pointer-to-pointer:
void someFunction (int **data) {
*data = malloc (sizeof (int));
}
void useData (int *data) {
printf ("%p", data);
}
int main () {
int *data = NULL;
someFunction (&data);
useData (data);
free(data);
return 0;
}
Why? Well, you want to change your pointer data
in the main function. In C, if you want to change something that's passed in as a parameter (and have that change show up in the caller's version), you have to pass in a pointer to whatever you want to change. In this case, that "something you want to change" is a pointer -- so to be able to change that pointer, you have to use a pointer-to-pointer...
Note that on top of your main problem, there was another bug in the code: sizeof(data)
gives you the number of bytes required to store the pointer (4 bytes on a 32-bit OS or 8 bytes on a 64-bit OS), whereas you really want the number of bytes required to store what the pointer points to (an int
, i.e. 4 bytes on most OSes). Because typically sizeof(int *)>=sizeof(int)
, this probably wouldn't have caused a problem, but it's something to be aware of. I've corrected this in the code above.
Here are some useful questions on pointers-to-pointers:
How do pointer to pointers work in C?
Uses for multiple levels of pointer dereferences?
Upvotes: 82
Reputation: 9
For simplicity, let me call the above single pointer parameter p and the double pointer pp (pointing to p).
In a function, the object that p points to can be changed and the change goes out of the function. However, if p itself is changed, the change does not leave the function.
Unfortunately, malloc by its own nature, typically changes p. That is why the original code does not work. The correction (58) uses the pointer pp pointing to p. in the corrected function, p is changed but pp is not. Thus it worked.
Upvotes: 1
Reputation: 2951
Rather than using double pointer we can just allocate a new pointer and just return it, no need to pass double pointer because it is not used anywhere in the function.
Return void *
so can be used for any type of allocation.
void *someFunction (size_t size) {
return malloc (size);
}
and use it as:
int *data = someFunction (sizeof(int));
Upvotes: 1
Reputation: 845
A common pitfall especially if you moved form Java to C/C++
Remember when you passing a pointer, it's pass by value i.e the value of the pointer is copied. It's good for making changes to data pointed by the pointer but any changes to the pointer itself is just local since it a copy!!
The trick is to use pass the pointer by reference since you wanna change it i.e malloc it etc.
**pointer --> will scare a noobie C programmer ;)
Upvotes: 12
Reputation: 123448
Here's the general pattern for allocating memory in a function and returning the pointer via parameter:
void myAllocator (T **p, size_t count)
{
*p = malloc(sizeof **p * count);
}
...
void foo(void)
{
T *p = NULL;
myAllocator(&p, 100);
...
}
Another method is to make the pointer the function's return value (my preferred method):
T *myAllocator (size_t count)
{
T *p = malloc(sizeof *p * count);
return p;
}
...
void foo(void)
{
T *p = myAllocator(100);
...
}
Some notes on memory management:
sizeof *p
instead of sizeof (T)
); this will save you some heartburn if the data type has to change (say from int to long or float to double). It also makes the code read a little better IMO.Upvotes: 2
Reputation: 2301
Replying to your additional question you edited in:
'*' denotes a pointer to something. So '**' would be a pointer to a pointer to something, '***' a pointer to a pointer to a pointer to something, etc.
The usual interpretation of 'int **data' (if data is not a function parameter) would be a pointer to list of int arrays (e.g. 'int a [100][100]').
So you'd need to first allocate your int arrays (I am using a direct call to malloc() for the sake of simplicity):
data = (int**) malloc(arrayCount); //allocate a list of int pointers
for (int i = 0; i < arrayCount; i++) //assign a list of ints to each int pointer
data [i] = (int*) malloc(arrayElemCount);
Upvotes: 1
Reputation: 7608
You have to pass a pointer to the pointer if you want to modify the pointer.
ie. :
void someFunction (int **data) {
*data = malloc (sizeof (int)*ARRAY_SIZE);
}
edit : Added ARRAY_SIZE, at some point you have to know how many integers you want to allocate.
Upvotes: 6
Reputation: 627
Here you are trying to modifying the pointer i.e. from "data == Null" to "data == 0xabcd"some other memory you allocated. So to modify data that you need pass the address of data i.e. &data.
void someFunction (int **data) {
*data = (int *) malloc (sizeof (int));
}
Upvotes: 1
Reputation: 15925
Apart from using the doublepointer technique, if there's only 1 return param needed rewrite is as following:
int *someFunction () {
return (int *) malloc (sizeof (int *));
}
and use it:
int *data = someFunction ();
Upvotes: 3
Reputation: 73443
someFunction() takes its parameter as int*. So when you call it from main(), a copy of the value you passed created. Whatever you are modifying inside the function is this copy and hence the changes will not be reflected outside. As others suggested, you can use int** to get the changes reflected in data. Otherway of doing it is to return int* from someFunction().
Upvotes: 3
Reputation: 35450
That is because pointer data is passed by value to someFunction
.
int *data = NULL;
//data is passed by value here.
someFunction (data);
//the memory allocated inside someFunction is not available.
Pointer to pointer or return the allocated pointer would solve the problem.
void someFunction (int **data) {
*data = (int *) malloc (sizeof (data));
}
int* someFunction (int *data) {
data = (int *) malloc (sizeof (data));
return data;
}
Upvotes: 3