《C語言深度解剖》(15):動態內存管理和柔性數組

🤡博客主頁:醉竺

🥰本文專欄:《C語言深度解剖》

😻歡迎關注:感謝大家的點贊評論+關注,祝您學有所成!


??💜💛想要學習更多C語言深度解剖點擊專欄鏈接查看💛💜???


目錄

1. 為什么存在動態內存分配

2. 動態內存函數?

2.1 malloc和free?

2.2 calloc?

2.3 realloc?

3. 常見的動態內存錯誤?

3.1 對NULL指針的解引用操作

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

3.3 對非動態開辟內存使用free釋放?

3.4 使用free釋放一塊動態開辟內存的一部分?

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

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

4. 幾個經典的筆試題?

5. C/C++程序的內存開辟?

6. 柔性數組

6.1 柔性數組的特性:?

6.2 柔性數組的使用?

6.3 柔性數組的優勢?


1. 為什么存在動態內存分配

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

int val = 20;//在棧空間上開辟四個字節
char arr[10] = { 0 };//在棧空間上開辟10個字節的連續空間

但是上述的開辟空間的方式有兩個特點:

  1. 空間開辟大小是固定的。
  2. 數組在申明的時候,必須指定數組的長度,它所需要的內存在編譯時分配。

但是對于空間的需求,不僅僅是上述的情況。有時候我們需要的空間大小在程序運行的時候才能知道, 那數組的編譯時開辟空間的方式就不能滿足了。 這時候就只能動態內存開辟了。?

2. 動態內存函數?

2.1 malloc和free?

void* malloc (size_t size);

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

  • 如果開辟成功,則返回一個指向開辟好空間的指針。
  • 如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
  • 返回值的類型是 void* ,所以malloc函數并不知道開辟空間的類型,具體在使用的時候使用者自己 來決定。
  • 如果參數 size 為0,malloc的行為是標準是未定義的,取決于編譯器。?

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

void free (void* ptr);

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

  • 如果參數 ptr 指向的空間不是動態開辟的,那free函數的行為是未定義的。
  • 如果參數 ptr 是NULL指針,則函數什么事都不做。

malloc和free都聲明在 stdlib.h 頭文件中。

舉個例子:?

  • 在釋放內存之后將指針置為 NULL 是一個良好的編程習慣,但并不是強制性的。然而,這個做法可以提供額外的保護,防止懸空指針(dangling pointer)的問題。
  • 懸空指針是指向已經釋放的內存的指針。如果指針在釋放后沒有被置為 NULL,那么它仍然包含一個地址,這個地址可能不再有效,因為釋放的內存可能已經被重新分配給其他用途。如果懸空指針被錯誤地解引用,可能會導致未定義行為,包括程序崩潰、數據損壞或安全漏洞。
  • 將指針置為 NULL 可以防止懸空指針被解引用,因為解引用 NULL 指針通常會導致程序立即崩潰,這樣開發者可以立即發現問題并修復它,而不是面對更難以追蹤的未定義行為。

2.2 calloc?

C語言還提供了一個函數叫 calloc , calloc 函數也用來動態內存分配。原型如下:?

void *calloc(size_t num, size_t size);
  • num:要分配的內存塊的數量。
  • size:每個內存塊的大小,以字節為單位。
  • 函數的功能是為 num 個大小為 size 的元素開辟一塊空間,并且把空間的每個字節初始化為0。
  • 與函數 malloc 的區別只在于 calloc 會在返回地址之前把申請的空間的每個字節全初始化為0。?
#include <stdio.h>
#include <stdlib.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (NULL != p){//使用空間}free(p);p = NULL;return 0;
}

所以如何我們對申請的內存空間的內容要求初始化,那么可以很方便的使用calloc函數來完成任務。

2.3 realloc?

  • realloc函數的出現讓動態內存管理更加靈活。
  • 有時會我們發現過去申請的空間太小了,有時候我們又會覺得申請的空間過大了,那為了合理的時 候內存,我們一定會對內存的大小做靈活的調整。那 realloc 函數就可以做到對動態開辟內存大小 的調整。

函數原型如下:

void* realloc (void* ptr, size_t size);
  • ptr 參數是一個指向之前分配的內存塊的指針。
  • size 參數指定了新的內存塊大小,以字節為單位。
  • 返回值:realloc 函數嘗試改變 ptr 指向的內存塊的大小為 size 字節。如果重新分配成功,它返回一個指向新分配內存塊的指針,這個指針可能與 ptr 相同(如果原地擴大成功),也可能不同(如果需要移動數據到新的位置)。如果失敗,它返回 NULL,并且原始內存塊保持不變?,不會釋放。

realloc在調整內存空間(下面演示的是擴大空間)時存在兩種情況:

情況1:原有空間之后有足夠大的空間

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

情況1:當是情況1的時候,擴展內存是在原有內存之后直接追加空間,realloc 函數重新申請空間之后,返回的地址還是原始空間的起始地址,?原來空間的數據部沒發生變化。如果新大小大于舊大小,超出舊大小部分的數據是未初始化的。

情況2:當是情況2的時候,原有空間之后沒有足夠的空間擴容。此時擴展的方法:在堆空間上另外找一個滿足大小的連續空間,并把舊空間的數據拷貝到新空間,然后釋放舊的空間,返回新空間的起始地址。

#include <stdio.h>
#include <stdlib.h>
int main() {int* ptr;int old_size = 5;int new_size = 10;// 分配一個整數數組的空間ptr = (int*)malloc(old_size * sizeof(int));if (ptr == NULL) {fprintf(stderr, "Initial memory allocation failed\n");return 1;}// 使用分配的內存for (int i = 0; i < old_size; i++) {ptr[i] = i;}// 重新分配內存以增加數組大小int* new_ptr = (int*)realloc(ptr, new_size * sizeof(int));if (new_ptr == NULL) {fprintf(stderr, "Memory reallocation failed\n");free(ptr); // 釋放原有內存return 1;}// 更新指針并使用新分配的內存ptr = new_ptr;for (int i = old_size; i < new_size; i++) {ptr[i] = i;}// 打印數組元素for (int i = 0; i < new_size; i++) {printf("%d ", ptr[i]);}printf("\n");// 釋放內存free(ptr);return 0;
}

3. 常見的動態內存錯誤?

3.1 對NULL指針的解引用操作

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

3.3 對非動態開辟內存使用free釋放?

3.4 使用free釋放一塊動態開辟內存的一部分?

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

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

忘記釋放不再使用的動態開辟的空間會造成內存泄漏。

切記: 動態開辟的空間一定要釋放,并且正確釋放 。?


4. 幾個經典的筆試題?

4.1 題目1:?

請問運行Test 函數會有什么樣的結果???

4.2 題目2:?

請問運行Test 函數會有什么樣的結果??

4.3 題目3:?

請問運行Test 函數會有什么樣的結果??

4.4 題目4:?

請問運行Test 函數會有什么樣的結果??


5. C/C++程序的內存開辟?

C/C++程序內存分配的幾個區域:?

1. 棧區(stack):在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結 束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是 分配的內存容量有限。 棧區主要存放運行函數而分配的局部變量、函數參數、返回數據、返 回地址等。

2. 堆區(heap):一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。分 配方式類似于鏈表。

3. 數據段(靜態區):(static)存放全局變量、靜態數據。程序結束后由系統釋放。

4. 代碼段:存放函數體(類成員函數和全局函數)的二進制代碼。?

有了這幅圖,我們就可以更好的理解在 static關鍵字修飾局部變量的例子了。

實際上普通的局部變量是在棧區分配空間的,棧區的特點是在上面創建的變量出了作用域就銷毀。 但是被static修飾的變量存放在數據段(靜態區),數據段的特點是在上面創建的變量,直到程序 結束才銷毀 所以生命周期變長。?


6. 柔性數組

C語言中的柔性數組(Flexible Array Member, FAM)是C99標準引入的一個特性,它允許結構體的最后一個成員是一個大小未指定的數組,這為處理可變長度數據結構提供了一種高效而靈活的方式。?

例如:

有些編譯器會報錯無法編譯可以改成:

6.1 柔性數組的特性:?

  • 位置要求:柔性數組必須是結構體的最后一個成員。這是因為它不占用結構體本身的空間,而是緊隨結構體之后分配內存。
  • 內存分配:雖然聲明時數組長度為0(如int a[0]或直接int a[]),但實際使用時,會通過動態內存分配為它分配足夠的空間以容納實際需要的元素數量。
  • 內存對齊:柔性數組不會影響結構體的自然對齊,因此在計算結構體大小時,柔性數組不計入。這有助于高效地利用內存。
  • 便捷的內存管理:由于柔性數組與結構體主體連續存儲,只需要一次內存分配即可為結構體和其后的柔性數組分配空間,這簡化了內存管理,尤其是在需要同時釋放結構體和數組時。
  • 優化訪問速度:連續的內存布局有利于CPU緩存,提高數據訪問效率。

例如:

6.2 柔性數組的使用?

這樣柔性數組成員a,相當于獲得了100個整型元素的連續空間。?

6.3 柔性數組的優勢?

上述的 type_a 結構也可以設計為:?

上述 代碼1代碼2 可以完成同樣的功能,但是更推薦?方法1?,方法1的好處:?

擴展閱讀:

C語言結構體里的數組和指針

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

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

相關文章

k8s中的集群調度

文章目錄 k8s中的集群調度Pod 創建流程 通過指定節點來創建pod所在的node節點通過標簽來指定pod創建在哪個節點上pod 的親和性Pod的親和性和反親和性親和性&#xff08;Affinity&#xff09;反親和性&#xff08;Anti-Affinity&#xff09; 污點與容忍污點&#xff08;Taint&am…

Spring Cache入門詳解

一、概述 1.1緩存介紹 Spring提供了一套cache緩存抽象(注解/接口)&#xff0c;使基于spring緩存的使用與實現解耦 默認實現&#xff0c;Spring JDK ConcurrentMap-based Cache第三方實現&#xff0c;caffeine/Ehcache/Redis等 https://docs.spring.io/spring-framework/do…

Postman快捷功能-快速填寫請求頭

大家好&#xff0c;之前給大家分享關于 Postman 工具的基礎使用&#xff0c;今天給大家介紹一個快捷功能&#xff0c;可以一定程度提高我們使用 Postman 工具的效率&#xff0c;在我們進行接口測試時&#xff0c;幾乎每個接口都需要填寫 Headers&#xff0c;且 Headers 中的參數…

【ai】livekit服務本地開發模式2:模擬1個發布者

是一個會議用軟件:LiveKit is an open source project that provides scalable, multi-user conferencing based on WebRTC. It’s designed to provide everything you need to build real-time video audio data capabilities in your applications.LiveKit’s server is wr…

【Python】 Django 框架如何支持百萬級日訪問量

基本原理 Django 是一個高級的 Python Web 框架&#xff0c;它鼓勵快速開發和干凈、實用的設計。Django 遵循 MVC&#xff08;模型-視圖-控制器&#xff09;設計模式&#xff0c;允許開發者通過編寫更少的代碼來構建高質量的 Web 應用程序。Django 自帶了許多內置功能&#xf…

發現沒:隨便搞個B端頁面,就想在客戶那里過關,難啦。

客戶對B端界面要求越來越高的原因可以有以下幾點&#xff1a; 用戶體驗要求提升&#xff1a;隨著用戶對移動應用和網頁的使用經驗增加&#xff0c;他們對于界面的交互、流暢性和易用性要求也越來越高。他們希望能夠在使用B端應用時&#xff0c;能夠快速、方便地完成任務&#…

2024年華為OD機試真題-文本統計分析-C++-OD統一考試(C卷D卷)

題目描述: 有一個文件, 包含以一定規則寫作的文本, 請統計文件中包含的文本數量 規則如下 1. 文本以";"分隔,最后一條可以沒有";",但空文本不能算語句,比如"COMMAND A; ;"只能算一條語句. 注意, 無字符/空白字符/制表符都算作"空&qu…

設計模式詳解(六):適配器模式——Adapter

目錄導航 適配器模式及其作用現實生活舉例 適配器模式的好處適配器模式的實現關系圖實現步驟 適配器模式的適用場景適配器模式示例 適配器模式及其作用 適配器模式是一種結構型設計模式。所謂結構型是指在代碼結構方面的設計模式。適配器模式作為中間層&#xff0c;可以讓交互…

Vue3 圖片或視頻下載跨域或文件損壞的解決方法

Vue3 圖片或視頻下載跨域或文件損壞的解決方法 修改跨域配置文件下載方法 修改跨域配置文件 修改vite.config.ts文件proxy里面寫跨域地址&#xff0c;如下圖&#xff0c;圖片地址就是我們要跨域的目標地址&#xff1a; 下載方法 如下就是我取消上面那句后的報錯 然后調用兩…

【C++風云錄】C++與智能交通:智能交通系統與車聯網

解鎖C的力量&#xff1a;在智能交通系統與車聯網中使用關鍵庫 前言 本文關注于C在智能交通系統與車聯網中的應用&#xff0c;并提供了五個常見庫的簡介和使用方法。這些庫包括&#xff1a;Veins, SUMO-GUI, OMNeT, NS-3和PLEXE&#xff0c;每個庫都有其獨特的功能和優點&…

【Java】Sping Boot中使用Javax Bean Validation

目錄 Javax Bean Validation在Spring Boot中集成Javax Bean Validation使用案例功能測試配置全局異常處理器重新測試返回特定形式的信息方式一方式二 附&#xff1a;常用的注解 Javax Bean Validation Javax Bean Validation是Java平臺的一項規范&#xff0c;旨在提供一種簡單…

想知道股指期貨和期權有什么不同嗎?

市場上目前有中金所的滬深300ETF&#xff0c;中證500和中證1000股指期貨&#xff0c;期權市場有上證50ETF&#xff0c;滬深300etf和中證500ETF期權&#xff0c;股指期貨和期權在買賣雙方的權利義務、風險收益特征、保證金制度、上市合約數量等方面均有較大區別&#xff0c;下文…

每天學點小知識:Windows終端Powershell美化

前言 本章的旨在教會你美化自己的終端&#xff0c;powershell需要以管理員運行 經過我的測試&#xff0c;不同的電腦可能會有不同的報錯&#xff0c;具體操作根據官方為主https://ohmyposh.dev/docs 效果展示 Oh My Posh&#xff1a;提供美觀的 PowerShell 提示符主題 1.安裝…

揭秘CISA:你不知道的信息安全認證,輕松掌握職場先機!

在當今的信息化時代&#xff0c;信息系統的安全和穩定是企業和組織的重要資產。信息系統審計是一項專業的工作&#xff0c;需要具備豐富的知識和經驗&#xff0c;以及敏銳的洞察力和判斷力。信息系統審計師是信息系統審計領域的專業人士&#xff0c;他們負責對信息系統的設計、…

MVVM模式的優點以及與MVC模式的區別?

1.MVVM 模式的優點&#xff1a; 1 、低耦合&#xff1a; 視圖&#xff08; View &#xff09;可以獨?于 Model 變化和修改&#xff0c;?個 ViewModel 可以綁定到不同的 "View" 上&#xff0c;當 View 變化的時候 Model 可以不變&#xff0c;當 Model 變化的時…

【OpenGL實踐12】關于緩存區Framebuffer的運用

文章目錄 一、說明二、幀緩沖區三、創建新的幀緩沖區四、附屬裝飾4.1 紋理圖像4.2 渲染緩沖區對象圖像 五、使用幀緩沖區5.1 后期處理5.2 更改代碼 六、后期處理效果6.1 色彩處理6.2 模糊6.3 Sobel算子 七、結論練習 一、說明 關于FrameBuffer的使用&#xff0c;是OpenGL的高級…

橫截面分位數回歸

一、分位數回歸簡介 分位數回歸&#xff08;英語&#xff1a;Quantile regression&#xff09;是回歸分析的方法之一。最早由Roger Koenker和Gilbert Bassett于1978年提出。一般地&#xff0c;傳統的回歸分析研究自變量與因變量的條件期望之間的關系&#xff0c;相應得到的回歸…

AI時代的服裝設計師--AIGC

AI時代的服裝設計師--AIGC AIGCAIGC設計能替代真正的設計師嗎森馬T恤設計AIGC優勢、優化 本文記錄于去年參加的一次森馬T恤設計活動的感受。 AIGC 可以說&#xff0c;近期以來&#xff0c;隨著ChatGPT的不斷發展&#xff0c;從ChatGPT-3到ChatGPT-4的飛速發展&#xff0c;AIGC…

Windows和Linux系統部署Docker(2)

目錄 一、Linux系統部署docker 前置環境&#xff1a; 1.安裝需要的軟件包&#xff0c; yum-util 提供yum-config-manager功能 2.添加阿里云 docker-ce 倉庫 3.安裝docker軟件包 4.啟動 docker并設置開機自啟 5.查看版本&#xff1a; 二、windows系統部署docker 1.查看…

Type ‘null‘ is not assignable to type ‘T‘. - ArkTSCheck

設置泛型將參數配置為 null 時拋出了如下異常: Type null is not assignable to type T. T could be instantiated with an arbitrary type which could be unrelated to null. <ArkTSCheck> 解決辦法 在 null 后面添加 ! 即可,以表示該值不會為 null data: T null! 以…