為什么要有動態內存分配?

文章目錄

  • 1.為什么要有動態內存分配
  • 2.malloc和free
    • 2.1 malloc
    • 2.2 free
  • 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.動態內存經典筆試題分析
    • 5.1 題?1:
    • 5.2 題?2:
    • 5.3 題?3:
    • 5.4 題?4:
  • 6.柔性數組
    • 6.1 柔性數組的特點:
    • 6.2 柔性數組的使?
    • 6.3 柔性數組的優勢
  • 7.總結C/C++中程序內存區域劃分

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

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

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

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

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

但是對于空間的需求,不僅僅是上述的情況。有時候我們需要的空間??在程序運?的時候才能知道,那數組的編譯時開辟空間的?式就不能滿?了。

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

2.malloc和free

2.1 malloc

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

void* malloc (size_t size);

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

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

2.2 free

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

void free (void* ptr);

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

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

舉個例?:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 0;
scanf("%d", &num);
int arr[num] = {0};
int* ptr = NULL;
ptr = (int*)malloc(num*sizeof(int));
if(NULL != ptr)//判斷ptr指針是否為空
{
int i = 0;
for(i=0; i<num; i++)
{
*(ptr+i) = 0}
}
free(ptr);//釋放ptr所指向的動態內存
ptr = NULL;//是否有必要?
return 0;
}

3.calloc和realloc

3.1 calloc

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

void* calloc (size_t num, size_t 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)
{
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 函數就可以做到對動態開辟內存??的調整。

函數原型如下:

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

在這里插入圖片描述

情況1

當是情況1 的時候,要擴展內存就直接原有內存之后直接追加空間,原來空間的數據不發?變化。

情況2

當是情況2 的時候,原有空間之后沒有?夠多的空間時,擴展的?法是:在堆空間上另找?個合適??的連續空間來使?。這樣函數返回的是?個新的內存地址。

由于上述的兩種情況,realloc函數的使?就要注意?些。

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

4.常見的動態內存的錯誤

4.1 對NULL指針的解引用操作

void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就會有問題
free(p);
}

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

void test()
{
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
*(p+i) = i;//當i是10的時候越界訪問
}
free(p);
}

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

void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}

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

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向動態內存的起始位置
}

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

void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重復釋放
}

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

void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}

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

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

5.動態內存經典筆試題分析

5.1 題?1:

void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}

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

5.2 題?2:

char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}

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

5.3 題?3:

void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}

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

5.4 題?4:

void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}

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

6.柔性數組

也許你從來沒有聽說過柔性數組(flexible array)這個概念,但是它確實是存在的。

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

例如:

struct st_type
{
int i;
int a[0];//柔性數組成員
};

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

struct st_type
{
int i;
int a[];//柔性數組成員
};

6.1 柔性數組的特點:

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

例如:

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

6.2 柔性數組的使?

//代碼1
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
//業務處理
p->i = 100;
for(i=0; i<100; i++)
{
p->a[i] = i;
}
free(p);
return 0;
}

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

6.3 柔性數組的優勢

上述的 type_a 結構也可以設計為下?的結構,也能完成同樣的效果。

//代碼2
#include <stdio.h>
#include <stdlib.h>
typedef struct st_type
{
int i;
int *p_a;
}type_a;
int main()
{
type_a *p = (type_a *)malloc(sizeof(type_a));
p->i = 100;
p->p_a = (int *)malloc(p->i*sizeof(int));
//業務處理
for(i=0; i<100; i++)
{
p->p_a[i] = i;
}
//釋放空間
free(p->p_a);
p->p_a = NULL;
free(p);
p = NULL;
return 0;
}

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

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

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

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

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

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

在這里插入圖片描述

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

  1. 棧區(stack):在執?函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執?結束時

這些存儲單元?動被釋放。棧內存分配運算內置于處理器的指令集中,效率很?,但是分配的內

存容量有限。 棧區主要存放運?函數?分配的局部變量、函數參數、返回數據、返回地址等。

《函數棧幀的創建和銷毀》

  1. 堆區(heap):?般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS(操作系統)

回收 。分配?式類似于鏈表。

  1. 數據段(靜態區):(static)存放全局變量、靜態數據。程序結束后由系統釋放。
  2. 代碼段:存放函數體(類成員函數和全局函數)的?進制代碼。

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

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

相關文章

docker hub 拉取鏡像失敗報Get “https://registry-1.docker.io/v2/“: net/http: request canceled while waiting

自己記錄一把&#xff0c;給兄弟們避坑 1.上問題報錯代碼 [rootlocalhost ~]# docker pull hello-world Using default tag: latestError response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connectio…

Hive數倉部署/分層/ETL腳本基礎指南

部署Hive數倉及分層基礎指南 部署和構建一個Hive數倉涉及多個步驟&#xff0c;包括設置Hadoop集群、配置Hive、設計數據倉庫架構以及實現ETL&#xff08;Extract, Transform, Load&#xff09;過程。下面是一個詳細的指南&#xff0c;幫助你完成這些步驟。 1. 設置Hadoop集群 首…

深入 Go 底層原理(六):垃圾回收(GC)

1. 引言Go 語言自帶垃圾回收&#xff08;Garbage Collection, GC&#xff09;&#xff0c;讓開發者從手動管理內存的繁重任務中解脫出來。Go 的 GC 以其低延遲和并發性而聞名&#xff0c;其目標是在不長時間暫停&#xff08;Stop The World, STW&#xff09;整個程序的情況下完…

專網內網IP攻擊防御:從應急響應到架構加固

內網IP攻擊防御&#xff1a;從應急響應到架構加固內網IP攻擊的隱蔽性遠超外網威脅&#xff0c;其本質是信任邊界內的權限濫用。應對需遵循"識別-隔離-溯源-加固"四步法則&#xff0c;兼顧應急止損與長效防御。應急處置&#xff1a;30分鐘響應窗口1. 流量阻斷&#xf…

Git、Gitee、GitHub、GitLab完整講解:從基礎到進階

第一部分&#xff1a;Git是什么&#xff1f; &#x1f4da;比喻&#xff1a;Git就像是一本"時光日記本" ? 每一段代碼的改動&#xff0c;Git都會幫你記錄下來&#xff0c;像是在寫日記。 ? 如果出現問題或者想查看之前的版本&#xff0c;Git可以帶你"穿越回…

WinForm之CheckBox 控件

CheckBox&#xff08;復選框&#xff09;是 WinForm 中用于實現 “多項選擇” 的控件&#xff0c;允許用戶從一組選項中選擇任意數量的項&#xff08;包括零項、一項或多項&#xff09;&#xff0c;適用于需要同時選擇多個選項的場景&#xff08;如愛好、權限設置、功能開關等&…

鯨魚優化算法(Whale Optimization Algorithm, WOA)是一種受座頭鯨捕食行為啟發的群體智能優化算法,由Seyedali Mirjalili于2016年提出

鯨魚優化算法(Whale Optimization Algorithm, WOA)是一種受座頭鯨捕食行為啟發的群體智能優化算法,由Seyedali Mirjalili于2016年提出。 它通過模擬鯨魚的狩獵策略(特別是“氣泡網捕食”行為)來解決優化問題,廣泛應用于函數優化、工程設計、機器學習參數優化等領域。以下…

信息量,驚奇度,熵、KL散度(相對熵),交叉熵、最大似然估計MLE與最小化交叉熵的等價證明、

一&#xff1a; 一些基本概念 1.1 信息量:特定事件所攜帶的信息多少信息量衡量的是特定事件所攜帶的信息多少&#xff0c;其數學定義為&#xff1a;其中p(x)是事件x發生的概率。核心思想&#xff1a;越罕見的事件&#xff0c;其攜帶的信息量越大&#xff1b;越常見的事件&#…

VBA 64位API聲明語句第012講

跟我學VBA&#xff0c;我這里專注VBA, 授人以漁。我98年開始&#xff0c;從源碼接觸VBA已經20余年了&#xff0c;隨著年齡的增長&#xff0c;越來越覺得有必要把這項技能傳遞給需要這項技術的職場人員。希望職場和數據打交道的朋友&#xff0c;都來學習VBA,利用VBA,起碼可以提高…

深入理解Java中String.intern()方法:從原理到并發控制實踐

深入理解 Java 中 String.intern () 方法&#xff1a;從原理到并發控制實踐 在 Java 開發中&#xff0c;String.intern()方法是一個看似簡單卻蘊含深意的 API。它在字符串常量池管理、內存優化以及并發控制等場景中有著關鍵作用。本文將從底層原理出發&#xff0c;結合實際案例…

在Linux中創建LVGL應用

在Linux中創建LVGL應用 簡介 上一篇文章介紹了在imx6上開發UI的流程 . 這篇接上文&#xff0c; 介紹具體的開發步驟。 1. 創建項目主目錄 mkdir my_lvgl_project cd my_lvgl_project2. 初始化 Git 倉庫 (可選但推薦) git init echo "# My Project with Dependencies&…

大模型對比評測:Qwen2.5 VS Gemini 2.0誰更能打?

一、背景與選型關鍵 在 AI 應用落地的時代&#xff0c;“AI大模型選型對比”成為關鍵環節。選擇合適的模型要綜合考量性能、上下文長度、推理能力、中文/編程支持、成本等多維度指標。 本文重點比較 Gemini2.0Flash-Lite &#xff08;Preview&#xff09;、Gemini2.0Flash &a…

轉置卷積解釋與示例計算

文章目錄轉置卷積的三種等價實現方法&#xff1a;原理、公式與等價性分析數學定義與核心公式方法一&#xff1a;零填充翻轉核卷積&#xff08;數學定義方法&#xff09;原理與公式等價性說明方法二&#xff1a;直接位置映射&#xff08;pytorch框架高效實現&#xff09;原理與公…

關于車位引導及汽車乘梯解決方案的專業性、系統性、可落地性強的綜合設計方案與技術實現說明,旨在為現代智慧停車樓提供高效、安全、智能的停車體驗。

一、系統概述隨著城市土地資源日益緊張&#xff0c;立體停車、自動化停車成為發展趨勢。本方案圍繞“車位引導系統 汽車乘梯系統”構建智慧停車核心體系&#xff0c;結合地磁/視頻/超聲波檢測、AI識別、語音交互、電梯自動調度等先進技術&#xff0c;實現車輛入場、引導、停泊…

【相機】曝光時間長-->拖影

曝光時間長 → 運動目標在快門開啟期間持續移動 → 同一像素記錄多個位置的能量 → 圖像出現“拖影”&#xff08;運動模糊&#xff09;。&#x1f50d; 具體原因卷簾快門&#xff08;Rolling Shutter&#xff09;效應 RealSense 的 RGB 傳感器&#xff08;如 IMX 系列&#xf…

day36 力扣1049.最后一塊石頭的重量II 力扣494.目標和 力扣474.一和零

最后一塊石頭的重量II有一堆石頭&#xff0c;用整數數組 stones 表示。其中 stones[i] 表示第 i 塊石頭的重量。每一回合&#xff0c;從中選出任意兩塊石頭&#xff0c;然后將它們一起粉碎。假設石頭的重量分別為 x 和 y&#xff0c;且 x < y。那么粉碎的可能結果如下&#…

Java內存模型(Java Memory Model,JMM)

?? JMM?? 是Java虛擬機&#xff08;JVM&#xff09;規范中定義的一組規則和規范&#xff0c;用于描述多線程環境下&#xff0c;Java程序中變量的訪問和修改行為&#xff0c;尤其是在并發編程中如何保證內存可見性、原子性和有序性。JMM 是 Java 并發編程的基石&…

【swoole Windows 開發(swoole-cli 開發 hyperf)】

先前swoole在Windows平臺的開發體驗極差&#xff0c;如果在Windows開發swoole的東西可以用docker或者虛擬機&#xff0c;遠程開發&#xff0c;體驗比較好的是直接Mac或者Linux系統開發。但是作為window平臺的釘子戶表示我窮。swoole之前已經推出了cygwin64編譯成winwods版本的方…

興達餐飲 酒店 進銷存管理系統軟件

興達餐飲 酒店 進銷存管理系統軟件

Seal Report:一款免費開源的報表工具

Seal Report 是一款基于 C# 語言開發的開源報表工具&#xff0c;可以從各種數據庫或 NoSQL 數據源中生成日常報告&#xff0c;并且執行復雜的計劃任務。 功能特性 免費開源&#xff1a;源代碼托管在 GitHub 上&#xff0c;用戶可以自由使用、修改、甚至集成到自己的系統中&…