Click the card below to follow the public account and star it to get my latest shares.Reply in the background Embedded Learning Materials to get a learning package 👇👇👇
Today I saw a question raised by a user on Zhihu:

The question included a code example:
void func(int *p) {
p = malloc(sizeof(int)); // Only modifies the local copy of p
}
void allocate_memory(int **pp) {
// Modify the pointer itself
*pp = (int *)malloc(sizeof(int)); // Allocate new memory for the pointer in the main function
**pp = 123; // Write a value in the new memory
}
int main() {
int *p = NULL; // Pointer in the main function, currently pointing to nothing
allocate_memory(&p); // Pass the address of p, i.e., int**
printf("Value pointed by p: %d\n", *p); // Output 123
free(p); // Don't forget to free the memory
}
With the code, it is easy to understand the user’s confusion:
If I want to allocate memory for a pointer through a function, why do I need to pass a double pointer instead of the pointer itself?
To understand this question, we first need to clarify one point, in C language, function parameters are passed by value. This means that when you call a function and pass a variable <span>a</span> as a parameter, the system actually copies the value of variable <span>a</span> into the function’s parameter. When entering the function, although it seems that its value is the same as your variable <span>a</span>, it is actually not variable <span>a</span>, just a copy. Therefore, all operations on it are on this copy, and the original variable <span>a</span> remains unaffected!
Thus, if you pass a pointer to a function, the pointer itself is a copied value. If you want to modify the value of the variable it points to, that is not a problem, because this value is consistent with the original pointer’s value, and you can address the variable’s address through this value. However, if you want to modify the pointer itself, sorry, as mentioned above, it is just a copy, and no matter how you change it, you cannot affect the original pointer variable!
Is the above text difficult to understand? Let’s look at the diagram:

The pointer <span>p</span> points to variable <span>a</span>, so its value is the address of variable <span>a</span>. Now, when passing <span>p</span> as a parameter to function <span>func</span>, based on the principle of passing by value, the value of <span>p</span> is passed to the parameter’s value, but the parameter’s address is independent and not the address of <span>p</span>. We can modify the value of variable <span>a</span> through the dereferencing operation on the parameter value (<span>*p</span>), they are related in the diagram, but if you directly change the value of the function parameter, no matter how you change it, you are modifying the value at address <span>300</span>, while our <span>p</span> address is <span>200</span>, which will not affect it at all! Therefore, passing the pointer itself cannot modify the original pointer inside the function.
At this point, if we change the pointer to a double pointer, which is a pointer to a pointer, let’s see what happens:

It can be seen that when passing a double pointer <span>pp</span>, although the parameter address is still different from the address of <span>pp</span>, its value becomes the address of pointer <span>p</span>. At this point, we can operate on pointer <span>p</span> through <span>*pp</span>, thus achieving modification of the original pointer outside the function.
We can add print statements to the source code provided by the user to verify the correctness of the above analysis:
void allocate_memory(int **pp) {
// Modify the pointer itself
*pp = (int *)malloc(sizeof(int)); // Allocate new memory for the pointer in the main function
**pp = 123; // Write a value in the new memory
printf("Address of pp in allocate_memory: %p\n", (void *)&pp);
printf("Value of pp in allocate_memory: %p\n", (void *)pp);
}
int main() {
int *p = NULL; // Pointer in the main function, currently pointing to nothing
printf("Address of p in main: %p\n", (void *)&p);
allocate_memory(&p); // Pass the address of p, i.e., int**
printf("Value of p: %p\n", (void *)p);
printf("Value pointed by p: %d\n", *p); // Output 123
free(p); // Don't forget to free the memory
}
In the main function, print the address of <span>p</span> (the pointer to be modified), and in the sub-function, print the address and value of parameter <span>pp</span>. Compile and run, the output is as follows:
jay@jay-home:~/test$ ./test
Address of p in main: 0x7fff1b30c5f0
Address of pp in allocate_memory: 0x7fff1b30c5c8
Value of pp in allocate_memory: 0x7fff1b30c5f0
Value of p: 0x55f5c670e6b0
Value pointed by p: 123
It is clear that the address of the pointer to be modified <span>p</span> is different from the address of function parameter <span>pp</span>, but since <span>pp</span> is a pointer to <span>p</span>, i.e., a double pointer, the value of <span>pp</span> equals the address of <span>p</span>. Thus, we can access the data at the address where <span>p</span> resides (which is the value of <span>p</span>) through dereferencing <span>*pp</span> and read and modify it.
From another perspective, if you can understand that modifying the value of an external ordinary variable within a function requires passing the address of that variable, then it is not difficult to understand why modifying an external pointer requires passing a double pointer. The term “double pointer” may seem advanced and cause unnecessary confusion; we should not get hung up on this name. Its essence is simply the address of the variable we need to modify, which just happens to store the address of another variable!
In summary, since the parameter passing mechanism of C language functions is “pass by value”, any modifications to function parameters will only affect the copy and not the original variable. Therefore, if we need to modify an external variable, we need to pass its address.
In cases where we need to modify a pointer, we pass the address of the pointer (i.e., a double pointer), so that the function can access and modify the original pointer’s value through that address. This is very common in dynamic memory allocation, linked list operations, tree structure construction, and other scenarios.
Finally, to summarize in one sentence:To modify something in a sub-function, pass its address. To modify a pointer, pass the address of the pointer; this is exactly the same principle as modifying ordinary variables, except that there is a special term for pointer addresses – double pointer.
—— The End ——

Comments from netizens: MDK uses V6 compiler, but STM32CubeMX does not support generating projects for keilV6

Solution for ESP-IDF download error libusb_open() failed

Why does Linux need to mount? Can’t we access the /dev directory directly?

Review of the most common mistakes made by C language beginners

What is a callback function?