Dynamic memory allocation of C (34)

        In general programs, we will inevitably encounter dynamic application memory, so what is the meaning of dynamic memory allocation? All operations in the C language are memory-based, and variables and arrays are aliases for memory. Memory allocation is determined by the compiler at compile time. When defining an array, the array length must be specified. Of course, the array length must also be determined at compile time.

        So why is there a need to dynamically allocate memory? While the program is running, it may be necessary to use some additional memory space. We all use malloc to dynamically apply for memory in C language . At that time , we used free when releasing. Let's take a look at how malloc and free are used to perform dynamic memory allocation and release. Use the following figure to illustrate

picture.png

        We can see that the program applies in the memory pool through malloc, and the return is released through free. If we just malloc the application without free, then our memory pool will be used up and the program will crash. This is what we usually call a memory leak.

        What malloc allocates is a contiguous piece of memory, which is in bytes and does not carry any type information . free is used to return dynamic memory to the system . The prototypes of these two functions are void* malloc(size_t size); void free(void* pointer) ; we have to pay attention to the following points: a> malloc and free are library functions, not system calls; b> malloc actually allocates There may be more memory than requested; c> cannot rely on malloc behavior under different platforms; d> when the requested dynamic memory cannot be satisfied, malloc returns NULL; e> when the parameter of free is NULL, the function returns directly .

        So let's think about it next, what will malloc(0) return? Will it report an error? Or do nothing? Or will there be indeterminate results? Let's do an experiment

#include <stdio.h>

intmain()
{
    int* p = (int*)malloc(0);
    
    printf("p = %p\n", p);
    
    return 0;
}

        Let's look at the compilation results

picture.png

        We see that the compiler gives a warning, but it still executes successfully. In fact, the memory we usually talk about has two concepts, one is its starting address, and the other is its size . In this section, we can explain it. malloc(0) only applies for a memory size of 0, but it also has a starting address. So if when we malloc(0) infinite times in the program, the program will eventually crash because its address information also takes up space.

        Let's take a look at another code, which is the memory detection module abstracted by Elder Tang from the actual project.


test.c source code

#include <stdio.h>
#include "mleak.h"

void f()
{
    MALLOC(100);
}

intmain()
{
    int* p = (int*)MALLOC(3 * sizeof(int));
    
    f();
    
    p[0] = 1;
    p[1] = 2;
    p[2] = 3;
    
    FREE(p);
    
    PRINT_LEAK_INFO();
    
    return 0;
}


mleak.h source code

#ifndef _MLEAK_H_
#define _MLEAK_H_

#include <malloc.h>

#define MALLOC(n) mallocEx(n, __FILE__, __LINE__)
#define FREE(p) freeEx(p)

void* mallocEx(size_t n, const char* file, const line);
void freeEx(void* p);
void PRINT_LEAK_INFO();

#endif


mleak.c source code

#include "mleak.h"

#define SIZE 256

/* Dynamic memory request parameter structure */
typedef struct
{
    void* pointer;
    int size;
    const char* file;
    int line;
} MItem;

static MItem g_record[SIZE]; /* Record the operation of dynamic memory request */

void* mallocEx(size_t n, const char* file, const line)
{
    void* ret = malloc(n); /* dynamic memory request */
    
    if( ret != NULL )
    {
        int i = 0;
        
        /* Traverse the global array and record this operation */
        for(i=0; i<SIZE; i++)
        {
            /* find the location */
            if( g_record[i].pointer == NULL )
            {
                g_record [i] .pointer = ret;
                g_record[i].size = n;
                g_record[i].file = file;
                g_record[i].line = line;
                break;
            }
        }
    }
    
    return ret;
}

void freeEx(void* p)
{
    if( p != NULL )
    {
        int i = 0;
        
        /* Traverse the global array, release memory space, and clear operation records */
        for(i=0; i<SIZE; i++)
        {
            if( g_record[i].pointer == p )
            {
                g_record[i].pointer = NULL;
                g_record[i].size = 0;
                g_record[i].file = NULL;
                g_record[i].line = 0;
                
                free(p);
                
                break;
            }
        }
    }
}

void PRINT_LEAK_INFO()
{
    int i = 0;
    
    printf("Potential Memory Leak Info:\n");
    
    /* Traverse the global array and print unreleased space records */
    for(i=0; i<SIZE; i++)
    {
        if( g_record[i].pointer != NULL )
        {
            printf("Address: %p, size:%d, Location: %s:%d\n", g_record[i].pointer, g_record[i].size, g_record[i].file, g_record[i].line);
        }
    }
}

        We see that memory is dynamically allocated in the f() function on line 6 in test.c, but not released. Since it is local, when this function is called, a memory leak will occur. Then we will print out the message on line 21. How is our corresponding function implemented? Put the requested memory address in an array in mleak.c, which will be checked later. If the FREE operation is performed, the corresponding deletion mark will be placed in the array, otherwise Mark exists. If the flag exists, we will print out the corresponding information. Let's take a look at the compilation results

picture.png

        We see that there is a memory size of 100 at address 0x9d13018 that has not been freed, which is located in line 6 of test.c. Next, let's comment out line 19 in teat.c to see if the memory will be printed if it is not released

picture.png

        We see the same print out. Prove that our memory leak detection module is still very accurate.

        Let's take a look at calloc and realloc, they are the siblings of malloc , the prototypes are: void* calloc(size_t num, size_t size); void* realloc(void* pointer, size_t new_size) ; then the parameters of calloc represent all Returns the type information of the memory, in which calloc will initialize the returned memory to 0; realloc is used to modify the size of a previously allocated memory block, the return value should be used after using realloc, when the first parameter of pointer is NULL , which is equivalent to malloc.

        Let's take the code as an example to analyze

#include <stdio.h>
#include <malloc.h>

#define SIZE 5

intmain()
{
    int i = 0;
    int* pI = (int*)malloc(SIZE * sizeof(int));
    short* pS = (short*)calloc(SIZE, sizeof(short));
    
    for(i=0; i<SIZE; i++)
    {
        printf("pI[%d] = %d, pS[%d] = %d\n", i, pI[i], i, pS[i]);
    }
    
    printf("Before: pI = %p\n", pI);
    
    pI = (int*)realloc(pI, 2 * SIZE * sizeof(int));
    
    printf("After: pI = %p\n", pI);
    
    for(i=0; i<10; i++)
    {
        printf("pI[%d] = %d\n", i, pI[i]);
    }
    
    free(pI);
    free(pS);
    
    return 0;
}

        Let's look at the compilation results

picture.png

        According to what we said earlier, the numbers in the array pI should be random numbers, and the numbers in the array pS are initialized to 0. But now it's all 0, don't worry, this is just an optimization done in gcc. We see that the size of the array pI does change after the call to realloc, and the address also changes. Let's see what the BCC compiler looks like

picture.png

        We see that the numbers in the array pI are indeed random numbers, while the numbers in the array pS are still all 0s. Through the study of dynamic memory allocation in this section, the summary is as follows: 1. Dynamic memory allocation is a powerful function in the C language, and the program can have the opportunity to use more memory when needed; 2. malloc simply applies for fixed memory from the system Byte-sized memory, calloc can apply for memory in units of type size and initialize it to 0, and realloc is used to reset the memory size.


        Welcome to learn C language together , you can add me QQ: 243343083 .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324810239&siteId=291194637