I am wondering if dynamically allocated memory with malloc global? I am reading online that allocated memory with malloc is stored on the heap. I also read online that all global variables are stored on the heap. Wouldn't this mean that dynamically allocated memory can be accessed globally? For example, I receive an error with the following code:
#include <stdio.h>
#include <stdlib.h>
void my_func(void)
{
printf("Pointer variables is: %d\n", *ptr);
}
int main()
{
int *ptr = (int *)malloc(sizeof(int));
*ptr = 5;
my_func();
return 0;
}
However, when i run the following code with a global variable there is no error:
#include <stdio.h>
int var = 5;
void my_func(void)
{
printf("Global variable is: %d\n", var);
}
int main()
{
my_func();
return 0;
}
CodePudding user response:
You can access the memory created by malloc
anywhere as long as you don't free
it. I think that is your meaning of global.
But the ptr
is a local variable of pointer type, points to the memory allocated. You have to pass it as a parameter of the function to use it.
They are two different concepts.
CodePudding user response:
First, C has no global scope. “Global” means a name (an identifier) can be defined once and will be known throughout the program. In C, for a name to be known in multiple translation units, you must declare it in each translation unit where it is to be known (and define it in one of them) and link the translated files together.
Second, it would only make sense to speak of names as global or as having linkage (the property about linking different declarations of a name to the same object or function) or scope (where in a program a name is visible, meaning able to be used). Memory does not have scope or linkage. It might be said to be global in the sense it is accessible throughout the entire program, but “global” is not the right word for this since that is about visibility of names.
Third, “on the heap” is slang and should be avoided. Memory is dynamically allocated. (The C standard uses just “allocated,” but “dynamically allocated” is more explicit and is clearer in other contexts.) This slang arose because early memory management software would keep records about free blocks of memory in a heap data structure. When memory was allocated, if it could be satisfied by an existing free block, that block would be removed from the heap and given to the calling routine for its use. So allocated memory is actually taken off the heap; it is not on the heap. And modern memory managers may use diverse data structures to hold their records, either with or without heaps.
The typical memory model for a program is that all of its memory is accessible throughout the program. When memory is reserved for some use, whether by malloc
or by other means, that memory may be used by any software in the program that has the address of that memory. Some memory is limited in how it may be used. For example, some may hold initialized data and be marked read-only, so that it cannot be modified. Other memory may hold program instructions and be marked as executable, so it can be executed (by a jump instruction or other instruction that transfers program control to that memory), whereas other memory in the program cannot be executed. However, these limitations generally apply to all software seeking to access memory in one way or another, unless special provisions are made (such as by calling operating system routines to change the protections).
In your program, ptr
is not declared before my_func
. Because of this, it is not visible inside my_func
. This means the name ptr
is not usable. It has nothing to do with the memory that ptr
points to. To make the name ptr
visible inside my_func
, you must declare it prior to using it. One way to do this would be to declare an external variable (here, “external” means outside of any function):
int *ptr; // External declaration (and tentative definition).
void my_func(void)
{
printf("Pointer variables is: %d\n", *ptr);
}
int main()
{
ptr = malloc(sizeof *ptr); // Changed from declaration to assignment.
*ptr = 5;
my_func();
return 0;
}
Another way is to declare it as a function parameter: void my_func(int *ptr) { printf("Pointer variables is: %d\n", *ptr); }
int main() { int *ptr = malloc(sizeof *ptr); *ptr = 5; my_func(ptr); return 0; }
In this case, `void my_func(int *ptr)` declares a **different** `ptr` from the one in `main`. There are two variables named `ptr` in this program, and they are not linked together. The one in `main` is given a value in `main`. Then the call `my_func(ptr)` passes the value of this `ptr` to `my_func`. When `my_func` starts executing, a new variable named `ptr` is created and is given the value passed as the argument.
Bonus: I changed `(int *)malloc(sizeof(int));` to `malloc(sizeof *ptr);`. In C, unlike C , it is not necessary to cast the result of `malloc`, and it is recommended not to because doing so can conceal the error of failing to use `#include <stdlib.h>`. Also, `malloc(sizeof *ptr)` says to allocate space for one of whatever type `ptr` points to. With `malloc(sizeof(int))`, an error can occur if somebody changes the type of `ptr` but forgets to find all places that type is used with `ptr` and change them too. With `malloc(sizeof *ptr)`, appropriate space will be allocated even if the type of `ptr` is changed with no other edits.