EP15:動態內存管理概述(c語言)malloc,calloc,realloc函數的介紹使用及柔性數組的介紹

如果學習方向是c++方向那么c語言有三個板塊的知識是非常重要的. 1:指針 2:結構體 3;動態內存管理.

序言:在c語言中,什么是動態內存

C語言中的動態內存是指在程序運行時,根據需要動態地分配內存空間的一種內存管理方式。與靜態內存相比,動態內存的大小和生命周期都可以在程序運行時動態地確定和調整,因此更加靈活。C語言中提供了四個函數:malloc、calloc、realloc和free,用于動態地分配和釋放內存空間。其中,malloc和calloc用于分配內存空間,realloc用于調整已分配內存空間的大小,free用于釋放已分配的內存空間。動態內存的使用需要引用頭文件<stdio.h>或<malloc.h>。

在本篇文章中,我們將著重簡述何為malloc函數,calloc函數,free,以及柔性數組

1.malloc函數簡述

1.1free函數

C語言提供了另外?個函數free,專門是用來做動態內存的釋放和回收的,函數原型如下:

?void free (void* ptr);

free函數用來釋放動態開辟的內存。

?但凡涉及到動態內存的開辟,釋放空間這一步作為最后一步絕對是不可或缺的.

1.2 malloc函數

函數頭文件: #include <stdlib.h>

函數參數: void* malloc (size_t size);

函數作用: 用于開辟動態內存

從代碼示例看函數的具體使用方法

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
?? ?int* p = (int*)malloc(10 * sizeof(int));//1.動態內存的開辟(指針p所指向的是malloc函數開辟空間的起始地址)

? ? ?malloc():括號里面要寫的是開辟多少大小的內存空間,一般用:任意整數*sizeof(整型)
?? ?if (p == NULL)
?? ?{
?? ??? ?perror("malloc");
?? ??? ?return 1;
?? ?}


?? ?int i = 0;
?? ?for (i = 0; i < 10; i++)//2.對動態內存開辟的空間進行訪問

?? ?{
?? ??? ?*(p + i) = i;//使用指針p去訪問malloc開辟的空間里面的元素,再解引用賦值給i
?? ?}


?? ?for (i = 0; i < 10; i++)//3.對開辟的空間中的內容進行打印
?? ?{
?? ??? ?printf("%d ",i );//將剛才訪問的空間里面存儲的數據打印出來
?? ?}


?? ?free(p);//4.對開辟的空間進行回收
?? ?p=NULL;
?? ?return 0;
?}

為啥要這么寫:??int* p = (int*)malloc(10 * sizeof(int));

解釋:由函數參數 void* malloc (size_t size);可知malloc函數一個空指針類型的函數,但是由于空指針是不可以直接用于指針的運算的,所以我們要將它強制類型轉換成我們想要的類型.

一點聯想:這一點讓我想起了qsort函數,感覺void*類型的指針都要進行這樣的操作,可以在這里留意一下并且進

行相關的知識遷移以便日后遇到相似知識點的學習

2.calloc函數簡述

總而言之,calloc函數的使用方法以及功能和malloc函數基本一致

函數頭文件: #include <stdlib.h>

函數參數: void* calloc (size_t num, size_t size);

函數作用: 用于開辟動態內存

從代碼示例看函數的具體使用方法

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
?? ?int* p = calloc(10, sizeof(int));//1.動態內存的開辟
?? ?if (p == NULL)
?? ?{
?? ??? ?perror("calloc");
?? ??? ?return 1;
?? ?}


?? ?int i = 0;//2.對動態內存開辟的空間進行訪問
?? ?for (i = 0; i < 10; i++)
?? ?{
?? ??? ?*(p + i) = i;
?? ?}


?? ?for (i = 0; i < 10; i++)//3.對開辟的空間中的內容進行打印
?? ?{
?? ??? ?printf("%d ", *(p + i) );
?? ?}


?? ?free(p);//4.對開辟的空間進行回收
?? ?p = NULL;

?? ?return 0;
}

3.對malloc函數與calloc函數進行總結

3.1 不同點 (函數參數上)

以上述兩段代碼為例

malloc函數是:int* p = (int*)malloc(10 * sizeof(int));

calloc函數是:?int* p = (int*)calloc(10, sizeof(int));

觀察上述兩段代碼,其實也沒啥不同點,就是把函數括號里面我們想要開辟的空間的那個表達式把逗號改成了*號的區別嘛

3.2 相同點(函數使用步驟上)

首先要明確的是它們都要進行強制類型轉換轉換成我們想要的指針類型.

最重要的是,它們是使用步驟可以分成四步

1.動態內存的開辟

2.對動態內存開辟的空間進行訪問

3.對開辟的空間中的內容進行打印

4.對開辟的空間進行釋放

簡化一下就是: 1.開辟 2.訪問 3.使用 4.釋放

這兩個函數在這四個步驟上的寫法是一摸一樣,沒有任何區別的.將此四部先后邏輯順序理清并進行適當的記憶這兩個動態內存函數便可以說是掌握了.

所以此二者等價

4.重要的realloc函數的簡介與使用

4.1 對realloc函數的使用進行簡述

?在本文的開頭闡述過何為動態內存"...動態內存的大小和生命周期都可以在程序運行時動態地確定和調整,因此更加靈活。..."

故而沒有realloc函數的介入很難把一段可正常運行的代碼叫做"動態內存管理"

函數頭文件: #include <stdlib.h>

函數參數: void* realloc (void* ptr, size_t size);

對函數參數的解釋: void*ptr就是要進行擴展的對象,size_t size就是要將被擴展的擴展至管理員預期的空間

函數作用: 用于動態內存的擴展,要和malloc函數或者calloc函數進行聯合使用

具體且形象的講解realoc函數的作用:

realloc的作用就是將原本malloc和calloc開辟的空間擴大到多少
舉個例子就是說如果malloc或calloc是一段單向路上不與起點重合的一個質點,calloc就是另外一個質點
用calloc質點到起點的距離減去malloc,calloc質點所在的距離便是calloc函數所追加的空間

如圖


?

從代碼示例看函數的具體使用方法

就是在malloc函數和calloc函數原先的使用步驟上加上擴容這一步

1.動態內存的開辟

2.對動態內存開辟的空間進行訪問

3,對malloc函數或calloc函數開辟的空間進行擴容

4.對開辟的空間中的內容進行打印

5.對開辟的空間進行釋放

總結下來就是 1.開辟 2.訪問 3,擴容 4.使用 5.釋放

4.2?以calloc函數進行開辟為例,擴容的公式

? ? int* ptr = (int*)realloc(p, 15 * sizeof(int));//擴展開辟空間
?? ?if (p != NULL)
?? ?{
?? ??? ?p = ptr;
?? ?}
?? ?else
?? ?{
?? ??? ?perror("errno");
?? ??? ?return 1;
?? ?}?

為什么這么寫: int* ptr = (int*)realloc(p, 15 * sizeof(int));

這里便涉及到calloc函數擴展內存空間的方式了

4.2.1calloc函數擴展內存空間的方式

情況1:擴展失敗,返回NULL,于是便有了?

?else
?? ?{
?? ??? ?perror("errno");
?? ??? ?return 1;
?? ?}?

情況2;擴展成功了,于是便有了

if (p != NULL)
?? ?{
?? ??? ?p = ptr;
?? ?}

擴展成功方式1:

在malloc函數或者calloc函數開辟好的空間后進行擴容,如果沒有足夠的空間進行擴大時候,此時的calloc函數會在堆區中重新選擇一塊大小滿足需求的空間,同時將舊空間中的舊數據連同著一塊拷過來,這也是為啥雖然上述代碼? int* ptr = (int*)realloc(p, 15 * sizeof(int));雖然寫的是15 * sizeof(int)實際上只是擴展了5*sizeof(int)大小的空間.然后釋放就空間,同時返回新的空間.

擴展成功方式1:

若空間大小足夠,則在已經開辟好的空間直接進行追加空間進行擴展,擴大空間后,直接返回就空間的起始地址.

?

4.3 從示例看realloc函數的具體用法?

根據上面總結的五個步驟來寫:??1.開辟 2.訪問 3,擴容 4.使用 5.釋放

int main()// 開辟 訪問 ? 擴容 使用 釋放
{
?? ?//開辟
?? ?int* p = (int*)calloc(10, sizeof(int));
?? ?if (p == NULL)
?? ?{
?? ??? ?perror("calloc");
?? ??? ?return 1;
?? ?}

?? ?//訪問
?? ?int i = 0;
?? ?for (i = 0; i < 10; i++)
?? ?{
?? ??? ?*(p + i) = i;
?? ?}

?? ?//擴容
? ? ?int* ptr = (int*)realloc(p, 15 * sizeof(int));//擴展開辟空間
?? ?if (p != NULL)
?? ?{
?? ??? ?p = ptr;
?? ?}
?? ?else
?? ?{
?? ??? ?perror("errno");
?? ??? ?return 1;
?? ?}

?? ?//使用
?? ?for (i = 0; i < 10; i++)
?? ?{
?? ??? ?printf("%d ", *(p + i) );
?? ?}

?? ?

?? ?//釋放
?? ?free(p);
?? ?p = NULL;

?? ?return 0;
}

ps:其實realloc函數除了調整空間外,也可以實現和malloc或者realloc函數一樣的功能

int*p=(int*)realloc(NULL,1o*sizeof(int));等價于malloc或者calloc函數,只是一般不這么去寫.

5.柔性數組?

5.1 柔性數組概述

?C99 中,結構中的最后一個元素允許是未知大小的數組,這就叫做『柔性數組』成員。

結構體成員的特點

? 結構中的柔性數組成員前面必須至少一個其他成員。

? sizeof 返回的這種結構大小不包括柔性數組的內存。

? 包含柔性數組成員的結構用malloc ()函數進行內存的動態分配,并且分配的內存應該大于結構的大小,以適應柔性數組的預期大小。

5.2 柔性數組的使用

以malloc函數為例,柔性數組的使用依舊遵循上述的五個步驟,不同的是要先創建一個結構體

1. 開辟 2.訪問 3.擴容 4.使用 5.釋放

struct st
{
?? ?char c;
?? ?int n;
?? ?int arr[0];
};


int main()
{
?? ?struct st* ps = (struct st*)malloc(sizeof(struct st) + 10 * sizeof(int));//1.開辟
?? ?//前面的sizeof(struct st)是計算此結構體本來的大小
?? ?//后面的 10 * sizeof(int) 意思是將柔性數組成員開辟成多少大小的

?? ?if (ps == NULL)
?? ?{
?? ??? ?perror("malloc");
?? ??? ?return 1;
?? ?}

?? ?ps->c = 'w';//2.訪問
?? ?ps->n = 100;
?? ?int i = 0;
?? ?for (i = 0; i < 10; i++)
?? ?{
?? ??? ?ps->arr[i]=i;//也可以這么寫 QUESTION2;點操作符和箭頭操作符的區別,在那些情況下一般用什么的總結歸納
?? ?}

?? ?struct st* ptr = (struct st*)realloc(ps, sizeof(struct st) + 15 * sizeof(int));//3.擴容
?? ?if (ptr != NULL)?
?? ?{
?? ??? ?ps = ptr;
?? ?}
?? ?else
?? ?{
?? ??? ?perror("realloc");
?? ??? ?return 1;
?? ?}

?? ?for (i = 0; i < 10; i++)//4.使用
?? ?{
?? ??? ?printf("%d ", i);
?? ?}
?? ?printf("\n");
?? ??? ?printf("%c \n", ps->c);
?? ??? ?printf("%d \n", ps->n);


?? ?free(ps);//5.釋放
?? ?ps = NULL;
?? ?return 0;
}

ps:"->"操作符和"."(點)操作符的使用

1.點操作符的使用情況

直接使用

? struct st
{
?? ?int a;
?? ?int b;
};
int main1()
{
?? ?struct st s = { .a = 10 , .b=20 };
?? ?printf("%d %d ", s.a, s.b);
?? ?return 0;
}

2.->的使用情況

由柔性數組的實例情況使用可知,在"結構體+指針"的情況下如果要使用指針對結構體中某一個成員變量進行訪問,那么就是"指針->結構體塵緣變量名=程序員想要賦的值".

封面如下

 

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/209635.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/209635.shtml
英文地址,請注明出處:http://en.pswp.cn/news/209635.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

12.ROS導航模塊:gmapping、AMCL、map_server、move_base案例

目錄 1 導航概述 2 導航簡介 2.1 導航模塊簡介 1.全局地圖 2.自身定位 3.路徑規劃 4.運動控制 5.環境感知 2.2 導航坐標系odom、map 1.簡介 2.特點 3.坐標系變換 2.3 導航條件說明 1.硬件 2.軟件 3 導航實現 3.1 創建本篇博客的功能包 3.2 建圖--gmapping 3.…

JavaScript基礎知識整理(最全知識點, 精簡版,0基礎版)

文章目錄 一、輸入和輸出內容 1.1 輸出 1.1.1 在瀏覽器的控制臺輸出打印 1.1.2 直接在瀏覽器的頁面上輸出內容 1.1.3 頁面彈出警告對話框 1.2 輸入 二、變量 2.1 變量是什么 2.2 變量的聲明和賦值 2.3 變量的命名規范和規范 三、變量擴展&#xff08;數組&#xff09; 3.1 數組…

Cypress:前端自動化測試的終極利器

引言&#xff1a; 在現代軟件開發中&#xff0c;前端自動化測試已經成為了一個不可或缺的環節。它不僅可以提高開發效率&#xff0c;減少手動測試的工作量&#xff0c;還可以保證軟件的穩定性和質量。而在眾多的前端自動化測試工具中&#xff0c;Cypress無疑是其中的佼佼者。本…

openGauss學習筆記-144 openGauss 數據庫運維-例行維護-慢sql診斷

文章目錄 openGauss學習筆記-144 openGauss 數據庫運維-例行維護-慢sql診斷144.1 背景信息144.2 前提條件 openGauss學習筆記-144 openGauss 數據庫運維-例行維護-慢sql診斷 144.1 背景信息 在SQL語句執行性能不符合預期時&#xff0c;可以查看SQL語句執行信息&#xff0c;便…

文章解讀與仿真程序復現思路——中國電機工程學報EI\CSCD\北大核心《考慮垃圾處理與調峰需求的可持續化城市多能源系統規劃》

這個標題涵蓋了城市多能源系統規劃中的兩個重要方面&#xff1a;垃圾處理和調峰需求&#xff0c;并強調了規劃的可持續性。 考慮垃圾處理&#xff1a; 含義&#xff1a; 垃圾處理指的是城市廢棄物的管理和處置。這可能涉及到廢物分類、回收利用、焚燒或填埋等方法。重要性&…

GIS入門,Leaflet介紹,Leaflet可以做什么,網頁中如何使用Leaflet地圖,vue中如何使用Leaflet地圖

VueLeafLet教程推薦&#xff1a;《VueLeaflet入門》 Leaflet介紹 Leaflet是一個開源的JavaScript庫&#xff0c;用于創建交互式的地圖和地圖應用。Leaflet框架具有輕量級、靈活性強、易于使用和擴展等特點&#xff0c;支持各種地圖服務商&#xff08;如OpenStreetMap、Google…

前端知識筆記(三十八)———HTTPS:保護網絡通信安全的關鍵

當談到網絡通信和數據傳輸時&#xff0c;安全性是一個至關重要的問題。在互聯網上&#xff0c;有許多敏感信息需要通過網絡進行傳輸&#xff0c;例如個人身份信息、銀行賬戶信息和商業機密等。為了保護這些信息不被未經授權的人訪問和篡改&#xff0c;HTTPS&#xff08;超文本傳…

【開源】基于Vue+SpringBoot的河南軟件客服系統

文末獲取源碼&#xff0c;項目編號&#xff1a; S 067 。 \color{red}{文末獲取源碼&#xff0c;項目編號&#xff1a;S067。} 文末獲取源碼&#xff0c;項目編號&#xff1a;S067。 目錄 一、摘要1.1 項目介紹1.2 項目錄屏 二、功能模塊2.1 系統管理人員2.2 業務操作人員 三、…

搞懂內存函數

引言 本文介紹memcpy的使用和模擬實現、memmove的使用和模擬實現、memcmp使用、memset使用 ? 豬巴戒&#xff1a;個人主頁? 所屬專欄&#xff1a;《C語言進階》 &#x1f388;跟著豬巴戒&#xff0c;一起學習C語言&#x1f388; 目錄 引言 memcpy memcpy的使用 memcpy的…

JS加密/解密之HOOK實戰2

上一篇文章介紹了HOOK常規的應用場景&#xff0c;這篇我們講一下HOOK其他原生函數。又是一個新的其他思路 很多時候&#xff0c;當我們想要某些網站的請求參數的時候&#xff0c;因為某些加密導致了獲取起來很復雜。 這時候hook就十分方便了 源代碼 var _JSON_Parse JSON.…

scp 指令詳細介紹

目錄 1. 基本語法 2. 例子 從本地到遠程 從遠程到本地 從遠程到遠程 使用端口和指定私鑰 遞歸復制目錄 3. 注意事項 如何拷貝文件的軟鏈接 SCP&#xff08;Secure Copy Protocol&#xff09;是一種用于在計算機之間安全地傳輸文件的協議。它通過加密的方式在網絡上安全…

Vue:Vue的開發者工具不顯示Vue實例中的data數據

一、情況描述 代碼&#xff1a; 頁面&#xff1a; 可以看到&#xff0c;input獲取到了data數據&#xff0c;但是&#xff0c;vue-devtool沒有獲取到data數據 二、解決辦法 解決辦法1&#xff1a; data.name的值不能全是中文&#xff0c;比如改成aa尚硅谷 解決辦法2&…

C語言 編程題

C語言學習&#xff01; 1.小明上課需要走n階臺階&#xff0c;他每次可以選擇走一階或者走兩階&#xff0c;他一共有多少種走法&#xff1f; 輸入描述&#xff1a;輸入包含一個整數n&#xff08;1 ≤ n ≤30&#xff09; 輸出描述&#xff1a;輸出一個整數&#xff0c;即小明可…

LeetCode 1457. 二叉樹中的偽回文路徑||位運算 DFS

1457. 二叉樹中的偽回文路徑 給你一棵二叉樹&#xff0c;每個節點的值為 1 到 9 。我們稱二叉樹中的一條路徑是 「偽回文」的&#xff0c;當它滿足&#xff1a;路徑經過的所有節點值的排列中&#xff0c;存在一個回文序列。 請你返回從根到葉子節點的所有路徑中 偽回文 路徑的…

Golang優雅實現按比例切分流量

我們在進行灰度發布時&#xff0c;往往需要轉發一部分流量到新上線的服務上&#xff0c;進行小規模的驗證&#xff0c;隨著功能的不斷完善&#xff0c;我們也會逐漸增加轉發的流量&#xff0c;這就需要按比例去切分流量&#xff0c;那么如何實現流量切分呢&#xff1f; 我們很容…

力扣(LeetCode)-1. 兩數之和

給定一個整數數組 nums 和一個整數目標值 target&#xff0c;請你在該數組中找出 和為目標值 target 的那 兩個 整數&#xff0c;并返回它們的數組下標。 你可以假設每種輸入只會對應一個答案。但是&#xff0c;數組中同一個元素在答案里不能重復出現。 你可以按任意順序返回…

【交流】PHP生成唯一邀請碼

目錄 前言&#xff1a; 1.隨機生成&#xff0c;核對user表是否已存在 代碼&#xff1a; 解析&#xff1a; 缺點&#xff1a; 2.建表建庫&#xff0c;每次從表中隨機抽取一條&#xff0c;用完時擴充 表結構 表視圖 代碼 解析 缺點 結論&#xff1a; 前言&#xff1a; …

LinuxBasicsForHackers筆記 -- 壓縮和歸檔

壓縮分為有損或無損。有損壓縮對于減小文件大小非常有效&#xff0c;但會丟失信息的完整性。換句話說&#xff0c;壓縮后的文件與原始文件并不完全相同。 這種類型的壓縮非常適合圖形、視頻和音頻文件&#xff0c;文件中的微小差異幾乎不會被注意到。 本章重點介紹這種無損壓縮…

解讀Stable Video Diffusion:詳細解讀視頻生成任務中的數據清理技術

Diffusion Models視頻生成-博客匯總 前言:Stable Video Diffusion已經開源一周多了,技術報告《Stable Video Diffusion: Scaling Latent Video Diffusion Models to Large Datasets》對數據清洗的部分描述非常詳細,雖然沒有開源源代碼,但是博主正在嘗試復現其中的操作。這篇…

醫學影像PACS信息化數字平臺源碼

PACS系統對醫院影像科意義重大&#xff0c;將業務量巨大的影像檢驗流程依托于信息化技術&#xff0c;對于進行信息化建設的醫院而言&#xff0c;是十分必要的。 PACS系統源碼&#xff0c;集成三維影像后處理功能&#xff0c;包括三維多平面重建、三維容積重建、三維表面重建、三…