Figure C Memory Allocation
The program code area stores the binary code of the function body. The global variables and static variables in the global data area are stored together. The initialized global variables and static variables are in one area. uninitialized global variables and uninitialized static variables are in another adjacent area. Constant data is stored in another region. The data is released by the system after the program ends. The BSS segment is usually a memory area used to store uninitialized global variables in the program. BSS is short for block started by symbol. The stack zone is automatically allocated and released by the compiler, and stores the function parameter values and local variable values. The method is similar to that in the data structure where the stack heap area is usually assigned and released by the programmer. If the programmer does not release the stack heap area, when the program ends, the OS may recycle the command line parameter area and store the command line parameter and environment variable value examples.
# Include <stdio. h> int A = 0; // static storage area (initialization area) char * P1; // static storage area (uninitialized area) void example () {int B; // stack char s [] = "ABC"; // stack char * P2; // stack static int B = 0; // static storage (initialization) // The allocated 10 and 20 bytes are in the heap p1 = (char *) malloc (10); P2 = (char *) malloc (10 );}
Note:
- In the embedded system, there are two types of memory: Rom and ram. The program is solidified into Rom. the variables and stacks are located in ram, and constants defined by const are also put into Rom.
- Defining constants with const can save space and avoid unnecessary memory allocation.
Standard Type of memory conventional memory the standard class occupies the first position in the memory allocation table, from 0 kb to 640kb (Address: 000000 H ~ 109 ffffh), occupies a total of KB capacity. Because it is at the beginning of the memory and in the DOS manageable memory area, we also call it low DoS Memory (low DoS Memory) or base memory ), programs using this space include bios, DOS Operating System, drivers of peripheral devices, interrupt vector table, and some resident programs, free and available memory space and general application software can execute high memory (upper memory) in this space. High memory is a layer of memory (640kb ~ 1024kb) high-end memory area (high memory area) is a 64kb memory expansion block (extened memory block) between 1024kb and 1088kb. The extended memory is more than 1 MB of memory space, the address is the memory that is continuously expanded from H. The memory expansion depends on the memory allocation method of the CPU addressing capability.
Three common allocation methods
The static storage area is allocated when the program is compiled, and the program exists throughout the entire running period. For example, global variables and static variables are created on the stack when the function is executed, the storage units of local variables in the function can be created on the stack. When the function execution ends, these storage units are automatically released. Stack memory allocation computation is built into the processor's instruction set, which is highly efficient. However, the allocated memory capacity is limited and dynamic memory allocation is allocated from the stack, when the program runs, it uses malloc or new to apply for any amount of memory. The programmer is responsible for releasing the memory with free or delete. The lifetime of the dynamic memory is determined by us. It is very flexible to use, but the most common problems are memory errors and countermeasures. Memory Errors are very troublesome. The compiler cannot automatically detect these errors, which can be captured only when the program is running. Most of these errors do not have obvious symptoms, but they are often invisible and increase the difficulty of error correction. If the memory allocation fails, new programmers often make this mistake because they do not realize that the memory allocation will fail. A common solution is to check whether the pointer is null before using the memory. For example:
T = (struct btree *) malloc (sizeof (struct btree); If (t = NULL) {printf ("memory allocation failed! \ N "); exit (exit_failure );}
The memory is allocated successfully, but it is referenced before initialization. This error is mainly caused by two reasons:
- No initialization Concept
- If the default initial value of memory is all 0, the reference initial value is incorrect. There is no uniform standard for the default initial values of the memory. Therefore, no matter how you create an array, do not forget to assign the initial values. Even if the initial value is 0, do not bother.
Forgot to release memory, causing memory leakage
- A function containing such errors loses a piece of memory every time it is called. At the beginning, the system memory was sufficient and you could not see the error. Once a program suddenly died, the system prompts: memory is exhausted
- Dynamic Memory application and release must be paired, and the usage of malloc and free in the program must be the same, otherwise there must be errors
The memory is released but it continues to be used.
- The object calling relationship in the program is too complex, so it is difficult to figure out whether an object has released the memory. At this time, we should re-design the data structure to fundamentally solve the chaos of Object Management.
- The Reture statement of the function is written incorrectly. Do not return a "Pointer" or "Reference" pointing to "stack memory" because the function body is automatically destroyed when it ends.
- After the memory is released using free or delete, the pointer is not set to null. Resulting in "wild pointer"
Rules
- After applying for memory with malloc or new, you should immediately check whether the pointer is null. Prevent the use of memory with NULL pointer
- Do not forget to assign initial values to arrays and dynamic memory. Avoid using uninitialized memory as the right value
- Avoid overrunning the subscript of an array or pointer. Be careful when performing the "more 1" or "Less 1" operation.
- Dynamic Memory application and release must be paired to prevent memory leakage
- After the memory is released using free or delete, the pointer is immediately set to null to prevent "wild pointer"
Comparison between pointers and arrays in C Programs, pointers and arrays can be replaced in many places, which creates an illusion, an equivalent array is created either in a static storage area (such as a global array) or on a stack. The array name corresponds to (instead of pointing to) a piece of memory, and its address and capacity remain unchanged throughout the lifecycle. Only the content of the array can change the pointer and can point to any type of memory block at any time, it features "mutable", so we often use pointers to operate on dynamic memory. Pointers are far more flexible than arrays, but they are more dangerous. Modify the size of character array a to 6 Characters and the content is hello. The content of A can be modified, for example, a [0] = 'x '. the pointer P points to the constant string "world" (in the static storage area with the content of World). The content of the constant string cannot be modified. In terms of syntax, the compiler does not think that the statement P [0] = 'X' is inappropriate, but this statement attempts to modify the content of the constant string and causes a running 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 cannot directly copy and compare array names. If you want to copy the content of array a to array B, statement B = A cannot be used; otherwise, a compilation error will occur. Use the standard library function strcpy for replication. Similarly, to compare whether the content of B and A is the same, we should use the standard library function strcmp to compare the statement P = a. It cannot copy the content of a to the pointer p, instead, the address of a is assigned to P. To copy the content of A, you can first use the library function malloc to apply for a memory with a capacity of strlen (a) 1 character, and then use strcpy to copy the string. Similarly, the statement if (P = A) compares not the content but the address, and should be compared using the database function strcmp.
# Include <stdio. h> # include <string. h> # include <stdlib. h> int main () {char a [] = "hello"; char B [10]; strcpy (B, ); // B = A int Len = strlen (a); char * P = (char *) malloc (LEN + 1) * sizeof (char) cannot be used )); strcpy (P, A); If (strcmp (P, A) = 0) {printf ("P and a are equal! \ N ") ;}free (p); Return 0 ;}The sizeof operator can be used to calculate the memory capacity (in bytes) of an array ). The value of sizeof (a) is 12. point to P to A, but the value of sizeof (P) is 4. this is because sizeof (p) obtains the number of bytes of a pointer variable (32bit machine memory address is 32bit), which is equivalent to sizeof (char *), rather than the memory capacity referred to by P. Note: When an array is passed as a function parameter, the array will automatically degrade to a pointer of the same type. Sizeof (a) is always equal to sizeof (char *) regardless of the size of array *)
# 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}
Calculation Result: How does the pointer Parameter Pass the memory? If the function parameter is a pointer, do not expect this pointer to apply for dynamic memory. In the example, the getmemory (STR, 200) Statement of the test function does not enable STR to obtain the expected memory. STR is still null. Why? 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, 200); strcpy (STR, "Hello world! "); // Running error printf (" % s ", STR); free (STR); Return 0 ;}The error is caused by the getmemory function. The compiler always needs to make a temporary copy for each parameter of the function. The copy of the pointer parameter P is _ p, and the compiler makes _ p = P. if the program in the function body modifies the content of _ p, the content of parameter P is modified accordingly. This is why pointers can be used as output parameters. In this example, _ P applied for a new memory, but changed the memory address indicated by _ p, but P was not changed at all. Therefore, the getmemory function cannot output anything. In fact, each execution of getmemory will leak a piece of memory, because we can use the function return value to pass the dynamic memory without the free release of Memory Improvement. This method is simpler, as shown in the example below:
# 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, 200); strcpy (STR, "Hello world! "); // Running error printf (" % s \ n ", STR); free (STR); Return 0 ;}
Note: although it is easy to use the function return value to pass dynamic memory, some people often use the return statement wrong. It is emphasized that the return statement should not be used to return the pointer pointing to the "stack memory", because the function will automatically die when it ends. 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; // compiler warning} int main () {char * STR = NULL; STR = getarray (); printf (" % s \ n ", STR ); // STR points to spam free (STR); Return 0 ;}
Prevent "Wild Pointer" and "Wild Pointer" from being a null pointer or a pointer to "junk" memory. Generally, null pointers are not incorrectly used, because if statements are easy to judge. However, the "wild Pointer" is very dangerous, and the IF statement does not work for it. There are two main causes of "wild pointer:
- The pointer variable is not initialized. When a pointer variable is created, it does not automatically become a null pointer. Its default value is random, which means it is random. Therefore, the pointer variable should be initialized at the same time when it is created, either set the pointer to null or point it to a valid memory, for example:
char *p = NULL;char *str = (char *)malloc(sizeof(char) * 100);
- After the pointer P is free or deleted, It is not set to null. It is mistaken that p is a valid pointer.
- Pointer operations go beyond the scope of a Variable
How can I deal with memory depletion? If a large enough memory block cannot be found when applying for dynamic memory, the malloc function returns a null pointer, declaring that the memory application failed. There are usually three ways to handle the "memory depletion" Problem
- Judge whether the pointer is null. If yes, use the return statement to terminate the function immediately. For example:
char* getPoint(){char *p = malloc(sizeof(char) * 100);if (p == NULL) {return null;}}
- Determine whether the pointer is null. If yes, immediately use exit (1) to terminate the entire program (I often use it as a recommended practice ):
char* getPoint(){char *p = malloc(sizeof(char) * 100);if (p == NULL) {exit(1);}}
- Set exception handling functions for new and malloc
The following is a prototype of malloc:
void * malloc(size_t size);
In this example, use malloc to apply for an integer-type memory with a length. The program is as follows:
int *p = (int *)malloc(sizeof(int) * length);
Note:
- The type of the malloc return value is void *. Therefore, you must explicitly convert the type when calling malloc and convert void * to the required pointer type.
- The malloc function does not recognize the type of memory to be applied for. It only cares about the total number of bytes of memory. We usually cannot remember the specific bytes of data types such as int and float on different platforms. Therefore, using sizeof in malloc is a good style.
Reference http://blog.csdn.net/kakaka2011/article/details/7382923