C語言之動態內存管理(malloc calloc realloc)

C語言之動態內存管理

文章目錄

  • C語言之動態內存管理
    • 1. 為什么要有動態內存管理
    • 2. malloc 和 free
      • 2.1 malloc
      • 2.2 free
      • 2.3 例子
    • 3. calloc 和 realloc
      • 3.1 calloc
      • 3.2 realloc
    • 4. 常見的動態內存錯誤
      • 4.1 對NULL指針的解引?操作
      • 4.2 對動態開辟空間的越界訪問
      • 4.3 對?動態開辟內存使?free釋放
      • 4.4 使?free釋放?塊動態開辟內存的?部分
      • 4.5 對同?塊動態內存多次釋放
      • 4.6 動態開辟內存忘記釋放(內存泄漏)
    • 5. 總結

1. 為什么要有動態內存管理

我們已經掌握的內存開辟?式有:

#include <stdio.h>int main()
{int val = 20;int arr[10] = { 0 };return 0;
}

上述的開辟空間的?式有兩個特點
? 空間開辟大小是固定的

?數組在申明的時候,必須指定數組的?度,數組空間?旦確定了??不能調整

所以C語?引?了動態內存開辟,讓程序員??可以申請和釋放空間

2. malloc 和 free

mallocfree函數都是在stdlib.h頭文件中聲明的

2.1 malloc

C語言中提供了一個動態內存開辟的函數:

void* malloc (size_t size);

其中size為要開辟的內存空間的大小,單位為字節

這個函數向內存申請?塊連續可?的空間,并返回指向這塊空間的指針

?如果開辟成功,則返回一個指向開辟好的內存空間的指針
?如果開辟失敗,則返回一個NULL指針
?返回類型為void *,因為malloc函數不知道要開辟什么類型的內存空間,只知道要開辟的大小
?如果參數為0,malloc函數的行為標準是未定義的,取決于編譯器

2.2 free

C語言還提供了一個的函數,專門用來做動態內存的釋放和回收的:

void free (void* ptr);

ptr為要釋放內存空間的指針

?如果參數ptr指向的內存空間不是動態開辟的,那么free函數的行為是未定義的
?如果參數ptrNULL,則函數什么都不做

如果不對malloc calloc realloc 開辟的空間進行釋放,即使出了作用域也不會銷毀,有可能導致內存泄漏

釋放的方式
1. free
2. 直到程序結束,由操作系統釋放

2.3 例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)malloc(10 * sizeof(int)); //開辟40個字節的空間//判斷是否為NULL指針if (p == NULL){perror("malloc fail\n"); //perror為錯誤信息打印return 1;}//使用int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;//*p = i;   //如果使用這種方法,p指針向后走了,在下面打印時,就找不到首元素的地址了//p++;}//打印for (i = 0; i < 10; i++){printf("%d ", *(p + i));}free(p);  //釋放p = NULL; //將指針置NULL,如果不置NULL,下面解引用p時,p就是野指針return 0;
}

代碼運行結果:>
0 1 2 3 4 5 6 7 8 9

malloc開辟空間時,是不會給空間初始化的,如果直接打印,會打印出隨機值

3. calloc 和 realloc

3.1 calloc

C語?還提供了?個函數叫 calloccalloc 函數也?來動態內存分配

void* calloc (size_t num, size_t size);

num為要開辟的元素個數
size為開辟元素的元素大小,單位為字節

?calloc為開辟num個大小為size元素的內存空間,并且將內存中每個字節初始化為0
?calloc的使用方法和malloc一樣,主要區別在于calloc會初始化元素

例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)calloc(10 ,sizeof(int));//判斷是否為NULL指針if (p == NULL){perror("calloc fail\n");return 1;}int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}return 0;
}

代碼運行結果:>
0 0 0 0 0 0 0 0 0 0

3.2 realloc

C語言中有一個函數用來調整動態內存開辟后的大小

void* realloc (void* ptr, size_t size);

ptr為要調整的內存地址
size為調整后的內存大小

? realloc函數的出現讓動態內存管理更加靈活
? 當我們發現我們使用malloc calloc realloc申請的內存空間不夠時,我們可以使用realloc進行擴容

?返回值為調整之后的內存的起始位置(不一定是原內存地址)
?如果開辟失敗則返回一個NULL
?如果開辟成功則分以下兩個情況:

情況1:原有空間之后有?夠?的空間
情況2:原有空間之后沒有?夠?的空間

在這里插入圖片描述

情況1:在原有內存后邊直接追加空間,原來的空間的數據不變
情況2:原有內存之后的空間不足以最加空間,那么realloc會在堆區中找到一塊足夠開辟新大小的空間,將舊空間中的數據拷貝到新空間,并且將舊空間釋放,同時返回新空間起始位置的地址

realloc的用法除了為開辟的內存進行擴容,也可以和malloc一樣

例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)malloc(10 * sizeof(int));//判斷是否為NULL指針if (p == NULL){perror("malloc fail\n");return 1;}int* tmp = (int*)realloc(p, 100*sizeof(int));if (tmp != NULL){p = tmp;}else{perror("relloc fail\n");return 1;}//使用//..........free(p);p = NULL;return 0;
}

在這里插入圖片描述
這次的運行結果就是情況2(開辟100個字節的大小時,可能會出現),當后面的空間不夠時, realloc就會找一塊新的空間
在這里插入圖片描述
這次只開辟了40個字節的空間,屬于情況1,后面的空間足夠時, realloc會直接在后面追加空間

4. 常見的動態內存錯誤

4.1 對NULL指針的解引?操作

#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(40);*p = 20; //如果malloc開辟空間失敗,p可能是NULL,此時p為野指針return 0;
}

在VS2022中,編譯器會進行提示,我們得對可能出現NULL的情況進行處理
在這里插入圖片描述

在使用malloc calloc realloc開辟空間時,最好對返回值進行判斷,當不為NULL再使用

4.2 對動態開辟空間的越界訪問

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}int i = 0;for (i = 0; i <= 10; i++)  //只有10個元素的空間,卻訪問了第11個元素,訪問越界了{*(p + i) = i;}free(p);p = NULL;return 0;
}

在這里插入圖片描述

4.3 對?動態開辟內存使?free釋放

#include <stdio.h>
#include <stdlib.h>int main()
{int a = 10;int* p = &a;free(p);return 0;
}

在這里插入圖片描述

當用free釋放了不是由malloc calloc realloc開辟的空間時,就會報錯

4.4 使?free釋放?塊動態開辟內存的?部分

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int a = 10;int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}//使用//......p++;free(p);p = NULL;return 0;
}

在這里插入圖片描述
當用free釋放了開辟空間的一部分時,就會報錯

4.5 對同?塊動態內存多次釋放

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int a = 10;int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}//使用//......free(p);free(p);p = NULL;return 0;
}

在這里插入圖片描述
對一塊動態開辟的內存進行多次free釋放

在上述代碼中如果free釋放NULL,則沒有問題,因為free的參數為NULL時,則什么都不做

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{int a = 10;int* p = (int*)malloc(40);if (p == NULL){perror("malloc fail\n");return 1;}//使用//......free(p);p = NULL;free(p);p = NULL;return 0;
}

4.6 動態開辟內存忘記釋放(內存泄漏)

#include <stdio.h>
#include <stdlib.h>void test()
{int* p = (int*)malloc(100);if (p != NULL){*p = 20;}
}
int main()
{test();while (1); //死循環,讓程序不結束return 0;
}

當動態開辟的內存不釋放時,就會一存在,在上述代碼中,調用了test函數,開辟了100個字節的空間,同時賦值,出函數時,p被銷毀了,但是開辟的空間并沒有被銷毀,沒人可以使用,也沒人可以釋放,就會導致內存泄漏

5. 總結

一丶
在使用malloc calloc realloc開辟的空間時,要對其進行判斷,當不為NULL的再進行使用
二丶
當不使用動態開辟的內存時,將其free釋放,同時將指針置NULL,防止可能出現的內存泄露和野指針
三丶
不對不是動態開辟的空間free,不連續對動態開辟的空間free,同時free動態開辟的空間時,要給開辟的起始地址,不能free部分空間

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

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

相關文章

女裝品牌網站建設的作用如何

服裝是任何人都需要的必備品&#xff0c;尤其是女裝&#xff0c;由于女性群體愛美追求時尚的心理更高&#xff0c;因此市場中有大量女裝品牌以及大量消費者&#xff0c;其規模非常高&#xff0c;眾多大小品牌林立及消費征集下&#xff0c;商家們經營也并不太容易&#xff0c;企…

Themis: Fast, Strong Order-Fairness in Byzantine Consensus

目錄 筆記后續的研究方向摘要引言秩序井然 Themis: Fast, Strong Order-Fairness in Byzantine Consensus CCS 2023 筆記 后續的研究方向 摘要 我們介紹了Themis&#xff0c;這是一種將交易的公平排序引入&#xff08;許可的&#xff09;拜占庭共識協議的方案&#xff0c;最…

參加百度Apollo技術沙龍—感受自動駕駛的魅力

2023年12月2日下午2點&#xff0c;我有幸參加了百度Apollo技術沙龍&#xff0c;這是一個圍繞Apollo新版本Beta的全面升級展開的深度交流活動。作為一名工程師&#xff0c;我深感榮幸能夠與眾多同行和專家一同探討自動駕駛技術的快速發展 在這次沙龍中&#xff0c;我了解到Apo…

Python:核心知識點整理大全7-筆記

目錄 4.2.5 遺漏了冒號 4.3 創建數值列表 4.3.1 使用函數 range() 4.3.2 使用 range()創建數字列表 結果如下&#xff1a; 4.3.3 對數字列表執行簡單的統計計算 4.3.4 列表解析 4.4 使用列表的一部分 4.4.1 切片 4.4.2 遍歷切片 4.4.3 復制列表 4.2.5 遺漏了冒號 fo…

使用vue-quill-editor(富文本框)禁用粘貼圖片

問題描述&#xff1a;富文本框復制粘貼未走上傳圖片接口&#xff0c;會將復制的圖片解析為base64編碼&#xff0c;為了控制這種情況可選擇禁用粘貼圖片&#xff0c;或者監聽有復制粘貼的圖片走上傳圖片接口 獲取到 quill 對象&#xff0c;可以通過 refs 或者 Quill 對象的 getI…

小程序自動更新功能

小程序自動更新功能 在 .vue 頁面的 script 中添加生命周期&#xff0c;在生命周期內監聽頁面信息 onLoad onLoad(options) {this.getUserInfo()this.intervalId setInterval(() > {this.getUserInfo()}, 3000);},onUnload onUnload: function() {// 在頁面卸載時清除定時…

vue的data

類型&#xff1a;Object | Function 限制&#xff1a;組件的定義只接受 function。 詳細&#xff1a; Vue 實例的數據對象。Vue 會遞歸地把 data 的 property 轉換為 getter/setter&#xff0c;從而讓 data 的 property 能夠響應數據變化。對象必須是純粹的對象 (含有零個或多個…

DC電源模塊與節能環保的關系

BOSHIDA DC電源模塊與節能環保的關系 隨著全球能源危機的加劇&#xff0c;環保節能已經成為世界各國政府和企業發展的主要方向。在電子行業中&#xff0c; DC電源模塊的出現為環保節能做出了貢獻。DC電源模塊是一種電源供應器件&#xff0c;可將高電壓轉換為低電壓&#xff0c;…

柏林噪聲C++

柏林噪聲 隨機噪聲 如上圖所示隨機噪聲沒有任何規律可言&#xff0c;我們希望生成有一些意義的局部連續的隨機圖案 一維柏林噪聲 假設希望生成一段局部連續的隨機曲線&#xff0c;可以采用插值的方式&#xff1a;在固定點隨機分配y值&#xff08;一般是整數點&#xff09;&a…

【數據分析實戰】酒店行業華住集團門店分布與評分多維度分析

文章目錄 1. 寫在前面2. 數據集展示3. 多維度分析3.1 門店檔次多元化&#xff1a;集團投資戰略觀察3.1.1 代碼實現3.1.2 本人淺薄理解 3.2 門店分布&#xff1a;各省市分布概覽3.2.1 代碼實現3.2.2 本人淺薄理解 3.3 門店分級評分&#xff1a;服務水平的多維度觀察3.3.1 代碼實…

F5怎么樣?從負載均衡到云原生的進階之路

從Web時代開始至云原生時代的應用服務交付的市場&#xff0c;技術與人的變化就是關注的焦點。從單純的Web負載均衡到復雜的企業應用交付&#xff0c;從單體應用到分布式、微服務架構&#xff0c;F5為企業技術架構更好、更優、更安全的運行做出了極大的努力。那么F5怎么樣&#…

Vue 循環走馬燈

1、使用 transform: translateX()&#xff0c;循環將滾動內容在容器內偏移&#xff0c;超出容器部分隱藏&#xff1b; 2、避免滾動到末尾時出現空白&#xff0c;需要預留多幾個。 3、一次循環偏移的距離scrollLoopWidth 可能受樣式影響需要做些微調&#xff0c;比如單個item的…

題目:分糖果(藍橋OJ 2928)

題目描述&#xff1a; 解題思路&#xff1a; 本題采用貪心思想 圖解 題解&#xff1a; #include<bits/stdc.h> using namespace std;const int N 1e6 9; char s[N];//寫字符串數組的一種方法,像數組一樣***int main() {int n, x;cin >> n >> x;for(int …

CSS新手入門筆記整理:元素類型相互轉換

元素類型 塊元素&#xff08;block&#xff09; 獨占一行&#xff0c;排斥其他元素跟其位于同一行&#xff0c;包括塊元素和行內元素。塊元素內部可以容納其他塊元素和行內元素。可以定義 width&#xff0c;也可以定義 height。可以定義 4 個方向的 margin。 行內元素&#xf…

使用navicat(或者其他數據庫管理工具)、powerdesigner導出數據字典

適合先有數據庫結構&#xff0c;后需要導出數據字典的情況&#xff0c;多數在發開完成交文檔或者用戶有庫的情況下 有條件的話推薦用powerdesigner導出&#xff0c;比較好看 如果用powerdesigner導出的注釋不對&#xff0c;是因為數據庫的編碼不對 1、使用navicat導出 在該數…

代碼隨想錄算法訓練營第45天| 70. 爬樓梯 (進階) 322. 零錢兌換 279.完全平方數

JAVA代碼編寫 70. 爬樓梯&#xff08;進階版) 卡碼網&#xff1a;57. 爬樓梯&#xff08;第八期模擬筆試&#xff09; 題目描述 假設你正在爬樓梯。需要 n 階你才能到達樓頂。 每次你可以爬至多m (1 < m < n)個臺階。你有多少種不同的方法可以爬到樓頂呢&#xff1f…

菜鳥學習日記(python)——推導式

python中的推導式是一種獨特的數據處理方式&#xff0c;可以從一個數據序列去構建另一個新的數據序列的結構體。 它包括以下推導式&#xff1a; 列表&#xff08;list&#xff09;推導式字典&#xff08;dict&#xff09;推導式集合&#xff08;set&#xff09;推導式元組&am…

Multi-Cell Downlink Beamforming: Direct FP, Closed-Form FP, Weighted MMSE

這里寫自定義目錄標題 Direct FPClosed-Form FPthe Lagrangian functionthe Lagrange dual function: maximizing the Lagrangianthe Lagrange dual problem: minimizing the Lagrange dual functionClosed-Form FP Weighted MMSE原論文 Lagrange dual5.1.1 The Lagrangian5.1.…

阿里云服務器經濟型、通用算力型、計算型、通用型、內存型實例區別及選擇參考

當我們通過阿里云的活動購買云服務器會發現&#xff0c;相同配置的云服務器往往有多個不同的實例可選&#xff0c;而且價格差別也比較大&#xff0c;例如同樣是4核8G的配置的云服務器&#xff0c;經濟型e實例活動價格只要1500.48/1年起&#xff0c;通用算力型u1實例要1795.97/1…

nvidia安裝出現7-zip crc error解決辦法

解決辦法&#xff1a;下載network版本&#xff0c;重新安裝。&#xff08;選擇自己需要的版本&#xff09; 網址&#xff1a;CUDA Toolkit 12.3 Update 1 Downloads | NVIDIA Developer 分析原因&#xff1a;local版本的安裝包可能在下載過程中出現損壞。 本人嘗試過全網說的…