動態內存分配
#千鋒教育 物聯網逆戰班#
天才就是無止境刻苦勤奮的能力。
1、malloc函數 和 free函數
1.1、malloc函數
#include<stdlib.h>
void *malloc(unsigned int num_size);
形參:num_size需要申請空間大小的字節數。
返回值:
成功:返回空間的起始地址
失敗:NULL
特點:
1、對於malloc的返回值 一般要強制類型轉換
2、malloc申請的空間 內容不確定 一般使用memset進行清空
3、多次調用malloc 第1次malloc 和 第2次malloc的地址不一定連續
1.2、free函數
void free(void *addr);
釋放堆區空間
1.3、案例1:從堆區申請 一個int空間
void test02()
{
int *addr = NULL;
addr = (int *)malloc(sizeof(int));
if(addr == NULL)//申請失敗了
{
printf("malloc err\n");
return;
}
printf("*addr=%d\n", *addr);//不確定的值
//對堆區空間 清0
memset(addr, 0, sizeof(int));
printf("*addr=%d\n", *addr);//0
//對addr的空間 就行寫 或 讀
*addr = 1000;//寫
printf("*addr=%d\n", *addr);//1000 讀
//釋放堆區空間 空間使用權限的回收 是否對空間內容清0 這是不確定的
free(addr);
}
int main(int argc,char *argv[])
{
test02();
return 0;
}
運行結果:
1.4、案例2:從堆區申請一個數組 數組的大小 由用戶決定
int get_n(void)
{
int n = 0;
printf("請輸入元素的個數:");
scanf("%d", &n);
return n;
}
int* get_addr(int n)
{
return (int *)malloc(n*sizeof(int));
}
void my_input_array(int *arr, int n)
{
int i=0;
//記得將arr指向的空間清0
memset(arr,0,n*sizeof(int));
//獲取鍵盤輸入
printf("請輸入%d個int數據\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
}
void my_print_array(int *arr, int n)
{
int i=0;
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test04()
{
int *arr=NULL;
int n = 0;
//得到用戶輸入的元素個數
//1、獲取用戶大小
n = get_n();
//定義函數 給arr申請堆區空間
arr = get_addr(n);
if(arr == NULL)
{
perror("get_addr");
return;
}
//對空間讀寫操作
my_input_array(arr, n);
//對空間數組遍歷
my_print_array(arr, n);
//釋放空間
free(arr);
}
int main(int argc,char *argv[])
{
test04();
return 0;
}
運行結果:
2、calloc函數
#include<stdlib.h>
void * calloc(size_t nmemb,size_t size);
參數:
1、nmemb 申請的數據塊數
2、size 每一塊大小
3、所以申請總大小=nmemb * size
返回值:
成功:返回空間的起始地址
失敗:返回NULL
特點:申請的空間自動清零
案例:
void test04()
{
int n = 0;
int i=0;
int *arr=NULL;
//1、獲取用戶大小
printf("請輸入元素的個數:");
scanf("%d", &n);
//2、根據大小從堆區申請空間
#if 0
arr = (int *)malloc(n*sizeof(int));
if(NULL == arr)
{
//perror 錯誤輸出
perror("mallac");
return;
}
memset(arr,0,n*sizeof(int));//清零
#endif
#if 1
arr=(int *)calloc(n, sizeof(int));//自動清零 不需要使用memset
if(NULL == arr)
{
//perror 錯誤輸出
perror("calloc");
return;
}
#endif
//對arr的讀寫操作
printf("請輸入%d個int數據\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
//遍歷數組
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
//釋放空間
free(arr);
}
3、realloc動態追加或減少空間
#include<stdlib.h>
void* realloc(void *s, unsigned int newsize);
功能:
在原先s指向的內存基礎上重新申請內存,新的內存的大小爲 new_size 個 字節,如果原先內存後面有足夠大的空間,就追加,
如果後邊的內存不 夠用,則realloc函數會在堆區找一個newsize個字節大小的內存申請,
將原先內存中的內容拷貝過來,然後釋放原先的內存,最後返回新內存的地址。
參數:s:原先開闢內存的首地址 newsize:新申請的空間的大小
返回值:新申請的內存的首地址
注意:一定要保存 realloc的返回值
案例
void test06()
{
int *arr = NULL;
int n = 0;
int i=0;
int n_new = 0;
//1、獲取用戶大小
printf("請輸入元素的個數:");
scanf("%d", &n);
arr=(int *)calloc(n, sizeof(int));//自動清零 不需要使用memset
if(NULL == arr)
{
//perror 錯誤輸出
perror("calloc");
return;
}
printf("請輸入%d個int數據\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
//遍歷數組
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
//再追加5個元素
printf("請輸入新增的元素個數:");
scanf("%d", &n_new);
arr = (int *)realloc(arr, (n+n_new)*sizeof(int));
printf("請輸入新增的%d個int數據\n",n_new);
for(i=n;i<(n+n_new); i++)
{
scanf("%d",arr+i);
}
for(i=0;i<(n+n_new);i++)
{
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
int main(int argc,char *argv[])
{
test06();
return 0;
}
運行結果:
4、堆區空間使用的注意事項
void test08()
{
int *p2 = NULL;
int *p3 = NULL;
//1、指向堆區空間的指針變量 不要隨意的更改指向
int *p=(int *)calloc(1,sizeof(int));
int num = 10;
p = #//p指向num 導致calloc申請的空間泄露
//2、不要操作已經釋放的空間
p2 = (int *)calloc(1,sizeof(int));
*p2 = 1000;
//釋放該空間
free(p2);
printf("*p2 = %d\n", *p2);//不確定
//3、不要對堆區空間重複釋放
p3 = (int *)calloc(1,sizeof(int));
free(p3);
free(p3);// err 多次釋放
}
5、防止多次釋放
void test09()
{
int *p = (int *)calloc(1,sizeof(int));
if(p != NULL)//防止多次釋放
{
free(p);
p=NULL;
}
if(p != NULL)
{
free(p);
p=NULL;
}
}