目录
一.前言
我们之前编程时创建的一些变量,你知道它们都是存放在内存的哪里吗?
其实,不同的类型的变量在内存中存储的位置是不一样的。
一起来看一下:
那么为什么要有动态内存开辟这一说呢?
有时候我们需要的空间大小在程序运行的时候才能知道,那数组在编译时开辟空间的方式就不能满足了,这时候就需要我们的动态内存分配了。
动态内存开辟主要要求我们了解和掌握四个函数
1.malloc
2.calloc
3.realloc
4.free
二.动态内存函数详解及其使用
2.1 malloc和free函数概述
1. malloc函数:(文档地址:cplusplus.com)。
2. free函数
2.1.1 malloc示例使用:
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<stdio.h>
int main()
{
int* p = (int *)malloc(10 * sizeof(int));
//如果开辟失败
//一定要去检查
if(p == NULL)
{
//打印错误原因
printf("%s\n",strerror(errno));
}
else
{
//正常使用空间
int i = 0;
for(i = 0 ; i < 10 ; i++)
{
*(p+i) = i;
}
for(i = 0 ; i < 10 ; i++)
{
printf("%d\n",*(p+i));
}
}
//当动态申请的空间不再使用的时候,就应该把空间还给操作系统
free(p);//主动回收掉
p = NULL;
return 0;
}
剖析代码:
如果,我将开辟的内存空间搞得很大,那么将会返回什么错误信息呢?
其实操作系统是会在我们程序结束的时候,将动态内存开辟的空间释放掉的,那么free函数还有存在的必要吗?
当然!!
怎么样,到这里是不是对malloc和free函数的理解清楚了很多呢?
2.2 calloc函数概述
2.2.1 calloc示例使用
int main()
{
int* p = calloc(10,sizeof(int));
if(p == NULL)
{
//打印错误原因
printf("%s\n",strerror(errno));
}
else
{
int i = 0;
for(i = 0 ; i < 10 ; i++)
{
printf("%d ",*(p+i));
}
}
free(p);
p = NULL;
}
代码剖析:
可以根据自己的实际需求来选择使用malloc函数还是calloc函数。
2.3 realloc函数概述
2.3.1 realloc函数的示例使用
int main()
{
int* p = (int *)malloc(5 * sizeof(int));
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
int i = 0;
for (i = 0; i < 5; i++)
{
*(p + i) = i;
}
for (i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
}
}
printf("\n");
//这里我想在开辟20个空间给我使用
int* p2 = (int *)realloc(p, 5* sizeof(int ));
if(p2 != NULL) //追加成功
{
p = p2;
}
int i = 0;
for (i = 5; i < 10; i++)
{
*(p + i) = i;
}
for (i = 5; i < 10; i++)
{
printf("%d ", *(p + i));
}
free(p);
p = NULL;
return 0;
}
代码剖析:
思考一下:
2.4 动态内存开辟空间中的常见错误
1.对空指针进行解引用操作
这个错误不用多作介绍,空指针(NULL)当然是不能进行解引用操作的
2.对动态开辟的内存越界访问
上端代码感受一下这个错误
int *p = (int *)malloc*(5 *sizoef(int));
if(p == NULL)
{
return 0;
}
else
{
for(int i = 0 ; i < 10 ; i++)
{
*(p+i) = i;
}
free(p);
p=NULL;
}
这里的错误很明显了,明明只开辟了五个空间,你缺要访问十个,有点过分呀~。
3.对非动态开辟的内存进行free操作
int main()
{
int p = 10;
free(p);
}
p在这里不是动态开辟的,如果用free释放是会报错的。
4.对同一块儿动态内存多次释放。
三.常见笔试题
3.1 传参问题的笔试题
void GetMemory(char *p)
{
p = (char *)malloc(100 *sizeof(int ));
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str,"Hello World!\n");
printf(str);
}
int main()
{
Test();
return 0;
}
上面的这段代码会不会正确输出呢?
很明显,这里没有输出“Hello World!”,
这段代码是有问题的。
那么问题出在哪里呢?
所以,这里也就很好的证明,为什么程序运行后没有输出。
那么怎么改正它呢?
还记得嘛?传值不行的时候我们可以传址过去。
成功运行
void GetMemory(char **p)
{
*p = (char *)malloc(100 * sizeof(int));
}
void Test(void)
{
char *str = NULL;
GetMemory(&str);
strcpy(str, "Hello World!\n");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
大家记得把动态开辟的空间释放以及要把指针置空。
3.2 返回栈空间的地址的问题
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
这段代码会顺利的打印“Hello World!”吗?
一起来看看。
我去,这是个什么玩意儿?为什么会打印出来这么个鬼东西?
别急,我们一起来看看吧
所以,这里返回的东西我们没有人知道会是什么。
3.3 造成内存泄漏问题
void Test(void)
{
char *str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
这段代码有没有问题呢?
正确的打印出来了。
但是,打印出来就没有问题了嘛?
所以,我们写free函数之后,都要将这个指针顺便置为空(NULL)。以防止这种不规范的行为造成不可挽回的后果。
void Test(void)
{
char *str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
str = NULL;
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
over~~~