1, the introduction
When you write a program, you often do not know the amount of data you need to process, or it is difficult to assess how much variation you need to process. In this case, to achieve efficient resource utilization – using memory management – you must dynamically allocate the required memory at run time and release the unneeded memory as soon as possible after use, which is the principle of dynamic memory management. Dynamic memory management also has the advantage of not having to rewrite a program when it needs to process more data on a system with more memory.
The memory occupied by a running C compiler is divided into five parts: code area, static data area, uninitialized data area, heap area and stack area.
C language defines four memory areas: code area, static storage area, stack area, heap area. Among them, stack area and heap area belong to dynamic storage area when the executable file is stored (that is, has not been loaded into memory), divided into: code area, static area and uninitialized data area three parts.
2. Code area
A read-only area, an area of storage where no changes can be made while a program is running. Used to store code and constants.
Store the machine instructions executed by the CPU. Typically, a code area is shareable (that is, it can be called by another executable), because frequently executed programs need only have one copy of the code in memory. Code areas are usually read-only, and the reason for making them read-only is to prevent a program from accidentally modifying its instructions. In addition, the code area also plans information about local variables.
Code area instructions are executed sequentially according to the programming flow. For sequential instructions, they are executed only once (per process). If they are repeated, they need to use jump instructions.
Code snippet: A code snippet is usually an area of memory used to store the code that a program executes. The size of this area is determined before the program runs, and memory areas are usually read-only. Some architectures also allow code segments to be writable, that is, to modify the program.
. The instructions in the code area include the opcode and the object (or object address reference) to operate on. If it is an immediate number (that is, a concrete value, such as 5), it will be included directly in the code; If the data is local, space is allocated in the stack area and the data address is referenced. If it is a BSS section and a data section, the data address will also be referenced in the code. In addition, the code segment also plans the memory space information requested by the local data.
Data area: read and write area, a storage area that can be modified as a program is running. Used to store variables
3. Static data area
This field contains global variables that are explicitly initialized in the program, static variables (including global and local static variables), and constant data (such as string constants). Note (only initialized once). For example, a declaration (global data) that is not in any function:
int max = 99;Copy the code
Causes the variable Max to be stored in the initialization data area according to its initial value.
static min = 100; Copy the code
This declares a static data that is a global static variable if declared outside any function, or a local static variable if declared inside the (local) body of the function. In addition, if you prefix the function name static, the function can only be called in the current file.
Data segment: Usually an area of memory used to hold initialized global variables in a program. The data segment is a static memory allocation. The static data area in the data section stores the global variables, static variables and constants initialized in the program.
4. Uninitialized data area
Uninitialized data area. Also known as BSS area, stores global uninitialized variables. The name BSS comes from an early assembly operator that marked the beginning of a block. BSS data is initialized to 0 or NULL by the kernel before program execution begins. For example, a declaration that is not in any function:
long sum[1000];Copy the code
Store the variable sum in the uninitialized data area.
BSS segment: Usually an area of memory used to hold uninitialized global variables in a program. BSS is short for Block Started by Symbol. The BSS segment is a static memory allocation, that is, it is zeroed out at the beginning of the program. The BSS section will normally be cleared during initialization.
5, the stack area
The stack area. By the compiler to automatically allocate the release of memory interval, the resulting memory space is generally continuous, is used to store the parameter value of the function, the value of local variables, etc. Stores function parameter values, local variable values, and the context content of the current task when switching tasks. It operates like a stack in a data structure. Whenever a function is called, the function returns the address and some information about the call, such as the contents of certain registers, is stored in the stack area. The called function then allocates space on the stack for its automatic and temporary variables. This is how C implements recursive calls to functions. For each recursive function call, a new stack frame is used so that variables in the new instance stack are not confused with variables in the other instance stack of the function. Int [] arr = {1, 2, 3}; int[] arr = {1, 2, 3}; The variable arr (array name) is stored in the stack, and the value of the variable arr (array elements) is stored in the heap (normal structure) (but not static, which means storing variables in a data segment). In addition, when a function is called, its parameters are pushed onto the stack of the process that initiated the call, and the return value of the function is pushed back onto the stack when the call ends. Because of the first-in, first-out nature of the stack, it is particularly convenient to save/resume the call scene. In this sense, we can think of the stack as an area of memory where temporary data is stored and exchanged.
6, heap area
The heap area. Used for dynamic memory allocation. The heap is located in memory between the BSS area and the stack area. Generally, it is allocated and released by the programmer. If the programmer does not release it, it may be reclaimed by the OS when the program ends. The memory area in the heap is not continuous, or the effective memory area is connected by linked list Pointers: used to hold the memory segment that is dynamically allocated during a process’s running, which is not fixed in size and can be dynamically expanded or shrunk. When a process calls a function such as malloc to allocate memory, the newly allocated memory is dynamically added to the heap (the heap expands); When memory is freed using functions such as free, the freed memory is stripped from the heap (the heap is reduced). When an application is loaded into memory space for execution, the operating system is responsible for loading code segments, data segments, and BSS segments, and will allocate space for these segments in memory. Stack segments are also allocated and managed by the operating system without the need for programmers to manage them explicitly. Heap segments are managed by the programmer himself, that is, by explicitly claiming and freeing space.
In addition, executable programs have corresponding program properties at run time. When supported by the operating system, these property pages are managed and maintained by the operating system.
After the C program is compiled, initialized global variables are stored in the data segment, and uninitialized global variables are stored in the BSS segment. Data segment and code segment are in the executable file, from which the system loads; The BSS segment is not in the executable and is initialized by the system. The BSS section only holds variables that have no values, so it doesn’t actually need to hold images of those variables. The size of the BSS segment required by the runtime is recorded in the target file, but the BSS segment does not occupy any space in the target file.
Difference between heap and stack:
The application memory space on the stack is automatically assigned, so when we are out of the variable’s scope, the system will automatically we recycle these Spaces, and the space on the heap application is to our own manual operation, when the corresponding scope, we need to call free or delete to release the application memory space, If we don’t free up the space in a timely manner, there will be more and more fragments in memory, and our actual memory space will become less and less, that is, more and more isolated memory blocks.
7, memset function
Memset is a computer C/C++ language initialization function. Set the contents of a block of memory to the specified value. This function usually initializes the newly requested memory. As mentioned before, it’s important to initialize variables, especially arrays and structures that use a lot of memory. When using arrays, it is common to get “hot hot hot hot hot” values because they are not initialized.
Each type of variable has its own initialization method. The memset() function is a “universal function” that initializes memory, usually for newly requested memory. It operates directly on memory space, meM stands for “memory”. The prototype of this function is:
## include <string.h>void *memset(void *s, int c, unsigned long n); Replaces the n bytes (typedef unsigned int size_t) following the current position in S with C and returns sCopy the code
The memory unit () function replaces the first n bytes pointed to by the pointer variable s with an integer c. S is a pointer variable of type void*, so it can be initialized for any type of data.
The purpose of memset() is to fill a block of memory with a given value. Because it can fill only one value, the initialization of this function is a raw initialization, and variables cannot be initialized to the data needed in the program. After initialization with memset, subsequent programs store the required data into the memory space.
Memsets typically use “0” to initialize memory units, and typically arrays or structures. Char, int, float, double and other variables can be initialized directly, there is no need to use memset. If you use memset, it will be troublesome.
Of course, arrays can also be initialized directly, but memset is the fastest way to zero out large arrays or structures because it operates directly on memory.
At this point, one might ask, “Isn’t an array of strings best initialized with ‘\0’? Can memset be used to initialize string arrays? So can the parameter c be assigned to ‘\0’?”
You can. Although c is required to be an integer, integers and characters are interchangeable. But assigning ‘\0’ is equivalent to 0, because the character ‘\0’ is 0 in memory. So initializing to 0 in memset also acts as the end identifier ‘\0’, so we usually just write ‘0’.
The third argument to the memset function is sizeof(). Note that the pointer variable must first be initialized to point to a valid address if it is zeroing out the memory location it points to. N should not be sizeof(p) when using memset to initialize a pointer to a memory cell such as p, which is a common rookie mistake. Because p is a pointer variable, no matter what type of variable p refers to, sizeof(p) has a value of 4. (Find someone else’s online)
#include<stdio.h>
#include<string.h>int main(void) { int i; char str[10]; char *p = str; memset(str, 1, sizeof(str)); // The last initializer is the length (it can be a number, but it is not necessary)for (i = 0; i < 10; i++) {
printf("%d\t", str[i]);
}
return 0;
}Copy the code
Memset (p, 0, sizeof(p)); // Address size is 4 bytes 0 0 0 0-52-52-52-52-52
memset(p, 0, sizeof(
The p represents a character variable of one byte, 0-52-52-52-52-52-52-52
memset(p, 0, sizeof(str)); 0 0 0 0 0 0 0 0 0 0
memset(str, 0, sizeof(str)); 0 0 0 0 0 0 0 0 0 0
memset(p, 0, 10); 0 0 0 0 0 0 0 0 0 0
Calloc function
Sometimes, we need a period of memory in the program to process the data, but also under the condition of uncertainty is to how much memory, for example, we apply an array a [100] but we do not know in advance will not use this 100 elements, for example, we will only use 10, then the rest of the 90 will still takes up space, is quite a waste of space, The calloc function is used to allocate contiguous storage space in the dynamic storage area of memory (in the heap)
Function prototype:
Void * calloc (unsigned int num, unsigned int size) void* calloc (unsigned int num, unsigned int size) The number of bytes of memory that an object occupies. Calloc automatically initializes memory to 0 compared to mallocCopy the code
After calloc dynamically allocates memory, it automatically initializes the memory space to zero. Malloc does not initialize the memory space, and the data in the allocated space is random.
Note: Size is only the sizeof the requested memory byte and has nothing to do with the data type stored in the requested memory block. Therefore, it is recommended to specify the size as “length * sizeof(data type)”. Int *p = (int *)calloc(20, sizeof(int))).
The calloc function returns a pointer to the starting address of the allocation; If the assignment is unsuccessful, NULL is returned.
#include<stdio.h>
int main(void) {
int *p = (int *)calloc(10, sizeof(int));
int i;
printf("Applied space is: \n");
for (i = 0; i < 10; i++) {
printf("%d ", *p++);
}
return0; } result: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Copy the code
Then one wonders: since calloc requires no computational space and can directly initialize memory to avoid errors, why not use calloc directly? What is malloc for? As a matter of fact, everything has two sides, there is a good side and inevitably there is a bad side. That’s efficiency. The calloc function is necessarily less efficient than malloc because it needs to initialize values for each space, and in the real world, many cases of space application do not need initial values, which is why many beginners are more exposed to malloc function
Realloc functions
Realloc () functions can reuse or extend memory previously allocated with malloc(), calloc(), and realloc() functions themselves.
Function prototype:
extern void *realloc(void *mem_address, unsigned int newsize); // Pointer name = (data type *) realloc (pointer name to change memory size, new size). // The new size must be larger than the original size, otherwise it will cause data loss! // If newsize is 0, free the memory pointed to by mem_address and return NULL.Copy the code
Check whether the current pointer has enough contiguous space. If so, expand the address pointed by mem_address and return mem_address. If not, allocate space according to the size specified by newsize first, copy the original data to the newly allocated memory area from beginning to end. The mem_address pointer is freed and the first address of the newly allocated memory region is returned. That is, reassign the address of the memory block.
The realloc() function takes two arguments: a pointer to the address returned by the previous malloc(), calloc(), or realloc() function, and the number of bytes of memory to allocate.
The realloc() function allocates the amount of memory specified by the second argument and copies the previously allocated contents of the first argument to the newly allocated memory equal to the smaller size of the old and new memory regions. That is, if the new memory is larger than the original memory, all the contents of the original memory are copied to the new memory. If the new memory is smaller than the original memory, only the contents whose length is equal to that of the new memory are copied.
If the first argument of realloc() is null, it is equivalent to allocating the new memory space specified by the second argument, which is equivalent to malloc(), calloc(), or realloc().
Realloc () will return the pointer to realloc(). Realloc () will return the pointer to realloc(). Realloc () will return the pointer to realloc(). 2) If there are not enough free bytes after the current memory segment, the first memory block in the heap that meets this requirement is used, the current data is copied to the new location, the original data block is freed, and the new memory block address location is returned. 3) If the request fails, NULL is returned, and the original pointer is still valid.
Matters needing attention:
The first argument is either a null pointer or a pointer to previously allocated memory. If you do not point to previously allocated memory or to freed memory, the result is indeterminate.
2. If the call succeeds, regardless of whether the free space behind the current memory segment meets the requirements, the original pointer will be released and a new pointer will be returned, although the returned pointer may be the same as the original pointer, that is, the original pointer cannot be released again.
Return value: a pointer to the allocated memory is returned if the reallocation is successful, otherwise NULL is returned.
Note: the data in raw memory remains the same. When memory is no longer used, you should use functions such as free() to free the memory block
#include<stdio.h>
#include<stdlib.h>
int main() { int i; int *t; int*pn = (int*)malloc(10 * sizeof(int)); Int t = pn;for(i = 0; i < 10; I ++) {// assign pn[I] = I; } realloc(pn = (int*)realloc(pn, 20 * sizeof(int)); // Add 10 more ints to add 20 intsfor(i = 10; i < 20; I ++) {// reassign pn[I] = I; }for(i = 0; i < 20; I++) {/ / outputprintf("%3d", pn[i]);
}
printf("\n");
printf("p=%p \nt=%p\n", pn, t); // Output address free(pn); // Free space pn = NULL; // The pointer is nullreturn0; } If the value of the applied space is small and there is free memory behind the original applied dynamic memory, the system will directly expand the space behind the original dynamic memory and return the original dynamic space base address; If the requested space is too large and there is not enough space for expansion, the system applies for a new piece of memory and copies the contents of the original space. The OS automatically frees the original space. If the requested space is too large, the system memory fails to be allocated and NULL is returned. The original memory will not be released. Note: If the memory space after expansion is smaller than the original space, there will be data loss, if directly realLOc (p, 0); Equivalent to free (p).Copy the code
Summary of use:
-
When RealLOc fails, NULL is returned
-
When Realloc fails, the original memory is not changed, freed or moved
-
If there is enough free memory behind the original memory,realloc memory = original memory + free memory, realLOc still returns the original memory address; If there is not enough memory left behind the original memory,realloc will apply for a new memory, and copy the original memory data into the new memory, the original memory will be free, Realloc returns the address of the new memory
-
If size is 0, the effect is the same as free(). Note that only the pointer itself will be released, such as the two-dimensional pointer ** A. When calling realloc on a, only one dimension will be released.
-
Pointers passed to Realloc must have been previously allocated via malloc(), calloc(), or Realloc ()
6. Pointers passed to Realloc can be null, equivalent to malloc.
Malloc and the free function
Malloc is called dynamic memory allocation, in Chinese is used to apply for a contiguous area to specify the size of the memory block type void * return distribution area of memory address, when cannot know memory location, want to bind the real memory space, you need to use dynamically allocated memory, and the distribution of size is the size of the program requirements.
Function prototype:
Void * malloc (size_t size); Malloc used to return a char pointer. The ANSIC standard states that this function returns a void pointer, so casting is required if necessary. It can request the system to allocate a memory block of num_bytes (or size) length. Allocate a contiguous space of size in the dynamic storage area of memory. When a memory allocation is successful, the function returns the starting address of the allocated area. Alternatively, the function returns a pointer to the beginning of the allocated area. (It returns the first byte address of the allocated memory.) If a suitable block of memory cannot be obtained, malloc returns a null pointerCopy the code
Int *p = (int *)malloc(20*sizeof(int)). If the compiler defaults int to 4 bytes, then the result is 80 bytes. And cast the space base address to int and assign a value to the pointer P, at this time the applied memory value is uncertain.
The essence of the malloc function is that it has the ability to concatenate available chunks of memory into a long list called a free linked list. When the malloc function is called, it looks along the join table for a block of memory large enough to satisfy the user’s request. The memory block is then split in two (one is equal to the size requested by the user, and the other is the remaining bytes). Next, the allocated chunk of memory is passed to the user and the remaining chunk (if any) is returned to the join table. When the free function is called, it attaches the memory block freed by the user to the free chain. Eventually, the free chain will be cut into many small memory fragments, and if the user requests a large memory fragment, there may be no fragments on the free chain that can meet the user’s requirements. The malloc function requests a delay and starts rummaging through the fragments on the free chain, collating them and merging adjacent small free blocks into larger ones. If a memory block cannot be obtained, the malloc function returns a NULL pointer (NULL pointer). Therefore, when calling malloc to dynamically apply for a memory block, we must determine the return value.
#include<stdio.h>
#include <stdlib.h> int main(void) { int count, *array; /*count is a counter, and array is an integer pointer to an array of integers */if((array=(int *) malloc(10 * sizeof(int))) == NULL)printf("Failed to allocate storage space.");
exit(1); // force to end the program}for(count = 0; count < 10; Count++) {/* assign to array */ array[count] = count; }for(count = 0; count < 10; Count++) {/* prints the array element */printf("%2d", array[count]);
}
return 0;
}Copy the code
-
Free: Free () is a memory freer function in C. It is usually used in combination with malloc() to free memory allocated by malloc(), calloc(), and realloc().
Function prototype:
void free(void *ptr); PTR -- Pointer to a block of memory to free that was previously allocated by calling malloc, calloc, or Realloc. If the argument passed is a null pointer, no action is taken. This function does not return any value.Copy the code
Example above:
#include<stdio.h>
#include <stdlib.h> int main(void) { int count, *array; /*count is a counter, and array is an integer pointer to an array of integers */if((array=(int *) malloc(10 * sizeof(int))) == NULL)printf("Failed to allocate storage space.");
exit(1); // force to end the program}for(count = 0; count < 10; Count++) {/* assign to array */ array[count] = count; }for(count = 0; count < 10; Count++) {/* prints the array element */printf("%2d", array[count]); } free(array); // No memory was freedreturn0; } ******free is important: ******* The amount of static memory is fixed at compile time and does not change at run time. The amount of memory used by automatic variables automatically increases or decreases during program execution, but the amount of dynamically allocated memory only increases unless freed using the free function which creates a pointer to array, (10* 4(int)) 40 bytes of memory. Assuming, as the code comments indicate, that free is omitted, when the function ends, the pointer to array as an automatic variable also disappears, but the 40 bytes of memory it points to remain. Since the array pointer has been destroyed, this memory cannot be accessed, and it cannot be reused because there is no call to free the memory. If it is a function, when it is called a second time, it creates the array pointer and calls malloc to allocate 40 bytes of memory. The first call to 40 bytes of memory is unavailable, so the malloc function allocated additional memory, when the function at the end of the memory cannot be accessed and used again, if the cycle to be 1000 times, and each time the call will allocate memory, continue to increase, in fact, before the end of the program, already run out of memory, This type of problem is called memory leak, so to prevent this kind of problem, you must add the free function after the dynamic memory allocation function to free the memory.Copy the code
Conclusion:
Malloc must be forced to be converted to a pointer of the actual type after we count the number of bytes. Another difference that isn’t immediately obvious is that Malloc allocates memory and doesn’t initialize it, so the value of a new slice of memory will be random
Generally, use free(the pointer to the start address) to release the memory after use. Otherwise, too many memory requests will cause memory leakage and affect the performance of the computer, so that the computer has to restart. This pointer can also be used to access the block of memory if it is not cleared.
In general, the malloc function is paired with the free function, which takes the address (pointer) returned by mallloc and frees the memory allocated by malloc. Therefore, The storage life of dynamic memory allocation is from malloc (or other) until F calls ree to free the memory. Malloc and free are suspected of managing a memory pool. Each call to malloc allocates memory to the program, and each call to free returns memory to the pool so that it can be reused. The argument to free should be a pointer to a block of memory allocated by malloc, and cannot be freed by other means (e.g. Declare an array), the allocated memory, the prototype malloc and free functions are all in the stdio.h header file.
11. Dynamic Memory Allocation (Dynamic storage)
Memory is allocated when the program executes and uses this variable, and freed immediately after use.
Dynamic memory allocation refers to the method of allocating or reclaiming storage space dynamically in the process of program execution. Unlike static memory allocation methods such as arrays, which require pre-allocation of storage space, dynamic memory allocation is made by the system on the spot according to the needs of the program, and the allocated size is the size required by the program.
When a program runs to the point where it needs a dynamically allocated variable or object, it must ask the system for a block of storage space in the heap of the required size to store the variable or object. When the variable or object is no longer in use, that is, at the end of its life, the amount of storage it occupies is explicitly released so that the system can reallocate the heap space and reuse limited resources.
When working with arrays, there is always the question: How big should an array be? In many cases, you don’t know how big an array you want to use. For example, you may not know how big the array you want to define is, so you need to make the array big enough. In this way, your program is running with a fixed amount of memory that you think is large enough. Even if you know how much space you want to use, if for any particular reason the amount of space you want to use increases or decreases, you have to modify the program again to make the array larger. This method of allocating fixed-size memory is called static memory allocation. But this approach to memory allocation has serious drawbacks, especially when dealing with certain problems: in most cases, it wastes a lot of memory, and in rare cases, it can cause out-of-bounds subscript errors when you define arrays that are not large enough.
We can solve this problem with dynamic memory allocation. The so-called dynamic memory allocation refers to the method of allocating or reclaiming storage space dynamically in the process of program execution. Unlike static memory allocation methods such as arrays, dynamic memory allocation requires pre-allocation of storage space, but is allocated by the system according to the needs of the program, and the size of the allocation is the size required by the program.
From the above dynamic and static memory allocation comparison can know the characteristics of dynamic memory allocation relative to static memory allocation:
1, do not need to allocate storage space in advance;
2. The allocated space can be expanded or reduced according to the needs of the program.
Common dynamic memory errors:
-
Dereference a NULL pointer
-
Bounds are crossed when operating on allocated memory
-
Free memory that is not dynamically allocated
-
An attempt to free part of a dynamically allocated block of memory and to continue using a block of memory after it has been freed.
Description:
-
The most common mistake with dynamic allocation is forgetting to check whether the requested memory was successfully allocated.
-
The second biggest source of errors in dynamic memory allocation is manipulating memory beyond the boundaries of allocated memory.
-
Different errors can occur when you use free:
1. The pointer passed to free must be a pointer returned from malloc, calloc, or Realloc.
2. Passing a pointer to the free function to free a block of memory that is not dynamically allocated can cause the program to terminate immediately or at a later time.
3. Attempting to free part of a dynamically allocated block of memory can cause similar problems.
// Example: Dynamic memory allocation implements a variable length one-dimensional array#define _GRT_SECURE_NO_WARNNGS
#include<stdio.h>
#include<stdlib.h>
#include"array.h"// This header contains a structure representing arrays and declarations of the following functionsconst Block_size = 20; /* Array array_creat(int ints_size); // Create an Array void array_free(Array *a); Int array_size(const Array *a); Int *array_at(Array *a, int index); Void array_inlate(Array *a, int more_size); */ int main(void) {Array a; Int I, j,n,m=0;while (1) {
printf("Please enter the size of the array you want: \n");
scanf("%d", &n); a = array_creat(n); // This can get the argument returned by aprintf("Input data \n");
for (i = 0; i < n; i++) {
scanf("%d", &j); *array_at(&a, i) = j; // This function is equivalent to an array and stores the value of j into an element in the array.printf("Output data: \n");
for(i = 0; i < n; I++) {// iterate over the outputprintf("%d ", a.arrray[i]);
printf("\n");
}
printf("\n");
printf("Type 1 to initialize the array size, type something else to exit the program: \n");
scanf("%d", &n);
if(n == 1) { m = 0; // set j = 0; array_free(&a); // Free memory}else {
exit(0); // Exit program}}return0; } Array array_creat(int ints_size) // Create an Array {Array a; // Define an array structure a.size=ints_size; A.arrrray = (int *)malloc(sizeof(int)*a.size); // The first int* is a cast, and the second int* is 4 bytesreturna; } void array_free(Array *a)// Reclaim space {free(a->arrray); a->arrray = NULL; A ->size = 0; } // wrap int array_size(const Array *a)returna->size; } int *array_at(Array *a, int index)if(index >= a->size) {// The following formula is used to calculate the base of Block_size. Array_inlate (a, (index/Block_size + 1)*Block_size - a->size); // Return pointer is parenthesized to keep precedence intactreturn&(a->arrray[index]); // If a value is returned, it cannot be changed, } void array_inlate(Array *a, int more_size)// add {int* p = (int*)malloc(sizeof(int)*(a->size+more_size)); // Add a larger block of memory.for(i = 0; i < a->size; P [I] = a->arrray[I]; } free(a->arrray); A ->arrray = p; A ->size += more_size; 5 Input data 1 2 3 4 5 Output data: 1 2 3 4 5 Input 1 initialize the array size, input other statements exit program: 1 input the array size you need: 6 Input data 1 2 3 4 5 6 Output data: 1 2 3 4 5 6 Input 1 Initialize the array size, enter other statements exit program: 0 Process 1520 has exited. Return code is 0. Press any key to close this window...Copy the code
// Example: Dynamic memory allocation implements variable length 2d arrays#include<stdio.h>
#include<malloc.h>
int main(void)
{
int n, m;
scanf("%d %d", &n, &m); Int **p = (int **)malloc(sizeof(int *) * n); Malloc returns an int*; sizeof(int*) specifies the sizeof the pointer multiplied by /*, and returns the first address to a 2-d pointer p; Int a < -- int *; < -- int **p; int b < -- int *; int c < -- int *; int d < -- int *; */ // (int* *) one * represents a cast, and the other one represents a pointer to int* //sizeof(int*). // The data type of the p pointer is a second level pointer, and it points to some first level Pointers in the spacefor(int i = 0; i < 5; I++) / / each row has two columns elements {p = (int *) [I] malloc (sizeof (int) * m); // The size of each level pointer value points to an actual size of space // *(p+ I) = p[I] each movement represents the movement of the row} // assignmentfor (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
p[i][j] =1;
//*(*(p + i) + j) = p[i][j]
}
}
for (int i = 0; i < n; i++)
{
for(int j = 0; j < m; J++) {// prints the value and address of each element of the arrayprintf("%d=%p\t", p[i][j],&p[i][j]);
}
printf("\n");
}
for(int i = 0; i < n; I ++) {// free(p[I]); } free(p); // Release the wholereturn0; } /* 5 2 1=010F44C0 1=010F44C4 1=010F4378 1=010F433C 1=010F4330 1=010F4374 1=010FAB60 1=010FAB64 1=010FAD98 1=010FAB94 Process 8432 has exited. Return code is 0. Press any key to close this window...Copy the code
12, Const function (supplement)
Const, which converts an object to a constant. Const is a constant in C. In fact, const is quite powerful in C. It can modify variables, arrays, Pointers, function arguments, and so on.
1. Modify variables:
Using const to modify a variable in a program allows you to declare the variable read-only and protect its value from modification. As follows:
const int i = 5; Variable I is read-only and cannot be changed; If you want to reassign I, say I = 10; Is wrong.
It is important to note that when a variable is defined, it must be initialized. The definition can also be written as int const I =5, which is also true.
In addition, const modifiers also save space. Usually, the compiler does not allocate space to ordinary const read-only variables. Instead, it stores them in a symbol table.
2. Decorate arrays
Const can also modify arrays in C, as in the following example:
Const int array[5] = {1,2,3,4,5};
array[0] = array[0]+1; / / error
Array elements, like variables, have read-only properties that cannot be changed; Once changed, such as the program will report an error.
3. Modify function parameters
The const keyword decorates a function parameter, qualifying it to prevent it from being modified inside the function. The qualified function parameters can be ordinary variables or pointer variables. Examples are as follows:
void fun1(const int i)
i++; // The value of I was changed
void fun2(const int *p)
(*p)++; // The value of p pointing to space is changed
Int sum(const a[],int n); int sum(const a[],int n); This code tells the compiler that the function cannot modify the contents of the array pointed to by a, if you accidentally use something like a[I]++; , then the program will report an error. Note that this use of const does not require the array to be a constant. Rather, the function treats the array as a constant and cannot be modified. Using const protects the data in the array from being modified.
4. Modify Pointers
Const pointer (C); const pointer (C); const pointer (C) The other is to make the pointer immutable. Examples are as follows:
int i = 5;
int j = 6;
int k = 7;
const int * p1 = &i; / / definition 1
int * const p2 =&j; / / definition 2
Two Pointers p1 and p2 are defined above.
Const p1=20; const p1=20; const p1=20; However, the value of P1 can be changed, and there is no problem in reassigning p1, such as P1 =&k.
In definition 2, const is limited to p2. If p2=&k, an error will be reported. But *p2, that is, the value of the space it points to can be changed, such as *p2 =80 is no problem, the program runs normally.
There are a few rules to note about pointer assignment and const:
It is legal to initialize or assign an address to const or nonconst data as a pointer to const. 2. We can declare and initialize a pointer that can point nowhere else, but at the location of const. 3. We can also use const twice when creating a pointer, which means that the pointer cannot change either the address to which it points or the value of the address to which it points
List:
int a[10]; const double b[10]; const double *p=a; / / p = b effectively; / / effective p = & a, [3]. // valid --------------------------- int a[10]; const double b[10]; Double *p=a; double *p=a; double *p= b; // Void * p=&a[3]; / / effective -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- void sum (const double * a, int n); // This function can take a plain array and a const array name, because both can be used to initialize a pointer to const int a[10]; const double b[10]; sum(a,5); / / legal sum (b, 4); --------------------------- int a[10]; double *const p=a; //p points to the beginning of the array p=&a[0]; *p=9.9; / / can do, to change the value of a [0] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- int a, [10]. const double *const p=a; p=&a[0]; // not allowed *p=9.9; / / not allowedCopy the code
13, block
Block is a block of data, is an abstract concept, have nothing to do with the C language, this kind of abstract things, don’t say can also use other languages, is partitioned management will put the things in daily life, not to block in the C language definition, because this is only an abstract concept, block can be a memory block, block, block, even a postage stamp can also is a piece of… A basic unit that is classified in management
Storage period:
This is also a characteristic of variables. It’s called lifetime, and it’s how long a variable has been in memory.
1. Static storage: Memory space is allocated when the program is compiled and remains unchanged until it is released at the end of the program execution.
Thread_local allocates a separate private backup to each thread
3. Automatic storage period: Local variables are usually automatically stored for the auto period
4, dynamic storage: is the memory allocated with new or MALloc, if not actively released, in the entire program occupied memory
Scope:
This is the scope in which the variable works, depending on the link point.
1. Block scope: enclosed in {}, from the beginning of the declaration to the end of “}”
2. Function scope: The scope of goto (identifier) is the entire function.
3, function prototype scope: function declaration begins, function declaration ends and ends
4. File scope: the entire file or program
Link property: Indicates the scope in which a variable can be used.
1, internal links: can only be used within the source file.
2, external links: can be used in the source file internal and external files.
3. Empty connection: can only be used within code blocks (functions).
Qualifiers:
Volatile:
const:
restrict:
_Atomic: