一、常见的动态内存使用错误
在使用动态内存分配的时候,如果不细心的话也许会出现错误,以下为几种常见类型的错误,一起来看看把。
1.对NULL指针的解引用操作:
看看下面这个例子
int main()
{
int *p=(int*)malloc(INT_MAX);//INT_MAX为C语言宏定义的最大值
*p=12;
free(p);
return 0;
}
这个代码有什么问题?
如果细心的话就会发现,此时动态开辟的空间过于大,很可能会导致动态内存分配失败,使指针变量p接收的是一个NULL,这样的话,p就成为了一个空指针。
空指针不能进行解引用操作!
因此,为了预防这种情况发生,我们最好在使用指针变量前判断其是否为空指针。
int main()
{
int *p=(int*)malloc(INT_MAX);//INT_MAX为C语言宏定义的最大值
//判断
if(p==NULL)
{
return 1;
}
*p=12;
free(p);
return 0;
}
2.越界访问
对于越界访问的情况其实我们都不陌生,在学习数组的时候,也很强调不能越界访问。
int main()
{
int *p=(int *)malloc(10*sizeof(int));
//判断是否为空指针
if(p==NULL)
{
return 1;
}
//使用
int i=0;
for(i=0;i<=10;i++)
{
*(p+i)=i;//当i=10已经越界访问了,所以循环判断条件应该修改为i<10
}
//释放空间
free(p);
p=NULL;
return 0;
}
3.释放空间
对于自己动态开辟的空间,使用结束不需要再次使用的情况下,需要我们手动去释放掉这些空间,不然在程序结束前,这些内存空间会被一直被占用
另外,使用free函数释放空间时,要确保输入的参数是内存开辟空间的首地址,每当使用free函数释放空间前,大家可以看看前面的代码,看看开辟空间的首地址是否已经在使用过程中被改变了。
二、一道动态内存题目
学习了相关知识之后,我们可以来看一个题目,加深一下理解。不过看题目之前,我们来学习一个字符串函数,这个函数将在题目中出现。
#include<string.h>
char * strcpy(char *dest ,const char *src)
功能:复制一个字符串的内容到另一个字符串的结束标志'\0'处
参数:被连接的字符串的结束标志'\0'的地址dest 连接内容字符串的首地址src
看看效果:
进入主题,看看接下来要探讨的题目:
#include<stdio.h>
#include<string.h>
void GetMemory(char *p)
{
p=(char *)malloc(100);//开辟100个字节的空间,首地址为p
}
void test(void)
{
char*str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf("%s",str);
}
int main()
{
test();
return 0;
}
请问:程序运行会不会打印出来:hello world?
答案其实是不会。我们可以来逐步研究一下这个代码。
首先,如果认为会打印成功的伙伴是不是认为将str作为GetMemory()参数,然后GetMemory()函数就会开辟100个字节的空间,让str作为首地址?
按照这样的设想,那么程序就会打印出来hello world,既然没有打印,说明str没有接收到动态开辟空间的首地址,那么谁存入这个首地址?
其实是形式参数p,学过C语言函数的都知道,函数的形参是对实际调用函数过程中传入的实参的一份临时拷贝。本质上,指针变量p和指针变量str是两个不同的变量。只是在未执行函数语句之前,p和str的内容是一样的,都为NULL。但是,后续对p进行赋值操作,其实跟str没有一毛钱关系。
那么有什么方法可以解决?当然有!那就是以二级指针作为形参,通过解引用操作直接锁定str的内容,对其赋值,如果你听不懂,那可以看看下面具体的代码。
三、柔性数组
1.什么是柔性数组?
结构体中的最后一个成员允许是未知大小的数组,这样的数组即为柔性数组。
注意:
01.柔性数组只会存在在结构体中
02.柔性数组只能是结构体的最后一个成员
03.此结构体不能只有柔性数组这一个成员
//柔性数组
struct Stu
{
int i;
int a[0];//柔性数组
};
这是一种写法,也有另一种写法:即 int a[]
2.柔性数组的特点
包含柔性数组成员的结构体用malloc()函数进行动态内存分配,并且分配的大小应该大于结构体的大小(即sizeof(struct Stu)的大小)
这里需要注意的是:由于柔性数组大小未知,sizeof(struct Stu)计算求得的大小不包括数组的大小,只包含除了柔性数组以外其他成员的大小。看看例子:
3.给包含柔性数组成员的结构体动态开辟内存
给出一个公式:
开辟空间大小=sizeof(结构体)+数组需要的空间
//创建包含柔性数组的结构体
struct Stu
{
int i;
int a[0];
};
//为结构体开辟空间
int main()
{//开辟空间
struct Stu*ps=(struct Stu*)malloc(sizeof(struct Stu )+10*sizeof(int));
//判断是否开辟成功
if(ps==NULL)
{
return 1;
}
//使用......
//释放空间和置空指针
free(ps);
ps=NULL;
return 0;
}
4.包含柔性数组的结构体的使用
这种包含柔性数组的结构体与含有数组的结构体的使用情况差不多是一样的。以给结构体每一个成员赋值为例子。