準備
博主:大大怪先森(記得關注哦!)
編程環境:vs2013
提示:本文內容主要講述堆中的動態記憶體開辟的問題!!!
文章目錄
- 準備
- 前言
- 一、為什么存在動態記憶體
- 二、動態記憶體函式的介紹
- 1.malloc函式和free
- 2.calloc函式
- 3.realloc函式
- 三.經典例題
- 3.1傳值還是傳址?
- 3.2記憶體泄漏
- 3.3生命周期問題
- 3.4野指標的使用
- 四.柔性陣列
- 4.1柔性陣列簡單舉例
- 4.2柔性陣列的特點和使用
- 4.2.1柔性陣列的特點
- 4.2.2 柔性陣列的使用
- 4.3柔性陣列的優勢
- 總結
前言
我們在使用記憶體的時候,是否想要自己來開辟記憶體,為自己所用,
做一個記憶體管理大師,今天我將帶各位了解一個堆上的記憶體的開辟???
提示:以下是本篇文章正文內容!!!
一、為什么存在動態記憶體
我們已經掌握了在堆疊上開辟空間:
int a = 0;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
但是堆疊取開辟有兩個特點:
1.空間開辟大小是固定的,
2. 陣列在申明的時候,必須指定陣列的長度,它所需要的記憶體在編譯時分配
但是如果需要我們在堆上開辟一塊記憶體,我們又需要怎么做呢?
本文將為各位大大解決堆上記憶體開辟的問題!!!
在此我們先大致了解一下記憶體的存盤方式

二、動態記憶體函式的介紹
1.malloc函式和free
C語言提供的malloc函式:
void* malloc (size_t size);
這個函式可以在堆區上開辟記憶體連續可用的空間
- 如果開辟成功,則回傳一個指向開辟好空間的指標,
- 如果開辟失敗,則回傳一個NULL指標,因此malloc的回傳值一定要做檢查,
- 回傳值的型別是 void* ,所以malloc函式并不知道開辟空間的型別,
- 具體在使用的時候使用者自 己來決定,
- 如果引數 size 為0,malloc的行為是標準是未定義的, 取決于編譯器,
堆疊區開辟后的空間無法自動的釋放,需要我們自己來釋放空間,防止記憶體泄漏的問題,
所以這里就需要用到free函式來釋放開辟的記憶體!
free函式
void free (void* ptr);
- 如果引數 ptr 指向的空間不是動態開辟的,那free函式的行為是未定義的,
- 如果引數 ptr 是NULL指標,則函式什么事都不做,
代碼如下(示例):
#include<stdio.h>
#include<assert.h>
#define num 10
int main()
{
int arr[num] = { 0 };
//代碼2
int* ptr = NULL;
ptr = (int*)malloc(num*sizeof(int));
if (NULL != ptr)//判斷ptr指標是否為空
{
int i = 0;
for (i = 0; i<num; i++)
{
*(ptr + i) = i;
printf("%d", *(ptr + i));
}
}
free(ptr);//釋放ptr所指向的動態記憶體
ptr = NULL;
return 0;
}
2.calloc函式
此函式的用法和malloc的開辟方式唯一的不同點就是在開辟記憶體的同時初始化,
小編在此不過多介紹內容了,小編不是偷懶哈,可以參照上面的malloc的開辟方式!!!

void* calloc (size_t num, size_t size);
代碼如下(示例):
#include<stdio.h>
#include<assert.h>
#define num 10
int main()
{
int arr[num] = { 0 };
int* ptr = (int*)calloc(10, sizeof(int));
free(ptr);
ptr = NULL;
return 0;
}

3.realloc函式
- realloc函式的出現讓動態記憶體管理更加靈活,
- 有時會我們發現過去申請的空間太小了,有時候我們又會覺得申請的空間過大了, 那為了合理的時 候記憶體,我們一定會對記憶體的大小做靈活的調整,
- 那realloc 函式就可以做到對動態開辟記憶體大 小的調整!!!
void* realloc (void* ptr, size_t size);
- ptr 是要調整的記憶體地址 size 調整之后新大小 回傳值為調整之后的記憶體起始位置,
- 這個函式調整原記憶體空間大小的基礎上,還會將原來記憶體中的資料移動到 新 的空間,
第一種情況:原有空間之后有足夠大的空間
第二種情況:原有空間之后沒有足夠大的空間

代碼如下(示例):
#include <stdio.h>
int main()
{
ptr = (int*)realloc(ptr, 1000);
int*p = NULL; p = realloc(ptr, 1000);
if(p != NULL)
{
ptr = p;
}
free(ptr);
return 0; }
三.經典例題
3.1傳值還是傳址?
代碼如下(示例):
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
請問test()函式代碼運行結果會怎樣?
報錯,傳址錯誤!!!傳地址不等于傳值!
3.2記憶體泄漏
代碼如下(示例):
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
int main()
{
Test();
return 0;
}
請問test()函式代碼運行結果會怎樣?
未進行free()函式的操作,存在記憶體泄漏的問題!!!
我相信各位大大肯定不會犯這種非智力性的錯誤的,
3.3生命周期問題
代碼如下(示例):
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
請問test()函式代碼運行結果會怎樣?
生命周期一到,開辟的記憶體自動消除!!!
3.4野指標的使用
代碼如下(示例):
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
請問test()函式代碼運行結果會怎樣?
動態記憶體開辟的空間已經被free掉了,再在str指向的空指標進行訪問就是野指標的越界訪問!!!
四.柔性陣列
結構中的最后一個元素允許是未知大小的陣列,這就叫做『柔性陣列』成員,
4.1柔性陣列簡單舉例
typedef struct st_type
{
int i;
int a[0];//柔性陣列成員
//或者 int a[]
}type_a;
4.2柔性陣列的特點和使用
4.2.1柔性陣列的特點
- 結構中的柔性陣列成員前面必須至少一個其他成員,
- sizeof 回傳的這種結構大小不包括柔性陣列的記憶體,
- 包含柔性陣列成員的結構用malloc ()函式進行記憶體的動態分配, 并且分配的記憶體應該大于結構的大 小,以適應柔性陣列的預期大小,
4.2.2 柔性陣列的使用
代碼如下(示例):
//代碼1
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);
這樣柔性陣列成員a,相當于獲得了100個整型元素的連續空間,
4.3柔性陣列的優勢
第一個好處是:方便記憶體釋放
如果我們的代碼是在一個給別人用的函式中,你在里面做了二次記憶體分配,并把整個結構體回傳
給用戶,用戶呼叫free可以釋放結構體,但是用戶并不知道這個結構體內的成員也需要free,所
以你不能指望用戶來發現這個事,所以,如果我們把結構體的記憶體以及其成員要的記憶體一次性分
配好了,并回傳給用戶一個結構體指標,用戶做一次free就可以把所有的記憶體也給釋放掉,
第二個好處是:這樣有利于訪問速度.
連續的記憶體有益于提高訪問速度,也有益于減少記憶體碎片,(其實,我個人覺得也沒多高了,反
正你跑不了要用做偏移量的加法來尋址,
總結
希望本篇文章能給各位帶來幫助,如有不足還請指正!!!
碼字不易,各位大大給個收藏點贊吧!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/337693.html
標籤:其他
上一篇:資料結構(C語言版)之堆疊及遞回
下一篇:Linux常用簡單命令

