Modifying a pointer in another function requires a concept called multiple indirection, I will explain it in later, spoiler solution given @geofftnz uses multiple indirection. What I am trying to do is try my best to explain multiple indirection in C.
Consider the following two programs, I will walk through the code.
The following program does not use multiple indirection, so it fails.
program with error:
// filename: noIndirection.c
#include <stdio.h>
#include <stdlib.h>
void allocater(int *ptrTempAllctr)
{
ptrTempAllctr = malloc(sizeof(int));
if (ptrTempAllctr == NULL) {
perror("in allocater() memory allocation error");
exit(EXIT_FAILURE);
}
}
int main()
{
int *ptrMain = NULL;
allocater(ptrMain);
if (ptrMain == NULL) {
printf("ptrMain is points to NULL\n");
return 1;
}
//free(ptrMain); // we don't have to free because it will be invalid free.
return 0;
}
consider the above program(noIndirection.c
), which has a variable ptrMain
it is a pointer points to an int.
If it was passed to a function, in the function scope(body) a temporary pointer variable is created because arguments of the function are temporary variables, they get deleted when they go out of scope.
The temporary pointer variable ptrTempAllctr
(which is a argument) will point to what ever the caller(main
) function's variable ptrMain
(which is pointing to NULL
) pointed when it was passed as argument to the function.
If we use malloc()
or assign another pointer to the temporary variable ptrTempAllctr
then it will point to it but the pointer variable in caller(main
) function that was passed as argument to the to function allocater()
still points to the same data(which is NULL
) which it was pointed before the function call.
When the called (allocater()
) function goes out of scope the temporary pointer variable is popped from stack and the memory left unallocated we end up memory leak.
To bypass this limitation we need use multiple indirection.
MULTIPLE INDIRECTION:
Multiple indirection when we use of pointer/s to pointer/s in varying level(with multiple `*`) eg: `int **pp, int ***ppp`, etc.
and we assign them using address-of(&
) operator.
what multiple indirection pointer type variables does is, allows us to make is
a pointer to a pointer variable itself for fixing the above program.
This allows us to pass the address of the ptrMain
to allocater()
using this call
allocater(&ptrMain);
thus the above program noIndirection.c
doesn't allow us do this, see the program withIndirection.c
to implement this multiple indirection.
We need pointer to int pointer(int **ptrMain
) as function argument for allocater()
function in this case to solve the above buggy program(noIndirection.c).
This was used in the following program.
The following program uses multiple indirection to solve the bug in previous program.
// filename: withIndirection.c
#include <stdio.h>
#include <stdlib.h>
void trueAllocater(int **ptrTrueAllocater)
{
*ptrTrueAllocater = (int *) malloc(sizeof(int));
if (ptrTrueAllocater == NULL) {
perror("in trueAllocater() memory allocation error");
exit(EXIT_FAILURE);
}
}
int main(void)
{
int *ptrMain = NULL;
trueAllocater(&ptrMain);
if (ptrMain == NULL) {
printf("memory not allocated\n");
return EXIT_FAILURE;
}
printf("memory allocated and assigned to ptrMain");
printf(" from trueAllocater\n");
free(ptrMain);
return EXIT_SUCCESS;
}
see the program withIndirection.c
for reference from now.
To solve our problem we need pass the address of the pointer variable ptrMain
(trueAllocater(&ptrMain);
) to the trueAllocater, in-order to change ptrMain
where it needs to be pointing later on in trueAllocater()
or another function,
to do this the function needs to accept indirection pointer with correct level of indirection,
which is to add another * added to the argument declaration to my current understanding for the variables that are passed.
By means we need to have the trueAllocater()
function argument as int **
from int *
in withIndirection.c
as opposed to noIndirection.c
so the indirection level will be statisfied.
When the address of the caller's argument variable ptrMain
's actual address was passed to the function. the temprary ptrTrueAllocater
argument variable in
function is pointing to the address of pointer variable ptrMain
's address in caller(main
) function not what pointer variable ptrMain
(which is NULL
in the program) points to in function(main
).
If we dereference the ptrTrueAllocater
variable the address which ptrMain
points to will be revealed because the ptrTrueAllocater
temporary variable is pointing to the caller(main
) ptrMain
variable itself not it contents.
The contents of the dereferenced ptrTrueAllocater
variable will be the address of the data which was pointed by the caller(main
)'s variable(ptrMain
),
so we have to do one additional dereference to get the final data.
so we have to dereference once to get the address of the ptrMain
which it points in-order to change the where ptrMain
needs to be pointed and dereference
twice to get the actual data pointed by the ptrMain
which is NULL
.
@PaulWicks you intented to change so you have to dereference once to allocate or change where its pointing.
The intent of multiple indirecting using pointers is to create multi-dimensional array and passing pointer arguments that need to be pointed to something.
We need to change the variable according to the types we have to manipulate like the following,
every addition of * in declaration will increase pointer indirection level
and every dereference will decrease the pointer indirection level that is will get close to data.
We can solve this problem by returning the address to the caller function assigning to the required pointer variable.
yes, we can use this multi indirection variable syntax for creating one or
multi dimensional arrays. This will confuse beginners at first, if they put time to
read lots of code they'll able to find the difference between them.
Please correct me if I am wrong, please give feedback and let me know what are
the other uses of multiple indirection pointers.
apologies for my bad english.
these are the resources helped me to understand multiple indirections.
https://boredzo.org/pointers/#function_pointers
https://cseweb.ucsd.edu/~ricko/rt_lt.rule.html