91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解C語言中的動態內存分配

發布時間:2021-11-25 14:15:17 來源:億速云 閱讀:184 作者:柒染 欄目:編程語言

如何理解C語言中的動態內存分配,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

        在一般的程序中,我們難免會遇到動態的申請內存,那么動態內存分配的意義到底是什么呢?在 C 語言中的一切操作都是基于內存的,變量和數組都是內存的別名。內存分配由編譯器在編譯期間決定,定義數組的時候必須指定數組長度,數組長度當然也是在編譯期就必須確定的。

        那么為什么會有動態分配內存的需求呢?在程序運行的過程中,可能需要使用一些額外的內存空間。我們都是在 C 語言中使用 malloc 來動態申請內存的,當時釋放的時候是用 free,下來我們看看 malloc 和 free 用于執行動態內存分配和釋放時是怎樣進行的,用下圖進行說明

如何理解C語言中的動態內存分配

        我們可以看到程序通過 malloc 在內存池中進行申請,那么歸還則是通過 free 進行釋放的。如果我們只是 malloc 進行申請而不 free,那么我們的內存池將會被用完,那么程序也就崩潰了。這就是我們平時所說的內存泄漏。

        malloc 所分配的是一塊連續的內存,它是以字節為單位并且不帶任何的類型信息。free 則是用于將動態內存歸還系統。這兩個函數的原型是 void* malloc(size_t size); void free(void* pointer);我們得注意這么幾點:a> malloc 和 free 是庫函數,而不是系統調用;b> malloc 實際分配的內存可能會比請求的多;c> 不能依賴于不同平臺下的 malloc 行為;d> 當請求的動態內存無法滿足時,malloc 返回 NULL;e> 當 free 的參數為 NULL時,函數直接返回。

        那么我們接下來思考下,malloc(0) 將返回什么?是會報錯?還是啥也不做?還是會出現不確定的結果?我們做下實驗看看

#include <stdio.h>

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

        我們看看編譯結果

如何理解C語言中的動態內存分配

        我們看到編譯器給出警告了,但是還是成功執行了。其實我們平時所說的內存有兩個概念,一個是它的起始地址,一個是大小。在這塊我們就好解釋了,malloc(0) 只是申請的內存大小為0而已,但是它還會有起始地址。所以如果當我們在程序中無限次的 malloc(0) 時,程序最終會崩潰,因為它的地址信息也會占用空間。

        下來我們再看一個代碼,是唐長老從實際工程中抽象出來的內存檢測模塊

test.c 源碼

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

void f()
{
    MALLOC(100);
}

int main()
{
    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 源碼

#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 源碼

#include "mleak.h"

#define SIZE 256

/* 動態內存申請參數結構體 */
typedef struct
{
    void* pointer;
    int size;
    const char* file;
    int line;
} MItem;

static MItem g_record[SIZE]; /* 記錄動態內存申請的操作 */

void* mallocEx(size_t n, const char* file, const line)
{
    void* ret = malloc(n); /* 動態內存申請 */
    
    if( ret != NULL )
    {
        int i = 0;
        
        /* 遍歷全局數組,記錄此次操作 */
        for(i=0; i<SIZE; i++)
        {
            /* 查找位置 */
            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;
        
        /* 遍歷全局數組,釋放內存空間,并清除操作記錄 */
        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");
    
    /* 遍歷全局數組,打印未釋放的空間記錄 */
    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);
        }
    }
}

        我們看到在 test.c 中第6行 f() 函數中動態申請了內存,但是沒有進行釋放。由于是局部的,當這個函數調用完后,將產生內存泄漏。那么我們在第 21 行將會打印出信息。我們這個對應的函數是怎么實現的呢,在 mleak.c 中將申請得到的內存地址放入一個數組中,在后面會進行檢查,如果進行 FREE 操作,便會在數組中對應的刪除標記,否則標記存在。如果標記存在,我們則會打印出對應的信息來。我們來看看編譯結果

如何理解C語言中的動態內存分配

        我們看到在地址為 0x9d13018 處存在100大小的內存沒進行釋放,它位于 test.c 的第6行。下來我們注釋掉 teat.c 中的第19行,看看這個內存沒進行釋放是否會打印出來

如何理解C語言中的動態內存分配

        我們看到一樣的打印出來了。證明我們這個內存泄漏的檢測模塊還是很準的。

        下來我們在來看看 calloc 和 realloc,它們是 malloc 的同胞兄弟,原型分別為:void* calloc(size_t num, size_t size); void* realloc(void* pointer, size_t new_size);那么 calloc 的參數代表所返回內存的類型信息,其中 calloc  會將返回的內存初始化為 0;realloc 用于修改一個原先已經分配 的內存塊大小,在使用 realloc 之后應該使用其返回值,當 pointer 的第一個參數為 NULL 時,等價于 malloc。

        下來我們以代碼為例進行分析

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

#define SIZE 5

int main()
{
    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;
}

        我們看看編譯結果

如何理解C語言中的動態內存分配

        按照我們前面講的,數組 pI 中的數應該是隨機數的,數組 pS 的數是被初始化為 0 的。可是現在全是0,別著急,這只是 gcc 中做的優化。我們看到數組 pI 在調用 realloc 后的大小確實改變了,并且地址也變了。下來我們看看 BCC 編譯器中是怎樣的

如何理解C語言中的動態內存分配

我們看到數組 pI 中的數確實是隨機數了,而數組 pS 中的數依舊全是 0。

總結如下:

1、動態內存分配是 C 語言中的強大功能,程序能夠在需要的時候有機會使用更多的內存;

2、malloc 單純的從系統中申請固定字節大小的內存,calloc 能以類型大小為單位申請內存并初始化為0,realloc 用于重置內存大小。

看完上述內容,你們掌握如何理解C語言中的動態內存分配的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

岳普湖县| 体育| 昌宁县| 临洮县| 江安县| 宝丰县| 龙里县| 舞阳县| 建阳市| 凉山| 唐河县| 三河市| 花垣县| 原平市| 陆良县| 沧源| 蓬莱市| 年辖:市辖区| 山东省| 施秉县| 保定市| 周宁县| 鹤峰县| 民县| 株洲市| 怀集县| 京山县| 仁寿县| 青州市| 松江区| 木里| 迭部县| 阳江市| 张家港市| 普兰店市| 繁昌县| 台南县| 井研县| 鱼台县| 唐山市| 安龙县|