C Memory allocation area
Program code Area
binary code that holds the function body
Global Data area
the storage of global variables and static variables is put together. Initialized global and static variables are in one area, uninitialized global variables and uninitialized static variables are adjacent to another area. Constant data is stored in another area. The data is released by the system after the program is finished. What we call the BSS (BSS segment) is usually a memory area used to store uninitialized global variables in a program. BSS is the abbreviation of English block started by symbol
Stack area
The compiler automatically assigns the release, holds the function's parameter value, the local variable value and so on. It works like a stack in a data structure
Heap Area
typically released by the programmer, if the programmer does not release, the program may end up being reclaimed by the OS
Command line argument area
value of the command line arguments and environment variables stored
Example
#include <stdio.h>
int a = 0;//static storage (initialization zone)
char *p1;//static storage (uninitialized zone)
void example ()
{
int b; Stack area
char s[] = "abc";//Stack area
char *p2;//stack area
static int b = 0;//static storage (initialization area)
//Allocated 10 and 20 bytes of area on heap
P1 = (char *) malloc (a);
P2 = (char *) malloc (+);
}
Icon
Attention
There are two types of memory in the embedded system, ROM and RAM, the program is solidified into ROM, the variables and stacks are set in RAM, and the constants defined by const are also put into ROM
Using const to define constants can save space and avoid unnecessary memory allocations
variable
What are local variables, global variables, and static variables?
As the name suggests, the local variable is in a limited range of variables, the scope is limited, for the program, in a function of the internal declaration of ordinary variables are local variables, local variables will be on the stack application space, after the function, the application space will be automatically released. The global variable, which is applied outside the function, is stored on the global (static area), knowing that the program ends before it is finished, so that its scope is the entire program. Static variables and global variables are stored the same way that the function body is declared static to make this variable work like a global variable, without worrying about the end of the function and being freed.
Related functions:
void *malloc (size_t size);
void free (void *p);
/* Generally such use
Struct elem *p;
p = (struct elem*) malloc (sizeof (struct elem))
void Free (P)
* *
malloc principle
The substance of the malloc function now, it has a so-called idle list that connects the available chunks of memory to a long listing. When the malloc function is invoked, it looks for a block of memory that is large enough to meet the user's request in the join table. The memory block is then split in half (the size of the piece is equal to the size of the user request, and the other is the remaining byte). Next, the memory assigned to the user is passed to the user, and the remaining piece, if any, is returned to the connection table. When the free function is invoked, it connects the memory blocks freed by the user to the idle chain. In the end, the free chain will be cut into a lot of small memory fragments, if the user requests a large memory fragment, then the idle chain may not be able to meet the user requirements of the fragment. As a result, the MALLOC function requests a delay and begins to rummage through the free chain to check each memory fragment, organize them, and merge the adjacent small free blocks into larger chunks of memory. If the required memory block is not available, the malloc function returns a null pointer, so be sure to make a return value when invoking the malloc dynamic request memory block.
Main points of use of malloc
The prototype of the function malloc is as follows:
void * malloc (size_t size);
Example
Use malloc to request an integer-type memory of length, as follows:
int *p = (int *) malloc (sizeof (int) * length);
Attention
The type of the malloc return value is void *, so the type conversion is explicitly done when the malloc is invoked, and the void* is converted to the desired pointer type
The malloc function itself does not recognize what type of memory is being requested, it only cares about the total number of bytes in memory. We usually don't remember the exact number of bytes of data types such as int,float in different platforms, so using sizeof in malloc is a good style.
Direct handling of the code, indeed very good!! Easy to understand
main.cpp
int a = 0;//global Initialization Zone
char *P1//Global uninitialized Zone
main ()
{
int b;//Stack
char s[] = "abc";//Stack
C Har *p2; Stack
char *p3 = "123456";//123456\\0 in the constant area, p3 on the stack. The
static int c =0;//Global (static) initialization area
P1 = (char *) malloc (a);
P2 = (char *) malloc (20);//the area with 10 and 20 bytes allocated is in the heap area.
strcpy (P1, "123456");//123456\\0 in a constant area, the compiler might optimize it to a place with the "123456" that P3 points to.
}
In addition, there are realloc (reallocation memory), Calloc (initialized to 0), Alloca (application memory on the stack, automatic release) and so on.
Specification type of memory
General Class (conventional Memory)
the General class occupies the first position in the memory allocation table, from 0KB to 640KB (address 000000H ~ 109FFFFH), and consumes a total of 640KB capacity. Because it is in front of the memory and in the Dos manageable memory area, we also call it low DOS Memory (lower DOS memory), or called basic memory (base Memory), the program that uses this space has bios,dos operating system, peripheral device driver, interrupt vector table, Some resident programs, free and available memory space, and general application software can be implemented in this space
High memory (Upper Memory)
high-level memory is a layer of memory above conventional memory (640KB ~ 1024KB)
High-end memory areas (Memory area)
It is 64KB memory between 1024KB and 1088KB
Extended memory Blocks (extened Memory block)
extended memory is more than 1MB of memory space, its address is starting from 100000H, continuous upward expansion of memory, extended memory depends on the CPU's addressing capability
Memory allocation method
Common three ways of allocating
Static storage area allocation
Memory is already allocated when the program is compiled, which exists throughout the running of the program, such as global variables, static variables
Creating on the Stack
When the function is executed, the storage units of local variables within the function can be created on the stack, and the storage units are automatically freed when the function is finished. Stack memory allocation operations are placed within the processor's instruction set and are highly efficient, but the allocated memory capacity is limited
Assigning from the heap
Dynamic memory allocation, the program at run time with malloc or new application for any amount of memory, the programmer is responsible for when using free or delete to release memory. The lifetime of dynamic memory is determined by us and is very flexible to use, but the problem is the most
Common memory errors and Countermeasures
A memory error is a very troublesome thing to do. The compiler cannot automatically discover these errors, which are usually captured when the program is running. Most of these errors do not have obvious symptoms, the hidden, increase the difficulty of error.
The memory allocation was unsuccessful, but it was used
Novice programmers often make this mistake because they are unaware that memory allocations will be unsuccessful. A common workaround is to check whether the pointer is null before using memory. For example:
t = (struct btree *) malloc (sizeof (struct btree));
if (t = = NULL) {
printf ("Memory allocation failed!\n");
Exit (exit_failure);
}
The memory allocation was successful, but it was not initialized to reference it
This error is committed primarily by two causes:
- No concept of initialization
- Mistakenly think that the default initial value of memory is all 0, resulting in a reference to initial error. The default initial value of memory is not a uniform standard, so no matter how to create an array, do not forget to assign an initial value, even if the initial value of 0 can not be omitted, not too troublesome
Forgot to free memory, causing memory leak
A function that contains this error loses a piece of memory every time it is called. At the beginning, the system has enough memory that you can't see the error. A program suddenly dies, the system prompts: memory exhaustion
Dynamic memory application and release must be paired, the program malloc and free use of the same number of times must be the same, otherwise there must be a mistake
Frees up memory and continues to use it
The object invocation relationship in the program is too complex to find out whether an object has freed up memory, so the data structure should be redesigned to fundamentally solve the confusion of object management.
The reture statement of the function is incorrectly written, and be careful not to return pointer or reference to stack memory because the memory is automatically destroyed at the end of the function body
When memory is freed with free or delete, the pointer is not set to null. resulting in "wild pointer"
Rules
After you request memory with malloc or new, you should immediately check to see if the pointer is null. Prevent use of memory with pointer null
Do not forget to assign an initial value to an array and dynamic memory. Prevents uninitialized memory from being used as the right value
Avoid arrays or pointer boundaries, especially if you are "1" or "less than 1".
Dynamic memory requests and releases must be paired to prevent memory leaks
After freeing memory with free or delete, set the pointer to null immediately to prevent the "wild pointer" from being generated
comparison of pointers to arrays
in C programs, pointers and arrays can be substituted for each other in many places, giving rise to an illusion that they are equivalent
Arrays are either created in the static store (such as global arrays) or created on the stack. The array name corresponds to (instead of pointing to) a piece of memory whose address and capacity remain unchanged throughout the lifecycle, and only the contents of the array can be changed
Pointers can be pointed at any time to any type of memory block, which is characterized by "variable", so we often use pointers to manipulate dynamic memory. Pointers are far more flexible than arrays, but they are also more dangerous.
Modify Content
the capacity of the character array A is 6 characters, and its contents are hello. The contents of a can be modified, such as a[0]= ' X '. The pointer p points to the constant string "world" (in the static store, the content is world), and the contents of the constant string cannot be modified. Syntactically, the compiler does not find the statement p[0]= ' x ' wrong, but the statement attempts to modify the contents of the constant string and cause a run error
#include <stdio.h>
int main ()
{
char a[] = "Hello";
A[0] = ' x ';
printf ("%s\n", a);
Char *p = "Wrold";
P[0] = ' x ';
printf ("%s\n", p);
return 0;
}
content Replication and comparison
You cannot copy and compare the array names directly. If you want to copy the contents of array A to array B, you cannot use statement B = A, or you will generate a compilation error. The standard library function strcpy should be used for replication. Similarly, compare B and a for the same content, should be compared with the standard library function strcmp
The statement p = A does not copy the contents of a to the pointer p, but instead assigns the address of A to P. To copy the content of a, you can use the library function malloc for p to apply a strlen (a) 1 characters of memory, and then use strcpy for string copying. Similarly, the statement if (p = = a) compares not the content but the address, should use the library function strcmp to compare
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
Char a[] = "Hello";
Char b[10];
strcpy (b, a); Cannot use B = a
int len = strlen (a);
Char *p = (char *) malloc ((len + 1) * sizeof (char));
strcpy (P, a);
if (strcmp (p, a) = = 0) {
printf (p and a are equal!) \ n ");
}
Free (p);
return 0;
}
Calculate Memory capacity
you can use operator sizeof to calculate the capacity (in bytes) of the number of groups. The value of sizeof (a) is 12. Point P to point A, but sizeof (p) is 4. This is because sizeof (p) Gets the byte number of a pointer variable (32bit machine memory address is 32bit), equivalent to sizeof (char *), Rather than the amount of memory that P refers to.
Note When an array is passed as a parameter of a function, the array is automatically degraded to the same type of pointer. Regardless of the capacity of the array A, sizeof (a) is always equal to sizeof (char *)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void FunC (char *a);
int main ()
{
char a[] = "Hello";
char *p = A;
printf ("%d\n", sizeof (a)); 6 bytes
printf ("%d\n", sizeof (p));//4 bytes
FunC (a);
return 0;
}
void FunC (char *a)
{
printf ("%d\n", sizeof (a));//4 bytes Instead of 6 bytes
}
Operation Result:
How the pointer parameter passes memory
if the function's argument is a pointer, do not expect to request dynamic memory with that pointer. In the example, the statement getmemory (STR, 200) of the test function did not enable STR to obtain the desired memory, and STR is still null.
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void GetMemory (char *p, int num)
{
p = (char*) malloc (sizeof (char) * num);
}
char* getmemory (char *p, int num)
{
p = (char *) malloc (sizeof (char) * num);
return p;
}
int main ()
{
char *str = NULL;
str = getmemory (str, MB);
strcpy (str, "Hello world!"); Run error
printf ("%s", str);
Free (str);
return 0;
}
Error
Reason
The problem is in the function getmemory. The compiler always makes a temporary copy of each parameter of the function, and the copy of the pointer parameter P is _p, and the compiler causes _p = p. If the program in the body of the function modifies the contents of the _p, the contents of the parameter P are modified accordingly. This is why the pointer can be used as an output parameter. In this case, _p has applied for new memory, but has changed the memory address that _p refers to, but P has not changed at all. So the function getmemory does not output anything. In fact, a chunk of memory is leaked each time the getmemory is executed because free memory is not freed
Improved
We can use the function return value to pass the dynamic memory, this method is simpler, see example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void GetMemory (char *p, int num)
{
p = (char*) malloc (sizeof (char) * num);
}
char* getmemory (char *p, int num)
{
p = (char *) malloc (sizeof (char) * num);
return p;
}
int main ()
{
char *str = NULL;
str = getmemory (str, MB);
strcpy (str, "Hello world!"); Run error
printf ("%s\n", str);
Free (str);
return 0;
}
Attention:
Using function return value to pass dynamic memory This is a good way to use it, but it's often used incorrectly. It is emphasized here not to return a pointer to "stack memory" with the returns statement because the memory automatically dies at the end of the function.
Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void GetMemory (char *p, int num)
{
p = (char*) malloc (sizeof (char) * num);
}
char* getmemory (char *p, int num)
{
p = (char *) malloc (sizeof (char) * num);
return p;
}
char* GetArray (void)
{
char p[] = "Hello world!";
return p; The compiler raises a warning that the
int main ()
{
char *str = NULL;
str = GetArray ();
printf ("%s\n", str); Str points to spam free
(str);
return 0;
}
Eliminate "wild pointer"
"Wild Pointer" is not a null pointer, it is a pointer to "junk" memory. People generally do not use null pointers incorrectly, because it is easy to judge with an if statement. But "wild pointers" are dangerous, and if statements do not work for them. There are two main causes of the "wild pointer":
The pointer variable is not initialized. Any pointer variable that has just been created does not automatically become a null pointer, and its default value is random, and it can be scrambled. Therefore, the pointer variable should be initialized at the time it is created, either by setting the pointer to null or by pointing it to legitimate memory, for example:
char *p = NULL;
Char *str = (char *) malloc (sizeof (char) * 100);
The pointer p is not NULL after being free or delete, and it is mistaken that p is a valid pointer.
The pointer operation goes beyond the scope of the variable
what to do with memory exhaustion
If a large enough chunk of memory is not found when requesting dynamic memory, the malloc function returns a null pointer, declaring that the memory request failed. There are usually three ways to handle "memory exhaustion" issues
Determine if the pointer is null, and if so, terminate the function with the return statement immediately. For example:
char* GetPoint ()
{
char *p = malloc (sizeof (char) *);
if (p = = null) {return
null;
}
}
To determine if the pointer is null or not, use Exit (1) immediately to terminate the entire program (which I often use is also recommended):
char* GetPoint ()
{
char *p = malloc (sizeof (char) *);
if (p = = NULL) {
exit (1);
}
}
Set exception handling functions for new and malloc