国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

C語言進階:動態內存管理

shinezejian / 2604人閱讀

摘要:釋放不完全導致內存泄漏。既然把柔性數組放在動態內存管理一章,可見二者有必然的聯系。包含柔性數組的結構用進行動態內存分配,且分配的內存應大于結構大小,以滿足柔性數組的預期。使用含柔性數組的結構體,需配合以等動態內存分配函數。

動態內存管理

動態內存分配的意義

當我們用類型如int,char創建變量時,所開辟的空間都是固定的。而開辟動態內存就是為了靈活的使用內存,以滿足程序的需要。

在語言學習時,對于內存的劃分為上述三者:棧區,堆區,靜態區。棧區存放臨時變量,靜態區存放靜態變量,堆區用來動態開辟。

動態內存開辟是在堆區上開辟空間,具體如何開辟請看下列函數。

動態內存函數的介紹

開辟釋放函數 malloc & free
函數聲明
void* malloc( size_t size );
Return Valuemalloc returns a void pointer to the allocated space, or NULL if there is insufficient(不充足) memory available. To return a pointer to a type other than void, use a type cast(轉換) on the return value. Always check the return from malloc, even if the amount of memory requested is small.Parametersize - Bytes to allocate    RemarksThe malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.
void free( void* memblock );
Return ValueNoneParametermemblock - Previously allocated memory block to be freedRemarksThe free function deallocates(解除) a memory block that was previously allocated. If memblock is NULL, the pointer is ignored. Attempting to free a memblock isn"t allocated on heap may cause errors.

malloc函數在堆區上申請size個字節的空間,并返回該空間的起始地址。

free函數釋放指針指向的動態開辟的空間,但不對指針造成任何影響。

函數用法
  • malloc返回通用類型的指針,將其強制轉換為所需類型,并用該類型的指針維護該內存空間。
  • 開辟成功返回空間起始地址,開辟失敗則返回NULL
  • 使用結束free釋放內存以防內存泄漏,將指針置空避免成為野指針。
//申請空間int* p = (int*)malloc(40);//檢查if (p == NULL) {    printf("%s/n", strerror(errno));    return -1;}//使用for (int i = 0; i < 10; i++) {    *(p + i) = i;    printf("%d ", *(p + i));}//釋放空間free(p);//置空p = NULL;
內存開辟函數 calloc
函數聲明
void* calloc( size_t num, size_t size );
Return Valuecalloc returns a pointer to the allocated space. To get a pointer to a type other than void, use a type cast on the return value. Parameters1. num - Number of elements2. size - Length in bytes of each elementRemarksThe calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.

malloc函數在堆區上申請numsize大小的空間,返回起始地址并將內容初始化為0。

函數用法
int* p = (int*)calloc(10, sizeof(int));if (p == NULL) {    perror("");    return -1;}for (int i = 0; i < 10; i++) {    *(p + i) = i;    printf("%d ", p[i]);}free(p);p = NULL;
內存調整函數 realloc
函數聲明
void* realloc( void* memblock, size_t size );
Return Valuerealloc returns a void pointer to the reallocated memory block. The return value is NULL if there is not enough available memory to expand the block to the given size, then the original block is unchanged.Parameters1. memblock - Pointer to previously allocated memory block2. size - New size in bytesRemarksThe realloc function changes the size of an allocated memory block. The memblock parament points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc. The contents of the block are unchanged, although the new block can be in a different location. 

realloc函數為已開辟的空間重新開辟大小。

函數用法
  • 當原空間后有足夠大小時,就緊接原空間開辟剩余空間,并返回整個空間的起始地址。

  • 當原空間后無足夠大小時,就在堆區尋找新空間,再將原空間的內容移動到新空間,返回新空間的地址且釋放原空間。

  • 當剩余空間不夠無法開辟時,增容失敗,返回NULL
//1.p = (int*)realloc(p, 20 * sizeof(int));//2.int* ptr = (int*)realloc(p, 20 * sizeof(int));if (ptr == NULL) {    return -1;}p = ptr;

防止增容失敗將原空間指針置空,故不可直接使用原指針接受返回值。判斷非空后再賦給原指針。

?

常見的動態內存錯誤

1.不檢查空指針
void test() {	int* p = (int*)malloc(INT_MAX / 4);	*p = 20;	free(p);}

對指向動態開辟的空間的指針一定要做有效的判斷。

2.越界訪問
void test() {	int i = 0;	int* p = (int*)malloc(10 * sizeof(int));	if (NULL == p) {		exit(EXIT_FAILURE);	}	for (int i = 0; i <= 10; i++) {		*(p + i) = i;	}	free(p);    p = NULL;}

作為程序員必須有意識地檢查所寫的代碼是否有越界訪問的問題。

3.釋放非動態開辟內存
void test() {	int a = 10;	int* p = &a;	free(p);    p = NULL;}

不可用free釋放非動態開辟的空間。

4.釋放部分內存
int main(){	int* p = (int*)malloc(100);	p++;	free(p);	return 0;}

改變指向動態開辟內存的指針,內存將無法管理。釋放不完全導致內存泄漏。

5.重復釋放內存
void test() {	int* p = (int*)malloc(100);	free(p);	free(p);}

使用free釋放已釋放的空間,即訪問非法內存。建議釋放內存和指針置空搭配使用。

6.忘記釋放內存
void test() {    int *p = (int*)malloc(100);    if(NULL != p) {        *p = 20;    }}int main() {    test();    while(1);}

使用結束不釋放內存造成內存泄漏。程序不停止,系統也不會自動回收。

?

筆試題

調用下列test函數,解釋運行結果。

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

程序報錯。

傳值調用:并沒有改變str的值仍為不予修改的空指針,可以使用二級指針接收str的地址。函數調用結束后指針銷毀故無法釋放空間以致內存泄漏。

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

程序打印隨機值。

返回棧空間地址:數組p在函數內創建,出函數銷毀,返回這部分空間的地址 ,屬于訪問非法空間。

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

程序運行成功,打印"hello"

傳址調用:本題是例一的正確寫法。

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

程序報錯。

野指針:動態開辟的內存釋放后指針不置空,造成野指針訪問非法內存。釋放內存和指針置空應該搭配起來使用。

釋放空間,銷毀空間都是將內存空間歸還給操作系統,即將此空間的使用權限歸還操作系統。雖不會改變空間內容以致打印出所謂的“正確結果”,但可能在之后被操作系統分配給其他程序時發生修改。但無論改變與否,一旦空間歸還后再去訪問就是訪問非法內存。

?

C/C++內存劃分

用例展示

根據下列創建的各種變量,分析內存的劃分。

int globalVar = 1;static int staticGlobalVar = 1;int main(){	static int staticVar = 1;		int localVar = 1;	int num1[10] = { 1,2,3,4 };	char char2[] = "abcd";	char* pChar3 = "abcd";	int* ptr1 = (int*)malloc(4 * sizeof(int));	int* ptr2 = (int*)calloc(4, sizeof(int));	int* ptr3 = (int*)realloc(ptr2, 4 * sizeof(int));	free(ptr1);	free(ptr3);	return 0;}
  1. globalVal,staticGobalVar,staticVar分別是全局變量和靜態變量,在數據段上創建。
  2. localVarnum,char2,pchar以及ptr本身都是局部變量,都是在棧區上創建的。
  3. malloc,calloc,realloc都是在堆區上開辟的內存塊,由指針ptr指向而已。
內存劃分圖示

  1. 棧區(stack):執行函數時,函數的局部變量都會在棧區上創建。壓棧:從棧頂向下開辟空間,彈棧:從棧底向上釋放空間。
  2. 堆區(heap):一般由程序員分配和釋放,從堆低向上開辟空間,堆頂向下釋放空間。在程序結束后也被操作系統會自動回收。
  3. 數據段(靜態區):存放全局變量,靜態數據。變量本在棧上創建,被static修飾后放在常量區,程序結束后由系統釋放。
  4. 代碼段(常量區):存放可執行代碼和只讀常量。

語言學習時期,僅對內存作此了解即可。內核空間和內存映射段會在操作系統中學習,此處不再深入研究。

?

柔性數組

C99中引入柔性數組。柔性數組(flexible array)面試中雖不是重要的考點,但仍需掌握最基本的使用。

柔性數組的定義

C99中,結構中最后一個元素允許是未知大小的數組,被稱為柔性數組成員。例如:

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

語法規定數組大小中寫0和不寫都代表不指定大小。意味數組可大可小,這便是柔性的含義。

有些編譯器可能只支持一種寫法。當然柔性數組前必須有其他成員,類型一致是為了避免考慮內存對齊。既然把柔性數組放在動態內存管理一章,可見二者有必然的聯系。

柔性數組的特點
  • 結構中柔性數組成員前必須至少有一個成員。

  • sizeof計算結構所占空間時不包含柔性數組的大小。

  • 包含柔性數組的結構用malloc進行動態內存分配,且分配的內存應大于結構大小,以滿足柔性數組的預期。

使用含柔性數組的結構體,需配合以malloc等動態內存分配函數。分配空間減去其他成員的大小,即為為柔性數組開辟的空間。

柔性數組的使用

malloc開辟的大小寫成如圖所示的形式,增加代碼的可閱讀性。

結構體所分配空間減去其他成員的大小,所剩即為為柔性數組開辟的空間大小,若不夠還可以用realloc調整大小,以滿足柔性數組“柔性”的需求。

struct st_type {	int i;	int a[0];};int main() {	printf("%d/n", sizeof(struct st_type));	//1.	struct st_type st;	//2.	struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int));	if (pst == NULL) {		perror("pst");		return -1;	}	return 0;}

含柔性數組結構體當然不可像第一種那樣使用,這樣結構體變量st僅有4個字節,不包含柔性數組。

Example
struct st_type {	int i;	int a[0];};int main() {	struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int));	if (pst == NULL) {		perror("pst");		return -1;	}	pst->i = 10;	for (int i = 0; i < 10; i++) {		printf("%d ", pst->a[i] = i);	}	//調整空間大小	struct st_type* ptr = (struct st_type*)realloc(pst, sizeof(struct st_type) + 20 * sizeof(int));	if (ptr == NULL) {		perror("ptr");		return -1;	}	pst = ptr;	for (int i = 10; i < 20; i++) {		printf("%d ", pst->a[i] = i);	}	//釋放	free(pst);	pst = NULL;	return 0;}
柔性數組的優勢

柔性數組成員利用動態內存可大可小,那同樣將柔性數組成員替換成指向動態開辟內存的指針也可達到同樣的效果。下文將對比二者都有何優劣。(為突出對比,已省略不必要的代碼)

柔性數組版本
struct st_type {	int i;	int a[];};int main() {	struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int));	for (int i = 0; i < 10; i++) {		printf("%d ", pst->a[i] = i);	}	//調整空間大小	struct st_type* ptr = (struct st_type*)realloc(pst, sizeof(struct st_type) + 20 * sizeof(int));	pst = ptr;	for (int i = 10; i < 20; i++) {		printf("%d ", pst->a[i] = i);	}	//釋放	free(pst);	pst = NULL;		return 0;}
指針版本
struct st_type {	int i;	int* pa;};int main() {	struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type));    pst->pa = (int*)malloc(10 * sizeof(int));    for (int i = 0; i < 10;
            
                     
             
               

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121538.html

相關文章

  • C語言進階動態內存管理/分配

    摘要:棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。棧區主要存放運行函數而分配的局部變量函數參數返回數據返回地址等。 C語言動態內存分配篇 目錄 一、為什么存在動態內存管理/分配? ????????內存的存儲形式劃分 二、動態內存函數的介紹 ????????malloc ...

    Carson 評論0 收藏0
  • 【前端進階之路】內存基本知識

    摘要:在運行腳本時,需要顯示的指定對象。大對象區每一個區域都是由一組內存頁構成的。這里是唯一擁有執行權限的內存區。換句話說,是該對象被之后所能回收到內存的總和。一旦活躍對象已被移出,則在舊的半空間中剩下的任何死亡對象被丟棄。 內存管理 本文以V8為背景 對之前的文章進行重新編輯,內容做了很多的調整,使其具有邏輯更加緊湊,內容更加全面。 1. 基礎概念 1.1 生命周期 不管什么程序語言,內存...

    Simon_Zhou 評論0 收藏0
  • C語言進階C語言實現通訊錄 升級版 { 含動態擴容/銷毀/信息保存功能 }(強烈建議收藏食用)

    摘要:之前的通訊錄在程序退出后內部的數據就會消失,再次打開程序后只能重新輸入數據,為此我們增加了一個保存功能來保存信息。 前言: 由于之前實現的通訊錄在存儲方面只能支持靜態的1000人的存儲量,但是如果聯系人較少,則會造成較大的內存浪費。而當聯系人一旦超過1000時,就不能再繼續存儲信息了。因...

    gxyz 評論0 收藏0
  • 是,入坑小記

    摘要:種一顆樹最好的時機是十年前,其次是現在經過一段刻骨的升本歷程,來到了西華大學。計劃是前進的路線圖免除對于以后學習的各自夸大的計劃,從實際出發找到適合自己的前進的路線圖。今年我歲,年輕。 種一顆樹最好的時機是十年前,其次是現在 經過一段刻骨的升本歷程,來到了西華大學。明顯能感覺到自己又有了新的...

    CoXie 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<