目录
(一)堆区
(二)malloc函数
(三)calloc函数
(四)realloc函数
(五)free函数
(六)常见问题
(一)堆区
C语言的内存分为这五个区。第一个区是栈区,用来存放函数内部的局部变量的,包括形参,返回值等。第二个区是堆区,也是本文的重点内容。堆区是用来分配动态内存的,我们本文介绍的动态内存函数申请的内存都是在堆区。 第三个区是静态区,用来存放全局变量的。第四个区是常量区,比如字符串等就存放在里面,而且里面的内存存放的数据不能改变,相同值的地址是相同的。第五个区是代码区,用来存放我们的程序的代码。
(二)malloc函数
动态内存函数的头文件都是<stdlib.h>。malloc函数的作用是向堆区申请类型size_ t size的字节,并返回申请内存的首地址。如果申请失败,返回NULL指针。首地址为void *,因为函数并不知道申请的地址要存放什么类型的数据,我们一般使用动态内存也必须要强制类型转换才能使用。下面是malloc的使用说明
//比如申请一片字节为40的字节,存放int类型的数据
size_ t nums = 40;//40字节
int* pa = (int*)malloc(nums);//强制类型转换malloc返回的地址的类型,变得可供使用。
(三)calloc函数
calloc函数和malloc函数的作用大致相同。与malloc不同的是,calloc申请字节后并将申请的字节的数据全是初始化为0。而且参数也不同了。第一个参数是元素的个数,第二个参数是每个元素的大小。下面是calloc的使用
//申请十个int元素的内存
size_t nums = 10;//10个元素
int* pa = (int*)calloc(nums, sizeof(int));//申请nums个元素,每个元素大小是sizeof(int)
(四)realloc函数
realloc函数是重新分配内存的函数。第一个参数是一个类型为void*的指针,第二个参数是重新分配的字节大小。返回是重新分配内存后的内存的首地址(需要类型转换使用)。分配成功有两个情况,第一种情况是直接在原地址追加内存(那一片后面的内存足够),第二个情况是重新再堆区找一片合适的内存(后面的内存不足)
realloc的使用
//将动态内存申请40字节的pa指针重新申请80个字节
size_t nums = 40;
int* pa = (int*)malloc(nums);
//使用realloc函数
if (pa == NULL)
{perror("malloc:");exit(1);
}//如果申请失败打印失败信息
pa = (int*)realloc(pa, nums * 2);//重新分配内存
(五)free函数
动态申请的内存并不会自己释放,而是由程序员管理的。如果动态申请的内存不释放,可能会导致严重的问题,比如内存泄漏,内存占用严重卡顿。所以我们每次使用完动态内存后必须使用free函数释放。参数就是待释放动态内存的指针。
(六)常见问题
1.对NULL指针的解引⽤操作
void test()
{int *p = (int *)malloc(INT_MAX/4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}
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);
}
3.对非动态开辟内存使用free释放
void test()
{int a = 10;int *p = &a;free(p);//ok?
}
4.free释放⼀块动态开辟内存的⼀部分
void test()
{int *p = (int *)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}
5.对同⼀块动态内存多次释放
void test()
{int *p = (int *)malloc(100);free(p);free(p);//重复释放
}
6.动态开辟内存忘记释放(内存泄漏)
void test()
{int *p = (int *)malloc(100);if(NULL != p){*p = 20;}
}
int main()
{test();while(1);
}