欣賞動態之美,不如欣賞C語言實現動態內存管理之美 ! ! !

本篇會加入個人的所謂‘魚式瘋言’
??????魚式瘋言:??????此瘋言非彼瘋言
而是理解過并總結出來通俗易懂的大白話,
我會盡可能的在每個概念后插入魚式瘋言,幫助大家理解的.
可能說的不是那么嚴謹.但小編初心是能讓更多人能接受我們這個概念 !!!
在這里插入圖片描述

前言

在本篇文章中,小編將帶大家領略動態內存管理的魅力💖💖💖

  1. 為什么要有動態內存分配
  2. malloc和free
  3. calloc和realloc
  4. 柔性數組
  5. 總結C/C++中程序內存區域劃分
    話不多說,我們直接上菜吧 💕💕💕

一.為什么要有動態內存分配

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

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

但是上述的開辟空間的?式有兩個特點:
? 空間開辟??是固定的。
? 數組在申明的時候,必須指定數組的?度,數組空間?旦確定了??不能調整
但是對于空間的需求,不僅僅是上述的情況。有時候我們需要的空間??在程序運?的時候才能知
道,那數組的編譯時開辟空間的?式就不能滿?了。
C語?引?了動態內存開辟,讓程序員??可以申請和釋放空間,就?較靈活了。

二. malloc和free

2.1 malloc

C語?提供了?個函數叫 malloc
malloc 函數?來動態內存分配,是作為內存空間的 開墾機
原型如下:
在這里插入圖片描述

2.1.1舉個栗子

#include <stdlib.h>
#include<stdio.h>
int main()
{int* p = (int*)malloc(10*sizeof(int));if (p == NULL){perror("malloc");return 1;}int i = 0;//使用 - 給數組賦值for (i = 0; i < 10; i++){*(p + i) = i;}//打印for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//釋放空間free(p);p = NULL;return 0;
}

在這里插入圖片描述
這個函數向內存申請?塊連續可?的空間,并返回指向這塊空間的指針。

? 如果開辟成功,則返回?個指向開辟好空間的指針。

<1> 錯誤示例

#include <stdlib.h>
#include<stdio.h>
int main()
{int* p = (int*)malloc(1000000000000);if (p == NULL){perror("malloc");return 1;}int i = 0;//使用 - 給數組賦值for (i = 0; i < 10; i++){*(p + i) = i;}//打印for (i = 0; i < 10; i++){printf("%d ", *(p + i));}return 0;
}

在這里插入圖片描述
寶子們是不是很疑惑,這是怎么回事呢?🤔🤔🤔
那是因為 malloc 在開辟空間的時候是有可能開辟失敗的

? 如果開辟失敗,則返回?個 NULL 指針,因此malloc的返回值?定要做檢查。

其他情況:
? 返回值的類型是 void* ,所以malloc函數并不知道開辟空間的類型,具體在使?的時候使?者??來決定。
? 如果參數 size 為0,malloc的?為是標準是未定義的,取決于編譯器。

2.2 free

在這里插入圖片描述

2.2.1舉個栗子

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

#include <stdlib.h>
#include<stdio.h>
int main()
{int* p = (int*)malloc(10*sizeof(int));//開辟空間if (p == NULL){perror("malloc");return 1;}//釋放空間free(p);p = NULL;return 0;
}

在這里插入圖片描述
有空間的開辟就有空間的釋放,有人問為什么要把 p 置為空指針NULL
小伙伴可以帶著疑問繼續往下看哦😊😊😊

三. calloc和realloc

3.1 calloc

C語?還提供了?個函數叫 calloc , calloc 函數也?來動態內存分配。原型如下:
在這里插入圖片描述
? 函數的功能是為 num 個??為 size 的元素開辟?塊空間,并且把空間的每個字節初始化為 0
? 與函數 malloc 的區別只在于 calloc 會在返回地址之前把申請的空間的每個字節初始化為全

3.1.1.舉個栗子

#include <stdio.h>
#include <stdlib.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (NULL != p){int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}free(p);p = NULL;return 0;
}

在這里插入圖片描述
所以我們就看出不區別啦

魚式瘋言

所以如果我們對申請的內存空間的內容要求初始化

那么可以很?便的使?calloc函數來完成任務。

以上這些都是固定的內存開辟, 還不足以靈活。
小編為什么會這樣說呢! ! !
是的,是的,我們還有超級秘密武器。
請友友向下看

3.2 realloc

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

函數原型如下:
在這里插入圖片描述

3.2.1.舉個栗子

#include <stdio.h>
#include <stdlib.h>
int main()
{int* ptr = (int*)malloc(10*sizeof(int));if (ptr != NULL){for (int i = 0; i < 10; i++){*(ptr+i) = i;printf("%d", ptr[i]);}}else{perror("malloc");return 1;}//擴展容量//代碼1 - 直接將realloc的返回值放到ptr中//ptr = (int*)realloc(ptr, 1000);//這樣可以嗎?(如果申請失敗會如何?)//代碼2 - 先將realloc函數的返回值放在p中,不為NULL,在放ptr中int* p = NULL;p = realloc(ptr, 15*sizeof(int));if (p != NULL){ptr = p;for (int i = 10; i < 15; i++){*(ptr + i) = i;}}printf("\n");for (int i = 0; i < 15; i++){printf("%d ", *(ptr + i));}//業務處理free(ptr);return 0;
}

在這里插入圖片描述

這時我們小愛同學就有疑問了🤔🤔🤔
為什么realloc在內存中到底是怎么加長 或是 減短的呢? ? ?

答案見下圖😍😍😍`

? ptr 是要調整的內存地址
? size 調整之后新??
? 返回值為調整之后的內存 起始位置
? 這個函數調整原內存空間??的基礎上,還會將原來內存中的數據移動到 新 的空間。
? realloc在調整內存空間的是存在兩種情況:
。情況1:原有空間之后有?夠?的空間
。情況2:原有空間之后沒有?夠?的空間
在這里插入圖片描述

魚式瘋言

上面的插圖和代碼充分說明了一點

我們不可以將 realloc 函數得到的變化后的空間直接放在我們需要的指針變量中

我們就有必要加上一個臨變量來判斷其是否為 NULL ! ! !

3.3 realloc的特殊使用

有沒有友友們想過,如果我往 realloc 傳第一個參數,傳的是NULL的空指針呢,那會怎么樣呢🤔🤔🤔
不妨我們來試試吧

#include <stdlib.h>
#include<stdio.h>
int main()
{//int* p = (int*)malloc(10 * sizeof(int));//等效于下面這個int* p = (int*)realloc(NULL,10*sizeof(int));//開辟空間if (p == NULL){perror("realloc");return 1;}for (int i = 0; i < 10; i++){*(p + i) = i;printf("%d ", *(p + i));}//釋放空間free(p);p = NULL;return 0;}

在這里插入圖片描述

四. 柔性數組

4.1 柔性數組的特點:

? 結構中的柔性數組成員前?必須?少?個其他成員。
? sizeof 返回的這種結構??不包括柔性數組的內存。
? 包含柔性數組成員的結構? malloc () 函數進?內存的動態分配,并且分配的內存應該?于結構的??,以適應柔性數組的預期??。

4.1.1.舉個栗子

#include<stdio.h>
typedef struct st_type
{int i;int a[0];//柔性數組成員
}type_a;
int main()
{printf("%d\n", sizeof(type_a));//輸出的是4return 0;
}

在這里插入圖片描述

這個栗子充分說明了柔性數組不占內存

魚式瘋言

我理解的柔性數組

  1. 在結構體中
  1. 最后一個成員
  1. 未知大小的數組

4.2 柔性數組的使?

4.2.2.舉個栗子

//柔性數組
#include<stdio.h>
#include<stdlib.h>
struct MyStruct
{int a;char b;int arr[];
};
int main()
{struct MyStruct* p = (struct MyStruct*)malloc(sizeof(struct MyStruct)+10*sizeof(int));if (p == NULL){perror("malloc");return 1;}for (int i = 0; i < 10; i++){p->arr[i] = i;printf("%d ", p->arr[i]);}p->a = 10;p->b = 'd';printf("\n%d\n", p->a);printf("%c\n", p->b);struct MyStruct* art= (struct MyStruct*)realloc(p,sizeof(struct MyStruct) + 20 * sizeof(int));if (art!=NULL){p = art;for (int i = 10; i < 15; i++){p->arr[i] = i;}}for (int i = 0; i < 15; i++){printf("%d ", p->arr[i]);}free(p);p = NULL;return 0;
}

在這里插入圖片描述
這樣柔性數組成員 arr,相當于獲得了 15 個整型元素的連續空間。

4.3 柔性數組的優勢

4.3.1舉兩個栗子

<1>
#include<stdio.h>
struct St
{char c;int n;int arr[0];//柔性數組//[]里面可以放隨機數字,也可放置為空
};
int main()
{//struct St s = {0};//printf("%d\n", sizeof(struct St));struct St* ps = (struct St*)malloc(sizeof(struct St) + 10 * sizeof(int));if (ps == NULL){perror("malloc");return 1;}ps->c = 'w';ps->n = 100;int i = 0;for (i = 0; i < 10; i++){ps->arr[i] = i;}//數組空間不夠struct St* ptr = realloc(ps, sizeof(struct St) + 15 * sizeof(int));if (ptr != NULL){ps = ptr;}else{perror("realloc");return 1;}//...繼續使用for (i = 10; i < 15; i++){ps->arr[i] = i;}for (i = 0; i < 15; i++){printf("%d ", ps->arr[i]);}printf("\n%d\n", ps->n);printf("%c\n", ps->c);//釋放free(ps);ps = NULL;return 0;
}

在這里插入圖片描述

<2>
struct St
{char c;int n;int* arr;
};int main()
{//struct St s = {0};//printf("%d\n", sizeof(struct St));struct St* ps = (struct St*)malloc(sizeof(struct St));if (ps == NULL){perror("malloc");return 1;}ps->c = 'w';ps->n = 100;ps->arr = (int*)malloc(10*sizeof(int));if (ps->arr == NULL){perror("malloc-2");return 1;}//使用int i = 0;for (i = 0; i < 10; i++){ps->arr[i] = i;}//數組空間不夠int* ptr = (int*)realloc(ps->arr, 15*sizeof(int));if (ptr == NULL){perror("realloc");return 1;}else{ps->arr = ptr;}//使用for (i = 10; i < 15; i++){ps->arr[i] = i;}for (i = 0; i < 15; i++){printf("%d ", ps->arr[i]);}printf("\n%d\n", ps->n);printf("%c\n", ps->c);//釋放free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}

在這里插入圖片描述

上述 <1> 和 <2> 可以完成同樣的功能,
但是 ?法1 的實現有兩個好處:

第?個好處是:?便內存釋放

如果我們的代碼是在?個給別??的函數中,
你在??做了?次內存分配,并把整個結構體返回給??。
??調?free可以釋放結構體,
但是??并不知道這個結構體內的成員也需要free,所以你不能指望??來發現這個事。所以,如果我們把結構體的內存以及其成員要的內存?次性分配好了.
并返回給???個結構體指針,??做?次free就可以把所有的內存也給釋放掉。

第?個好處是:這樣有利于訪問速度.

連續的內存有益于提?訪問速度,也有益于減少內存碎?。
(其實,我個?覺得也沒多?了,
反正你跑不了要?做偏移量的加法來尋址)

魚式瘋言

柔性數組的優勢就不言而喻了吧,但最最must一點是什么???
小伙伴們知道么😊😊😊
當然是 釋放內存指針置空(NULL) 咯! ! !

第一:

我們要明確一點 malloc / calloc / realloc 申請的空間都是在內存堆區(下面有講解)申請的

第二:在 堆區 申請的空間如果不主動釋放,出了作用域是不會銷毀的。

第三:

釋放的方式:

1.free 主動釋放

2.直到程序結束,才由 操作系統 回放

第四:

我們free釋放的該指針指向的空間,而不是該該指針變量本身的地址

故我們需要將該指針也得置為空(NULL)

五. 總結C/C++中程序內存區域劃分

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

  • 棧區(stack):在執?函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執?結束時
    這些存儲單元?動被釋放。棧內存分配運算內置于處理器的指令集中,效率很?,
    但是分配的內存容量有限。
    棧區主要存放運?函數?分配的局部變量、函數參數、返回數據、返回地址等。
  • 堆區(heap):?般由程序員分配釋放,
    若程序員不釋放,程序結束時可能由OS(操作系統)回收 。
    分配?式類似于鏈表。
  • 數據段(靜態區)(static)存放全局變量、靜態數據。程序結束后由系統釋放。
  • 代碼段:存放函數體(類成員函數和全局函數)的?進制代碼
    在這里插入圖片描述

總結

在本篇文章中
小編主要帶著寶子們學習了哪些呢,讓我們梳理梳理吧💖💖💖

  • 為什么要有動態內存分配,它的意義和作用體現在何處?
  • malloc 和 free 這兩個一頭一尾是怎么樣唱雙簧的?
  • calloc 和 realloc 具體然后使用和以及他們的特殊性
  • 柔性數組的特點以及他所自帶的獨特的優勢
  • 總結C/C++中程序內存區域是怎么樣子劃分的,他們分別存著哪些類型的數據
    💖💖💖本次博文就到這里了,感覺各位小伙伴的賞臉品讀小編寫的拙作哦,

如果覺得小編寫的還不錯的咱可支持三關下,不妥當的咱評論區指正

希望我的文章能給各位家人們帶來哪怕一點點的收獲就是小編創作的最大動力💖💖💖
在這里插入圖片描述

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

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

相關文章

ubuntu解決問題:E: Unable to locate package manpages-posix-dev

sudo apt-get install manpages-posix-dev 想要在ubuntu里面安裝manpages-posix-dev這個包&#xff0c;發現彈出錯誤 E: Unable to locate package manpages-posix-dev 解決方法如下&#xff1a; 1 查看當前ubuntu的版本 abhishekitsfoss:~$ lsb_release -a No LSB module…

python自動化測試實戰 —— WebDriver API的使用

軟件測試專欄 感興趣可看&#xff1a;軟件測試專欄 自動化測試學習部分源碼 python自動化測試相關知識&#xff1a; 【如何學習Python自動化測試】—— 自動化測試環境搭建 【如何學習python自動化測試】—— 瀏覽器驅動的安裝 以及 如何更…

河南省專業技術人員職稱評審之繼續教育

&#xff08;一&#xff09;職稱評審時會遇到一個關于繼續教育學時是否足夠的問題&#xff0c;作為新人很容易一頭霧水&#xff0c;這里以河南省為例&#xff0c;先在管理系統 http://manage.hnzjgl.gov.cn 注冊&#xff0c;根據自己單位選擇&#xff0c;有些高校雖然在地方而不…

力扣題:數字與字符串間轉換-12.12

力扣題-12.12 [力扣刷題攻略] Re&#xff1a;從零開始的力扣刷題生活 力扣題1&#xff1a;539. 最小時間差 解題思想&#xff1a;將字符串的時間形式換成數字形式的時間&#xff0c;然后計算差值即可&#xff0c;最重要的是最小的值加上一天的時間加入到數組最后&#xff08…

圖文教程:stable-diffusion的基本使用教程 txt2img(多圖)

之前我介紹了SD的安裝過程&#xff0c;那么這篇將介紹怎么使用SD 使用模型 SD安裝好之后&#xff0c;我們只有一個默認的模型。這個模型很難滿足我們的繪圖需求&#xff0c;那么有2種方法。 1是自己訓練一個模型&#xff08;有門檻&#xff09;2是去網站上找一個別人練好的模…

Python3 數據類型轉換 ----20231211

# 有時候,我們需要對數據內置的類型進行轉換,數據類型的轉換,一般情況下你只需要將數據類型作為函數名即可。Python 數據類型轉換可以分為兩種:隱式類型轉換 - 自動完成 顯式類型轉換 - 需要使用類型函數來轉換 隱式類型轉換 在隱式類型轉換中,Python 會自動將一種數據類型…

windows 鏡像下載地址

HelloWindows.cn - 精校 完整 極致 Windows系統下載倉儲站

python自動化運維快速入門,python自動化運維教程

大家好&#xff0c;給大家分享一下python自動化運維需要掌握的技能&#xff0c;很多人還不知道這一點。下面詳細解釋一下。現在讓我們來看看&#xff01; 面向學員 熟練使用計算機&#xff0c;對Windows、Linux 有一點了解從業職或在校學生 對目前從事互聯網運維&#xff0c;想…

附錄:已實現的多品種回測收益

聲明&#xff1a; 本人不進行任何投資建議&#xff0c;也不出售任何包括策略、算法的程序代碼。 僅作為個人的2023年開發心路總結&#xff0c;有任何異議可以在評論區留言&#xff0c;可以討論&#xff0c;如果你杠&#xff0c;那就是你對。 這世上有很多條路&#xff0c;每個…

12.11作業

第一個界面的頭文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMovie> #include <QMessageBox>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidg…

代理IP的正確打開方式,使用IPIDEA解決性能困境

目錄 1、王婆賣瓜&#xff0c;自賣自夸2、問問2023最專業的AI機器人3、有事沒事找吒哥 一、代理IP的困境和問題1、困境一&#xff1a;所在公司網絡環境不好2、困境2&#xff1a;代理協議使用不當3、困境3&#xff1a;免費的代理服務器寬帶小4、困境4&#xff1a;代理服務器距離…

第二百零二回 介紹一個三方包bluetooth_enable_fork

文章目錄 1. 概念介紹2. 使用方法2.1 自定義主題2.2 覆蓋父主題 3. 示例代碼 我們在上一章回中介紹了圖片縮放相關的內容&#xff0c;本章回中將介紹如使用主題.閑話休提&#xff0c;讓我們一起Talk Flutter吧。 1. 概念介紹 我們在這里說的主題包含兩方面的內容&#xff1a;…

Leetcode93 復原IP地址

復原IP地址 題解1 回溯(同分割回文字符串)Tips&#xff1a;換成deque<string>tmp會更快 有效 IP 地址正好由四個整數&#xff08;每個整數位于 0 到 255 之間組成&#xff0c;且不能含有前導 0&#xff09;&#xff0c;整數之間用 ‘.’ 分隔。 例如&#xff1a;“0.1.2…

SpringCloud面試題——Sentinel

一&#xff1a;什么是Sentinel&#xff1f; Sentinel是一個面向分布式架構的輕量級服務保護框架&#xff0c;實現服務降級、服務熔斷、服務限流等功能 二&#xff1a;什么是服務降級&#xff1f; 比如當某個服務繁忙,不能讓客戶端的請求一直等待,應該立刻返回給客戶端一個備…

達索系統SOLIDWORKS 2024零件特征功能增強

SolidWorks是一款專業的三維3D設計軟件&#xff0c;功能強悍&#xff0c;支持分布式數據管理&#xff0c;支持直接處理網格數據&#xff0c;提供更多的數據的靈活性&#xff0c;使用起來高效便捷。可以幫助用戶輕松進行3D CAD設計、機械設計、鈑金設計、模擬設計、電氣設計、PD…

swing快速入門(六)

注釋很詳細&#xff0c;直接上代碼 上一篇 本篇新增內容 Gridlayout&#xff08;網格布局&#xff09; Textfield組件的最大限定長度 Panel()的默認布局方式 Gridlayout的默認布局位置 import java.awt.*;public class swing_test_4 {public static void main(String[]ar…

UE4 透明物體不渲染顯示??

問題描述&#xff1a;半透明特效在背景&#xff08;半透明材質模型&#xff09;前&#xff0c;當半透明特效開始移動的時候&#xff0c;隨著速度的加快會逐漸不渲染&#xff01; 解決辦法&#xff1a; 1.設置透明度排序 2.如果還沒效果&#xff0c;修改半透明背景模型以下材質…

visual studio 2022 IDE對C++代碼反匯編

敲一段代碼&#xff0c;在windows電腦兒上&#xff0c;忽然想用visual studio瞧瞧這段代碼的匯編長什么樣&#xff0c;怎么做呢&#xff1f; 代碼有了 #include <stdio.h> void sort(int*,int);int main(){int array[] { 977,1,32,3,99,8,7,5,23,6 };int length int(…

2023年度總結

這一年一行代碼都沒寫&#xff01;&#xff01;&#xff01; 因為我離開了這個行業&#xff0c;但我為了CSDN 這個位置沒有空缺&#xff0c;不能留下遺憾&#xff0c;寫下這篇博客吧。 強迫癥&#xff0c;完美主義。。 留下三個問題吧 當初你為什么選擇了計算機這個行業?現…

(C++)VS下sizeof(string(““))與linux-g++下sizeof(string(““))大小區別及原因剖析

個人主頁&#xff1a;Lei寶啊 愿所有美好如期而遇 說明 博主是x86平臺&#xff0c;所以下面的結果是28&#xff1b;x64平臺下是40&#xff0c;size_t變了&#xff0c;由int變long long。 接下來我們先來介紹 vs 下string的數據結構 我們可以看到有一個_Buf數組&#xff0c;…