【C基礎】堆內存創建/釋放和內存清理函數/內存泄漏

本期涉及到了較多的指針,沒有徹底領悟的同學請翻閱之前的博文~

一閃一閃亮晶晶,滿天都是小星星***

什么是堆內存:

是進程的一個內存段(text、data、bss、heap、stack)之一,由程序員手動管理,
特點就是足夠大,缺點就是使用麻煩。

為什么使用堆內存:

1、隨著程序的復雜數量變多。
2、堆內存的申請釋放受控制。

如何使用堆內存:

注意:C語言中沒控制堆內存的語句,只能使用C標準庫提供的函數。
#include <stdlib.h>void *malloc(size_t size);
功能:從堆內存中申請size個字節的內存,申請內存中存儲是什么內容不確定。
返回值:成功返回申請到的內存的首地址,失敗返回NULL。void free(void *ptr);
功能:釋放一塊堆內存,可以釋放NULL,但不能重復釋放和非法地址。
注意:釋放僅僅是使用權,里面的數據不會被特意清理。

申請,釋放和置空堆內存:

#include <stdio.h>
#include <stdlib.h>int main(int argc,const char* argv[])
{// 從堆上分配一塊內存,首個字節的地址存放在指針變量p中int* p = malloc(sizeof(int)*10);for(int i=0; i<10; i++){p[i] = i;	printf("%d\n",p[i]);}// 解引用  使用堆內存*p = 1000;printf("%d\n",*p);// 釋放堆內存free(p);// 重復釋放會導致堆內存崩潰// free(p);// free只是釋放使用權,數據不會被特意清理for(int i=0; i<10; i++){printf("%d\n",p[i]);}// 堆內存釋放后指針要及時置空p = NULL;}
void *calloc(size_t nmemb, size_t size);
功能:從堆內存中申請nmemb塊size個字節的內存,申請的內存塊會被初始化為0。
注意:申請的依然是一塊連續的內存。void *realloc(void *ptr, size_t size);
功能:改變已經有內存塊的大小,在原有的基礎上調大或調小。
返回值:是調整后的內存塊的首地址,一定要重新接收返回值,可能不是在原內塊上調整的。如果無法在原內存塊上進行調整:1、申請一塊新的符合要的內存塊2、把原內存塊上的內容拷貝過去3、把原內存釋放掉返回新內存塊的首地址
注:realloc函數有個爭議性話題,對于大型工程可能存在內存泄漏,本人目前未能親自驗證,但不可不防。
#include <stdio.h>
#include <stdlib.h>int main(int argc,const char* argv[])
{int* p = malloc(40);for(int i=0; i<10; i++){p[i] = i;printf("%d ",p[i]);}malloc(20);int* p1 = realloc(p,80);printf("%p %p\n",p,p1);for(int i=0; i<10; i++){p1[i] = i;printf("%d ",p1[i]);}}

malloc的內存管理機制:

當首次向malloc申請內存時,malloc會向操作系統申請內存,操作系統會直接分配33頁(1頁=4096字節)內存交給malloc管理。但這不意味著可以越界訪問,因為malloc把使用分配給"其他人",這樣會產生臟數據。每個內存塊之間會有些空隙(4~12字節),這些空隙一些是為了內容對齊,其中有4個字節記錄著malloc維護信息,這些維護信息決定下次分配內存的位置,也可以借助計算出每個內存塊的大小,當這些信息被破壞時就會影響malloc和free函數的調用。

使用堆內存要注意的問題:

內存泄漏:內存無法再使用,也無法被釋放,而再次使用時只能重新申請,然后重復心以上過程,是積月累導致系統中可用的內存越來越少。注意:程序一旦結束屬于它的資源都會被操作系統回收。誰申請誰釋放,誰知道該釋放誰釋放。如何判斷內存定位泄漏:1、查看內存的使用情況。2、使用代碼分析工具檢查malloc的調用情況。3、包裝malloc、free,記錄申請、釋放的信息到日志中。內存碎片:已經釋放的但無法再繼續使用的內存叫內存碎片,是由于申請和釋放的時間不協調導致的,無法避免只能盡量減少。如何減少內存碎片:1、盡量使用棧內存。2、不要頻繁的申請釋放內存。3、盡量申請大塊內存自己管理。

內存清理函數:

#include <strings.h>void bzero(void *s, size_t n)
功能:把一塊內存清理為0
s:內存塊的首地址
n:內存塊的字節數#include <string.h>
void *memset(void *s, int c, size_t n);
功能:把內存塊按字節設置為c
s:內存塊的首地址
c:相設置的ASCII碼值
n:內存塊的字節數
返回值:設置成功后的內存首地址
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>int main(int argc,const char* argv[])
{int* p = malloc(40);for(int i=0; i<10; i++){p[i] = i;printf("%d\n",p[i]);}//bzero(p,40);memset(p,1,40);printf("---------------\n");for(int i=0; i<10; i++){printf("%d\n",p[i]);}
}

堆內存定義二維數組:

指針數組:定義n*m二維數組類型* arr[n];for(int i=0; i<n; i++){arr[i] = malloc(sizeof(類型)*m);}注意:每行的m的值可以不同,這就是不規則二維數組。
數組指針:類型 (*arr)[n] = malloc(類型*n*m);注意:所謂的多維數組都是用一維數組模擬的。
使用示例:

1、

#include <stdio.h>
#include <stdlib.h>int main(int argc,const char* argv[])
{int* arr[10] = {};for(int i=0; i<10; i++){arr[i] = malloc(40);}for(int i=0; i<10; i++){for(int j=0; j<10; j++){printf("%d ",arr[i][j]);}printf("\n");}
}

2、

#include <stdio.h>
#include <stdlib.h>int main(int argc,const char* argv[])
{int (*arr)[5] = malloc(sizeof(int)*4*5);for(int i=0; i<4; i++){for(int j=0; j<5; j++){printf("%d ",arr[i][j]);}printf("\n");}
}

3、

#include <stdio.h>int main(int argc,const char* argv[])
{int arr[4][5] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};//int *p = (int*)arr;int (*p)[5] = arr;for(int i=0; i<4; i++){for(int j=0; j<5; j++){printf("%d ",p[i][j]);}printf("\n");}
}
練習1:計算出 100~10000 之間的素數,結果存儲在堆內存中,不要浪費內存。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>bool is_prime(int num)
{for(int i=2;i<=sqrt(num);i++){if(0 == num % i)return false;}return true;
}int main(int argc,char* argv[])
{int* arr=NULL,cnt=0;for(int i=100; i<1000;i++){if(is_prime(i)){arr = realloc(arr,sizeof(int)*(cnt+1));arr[cnt++]=i;}}for(int i=0;i<cnt;i++){printf("%d ",arr[i]);}free(arr);arr=NULL;
}

字符:

在計算機中字符是以整數形式存儲在,當需要顯示時會根據ASCII碼表中的對應關系顯示出相應的符號或圖案。
'\0' 0
'0' 48
'a' 97
'A' 65字符的輸入:scanf("%c",&ch);ch = getchar();
字符的輸出:printf("%c",ch);putchar(ch);

串:

是一種數據結構,由一組連續的若干個類型相同的數據組成,有一個結束標志。

字符串:

由字符組成的串型結構,結束標志就是'\0'。字符串存在的形式:
字符串字面值:"由雙引號包含的若干個字符",以地址形式存在,數據存儲在代碼段,如果修改就會產生段錯誤。const char* str = "字面串字面值";sizeof("strstr") 結果字符個數加1。注意:它的結束標志隱藏在末尾。兩個一模一樣的字符串字面值在代碼段中只有一份。字符數組:由char類型組成的數組,要為'\0'預留位置。使用的棧內存,數據可以修改。常用方式:字符數組[] = "字符串字面值";會自動為'\0'預留位置。    賦值完成后字符串存在兩份,一份存儲在代碼段,另一份存儲在棧內存(可被修改)。

字符串的輸入:

scanf %s 地址 缺點:不能輸入空格char* gets(char *s);
功能:輸入字符串,并且可以接收空格
返回值:鏈式調用(把一個函數的返回值,作業另一個函數的參數)。char *fgets(char *s, int size, stdin);
功能:可以設置輸入的字符串的長度size-1字符,超出的部分不接收,它會為'\0'預留位置。
注意:如果輸入的字符數不足size-1,最后的\n會一起接收了。

字符串的輸出:

printf %s 地址int puts(const char *s);
功能:輸出一個字符串,會在末尾自動添加一個\n。
返回值:成功輸出的字符個數。

練習2:實現一個判斷一個字符串是否是回文串。

#include <stdio.h>
#include <stdbool.h>bool is_palindrome(const char* str)
{size_t len = 0;/* 獲取字符串長度 */while(str[len]) len++;for(int i=0; i<len/2; i++){if(str[i] != str[len-i-1]) return false;}return true;
}int main(int argc,const char* argv[])
{char str[255] = {};printf("%s\n",is_palindrome(gets(str))?"是回文串":"不是回文串");
}

練習3:實現一個函數把一個由數字字符組成的字符串轉換成整數。

#include <stdio.h>int str_to_int(const char* str)
{int num = 0;while(*str && '0'<=*str && *str<='9'){num = num*10 + *str-'0';str++;}return num;
}int main(int argc,const char* argv[])
{char str[256] = {};printf("%d\n",str_to_int(gets(str)));
}

練習4:實現一個函數把一個字符串逆序。

#include <stdio.h>char* reverse(char* str)
{size_t len = 0;while(str[len]) len++;for(int i=0; i<len/2; i++){char t = str[i];str[i] = str[len-i-1];str[len-i-1] = t;}return str;
}int main(int argc,const char* argv[])
{char str[255] = {};puts(reverse(gets(str)));
}

[OVER]

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

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

相關文章

19_05_01校內訓練[polygon]

題意 把一個邊長為1的正n邊形放到一個正m邊形中&#xff0c;要求m邊形完全覆蓋n邊形&#xff0c;可以有交點&#xff0c;并且中心重合。求正m邊形的最小邊長&#xff0c;至少精確到6位。要求logn計算。 思考 先考慮m|n的情況。 我們知道&#xff0c;正m邊形的邊長與可行區域&am…

六度人脈 全球最高效的人脈法則(圖)

六度人脈這一概念&#xff0c;在20世紀60年代由美國心理學家Stanley Milgram提出并驗證。 所謂六度人脈&#xff0c;即地球上所有的人都可以通過六層以內的熟人關系鏈和其他人聯系起來。 通俗地說&#xff1a;“最多通過六個人你就可以認識地球上任何一個陌生人。” SNS(社會…

[轉]numpy中的np.max 與 np.maximum區別

轉自&#xff1a;https://blog.csdn.net/lanchunhui/article/details/52700895 轉載于:https://www.cnblogs.com/xianhan/p/10609319.html

JVM 的 Finalization Delay 引起的 OOM(java.lang.OutOfMemoryError:null at sun.misc.Unsafe.allocateMemory.)

今天在壓力測試環境某一個服務出現crash了&#xff0c;經過一番檢查&#xff0c;終于發現是由于JVM的Finalization Delay引起的&#xff0c;這個問題比較特殊&#xff0c;這里記錄一下。 這個服務是用Java寫的&#xff0c;主要完成的功能是根據特定的指令文件生成mp4文件&#…

win10 php7+apache2.4的配置以及遇到的問題及解決

首先進入PHP官網下載php7的版本,我下的是PHP7.1.28,在PHP的下載頁面注意劃紅線和綠線的地方(我畫的) 1.畫了紅線的意思是請使用由apache lounge提供的編譯文件,也就是點進藍色Apache lounge這里下載. 2.畫了綠色的線的意思是用Apache的話你必須使用Thread Safe(線程安全)的PHP…

緩存區的輸入輸出,字符串常用操作,實現strlen/strcpy/strcat/strcmp函數)

輸出緩沖區&#xff1a; 程序輸入的數據并不能立即顯示在屏幕上&#xff0c;而是先存儲在輸出緩沖區中&#xff0c;滿足一些條件后才顯示出來。 1、遇到\n后 2、遇到輸入語句 3、當輸出緩沖區滿4K 4、當程序結束 5、手動刷新 fflush(stdout) 緩沖區機制可以提高數據的讀寫速度…

理性分散投資 收益袋袋平安

理財錦囊 想要投資理財&#xff0c;不光可以選擇股票和債券這類入門產品&#xff0c; 實際上&#xff0c;還可選擇其他低風險及高回報的投資產品&#xff0c;例如外匯、期貨和商品。 針對此&#xff0c;幾位分析師預測了2014年各國經濟走勢的重點&#xff0c;協助散戶們分配…

AI一周熱聞:華為豪擲3.3億劍橋買地,自建光芯片工廠;比特大陸IPO失敗,組織架構調整...

導讀 華為豪擲3.3億劍橋買地&#xff0c;自建光芯片工廠蘋果春季發布會無硬件發布&#xff0c;轉型之心迫切比特大陸IPO失敗&#xff0c;組織架構調整&#xff0c;王海超任CEO特斯拉起訴小鵬汽車員工竊取商業機密英偉達發布GauGAN&#xff0c;線條色塊秒變逼真圖像用機器學習防…

Docker 環境:Nexus3.x 的私有倉庫

Nexus3.x 的私有倉庫 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 使用 Docker 官方的 Registry 創建的倉庫面臨一些維護問題。比如某些鏡像刪除以后空間默認是不會回收的&#xff…

虛擬環境vitualenv的使用

Python3開發之虛擬環境virtualenv與virtualenvwrapper 在使用 Python 開發的過程中&#xff0c;工程一多&#xff0c;難免會碰到不同的工程依賴不同版本的庫的問題&#xff1b; 亦或者是在開發過程中不想讓物理環境里充斥各種各樣的庫&#xff0c;引發未來的依賴災難。 此時&am…

find_first_of和find函數的區別

小記&#xff1a; find_first_of函數最容易出錯的地方是和find函數搞混。它最大的區別就是如果在一個字符串str1中查找另一個字符串str2&#xff0c;如果str1中含有str2中的任何字符&#xff0c;則就會查找成功&#xff0c;而find則不同&#xff1b;

銀行各類理財收益漸漲 各類寶錢景尚不明朗

這個春天&#xff0c;投資似乎進入了一個好事多磨的階段。央行一反先前支持的態度&#xff0c;開始對互聯網理財念起了“緊箍咒”。一時間&#xff0c;各種“寶”的命運變得撲朔迷離起來。盡管各種“寶”聲明&#xff1a;不受央行政策影響。而投資者內心的擔憂&#xff0c;恐怕…

Firefox 66回歸!修復多項臭蟲相關問題

上周最新版Firefox 66因為爆出會使微軟Office 365中的PowerPoint文字消失的臭蟲&#xff0c;Mozilla暫停發送。3月27日Mozilla重新釋出修補完成的最新版Firefox 66.0.2。根據Mozilla臭蟲報告網頁&#xff0c;Firefox 66除了造成Office 365中的PowerPoint文字消失的問題外&#…

PHP全棧學習筆記27

數組概述&#xff0c;類型&#xff0c;聲明&#xff0c;遍歷&#xff0c;輸出&#xff0c;獲取數組中最后一個元素&#xff0c;刪除重復數組&#xff0c;獲取數組中指定元素的鍵值&#xff0c;排序&#xff0c;將數組中的元素合成字符串。 數組概述&#xff0c;數組是存儲&…

Docker : 數據卷(創建、掛載、查看、刪除)

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 數據卷 數據卷 是一個可供一個或多個容器使用的特殊目錄&#xff0c;它繞過 UFS&#xff0c;可以提供很多有用的特性&#xff1a; 數據卷…

mac地址和ip地址的區別(轉)

先糾正一下幾個比較模糊的概念&#xff1a;“MAC地址表儲存IP地址”&#xff0c; MAC地址表是二層設備中存儲“MAC地址”和“轉發端口”映射關系的表&#xff0c;并不直接存儲IP地址。 “路由器根據MAC地址來選擇路由進行數據發送”&#xff0c;對于三層設備的三層端口來說&…

你是否發現 職業能力危機,請 警惕

身在職場&#xff0c;你有不有遭遇職業能力危機呢 ? 核心競爭力的增長是職業持續性發展的基礎&#xff0c;隨著年齡的增長和工作經驗的積累&#xff0c;有的職場人士保持著良好的發展勢態&#xff0c;有的卻越來越落伍&#xff0c;競爭力越來越弱。只有能力跟得上變化&#x…

你的GitHub,怎么和我用的不太一樣?

說起代碼托管&#xff0c;相信絕大多數人腦海中浮現出的第一個詞都是“GitHub”。經過多年的發展&#xff0c;GitHub儼然已經成為了代碼托管領域的標簽…隨著國內互聯網環境的優化&#xff0c;互聯網產業鏈的不斷壯大&#xff0c;越來越多的產業被拉入到了互聯網中來&#xff0…

Windows下多個JDK版本的切換方法

問題 因我之前在window中無法命令行輸入&#xff0c;后來發現是電腦中存在多個JDK&#xff0c;導致設置混亂。于是&#xff0c;我繼續深入研究了當電腦存在多個JDK的情況下&#xff0c;如何設置想要的JDK版本。步驟 1.更改環境變量 進入環境變量的配置界面&#xff0c;將JAVA_H…

哈哈哈,只有程序員才懂的黑色幽默 ... ...

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 也是機緣巧合&#xff0c;讓我一個之前工作從未接觸過程序員的人&#xff0c;現在成天和程序員打交道&#xff0c;要知道&#xff0c;不…