目录
1.几道笔试题
1.1题目一:
1.2题目二
1.3题目三
1.4第四题
2.动态内存管理复习
3.柔性数组
3.1柔性数组的特点
3.2柔性数组的使用
3.3柔性数组的优点
1.几道笔试题
1.1题目一:
#include
#include
#include
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
Test();
return 0;
}
运行结果
文章图片
由于p为形参,开辟完空间出了GetMemory函数就会被销毁,此时没有指针能找到开辟空间的地址,造成内存泄漏问题,因此str还是NULL,而strcpy实现时需要将str进行解引用操作(对NULL解引用)会出问题(非法访问内存),程序崩溃。strcpy的实现可以参考C语言之字符串+内存函数_臻白林子的博客-CSDN博客_c语言字符串内置函数
注意:这里的printf(str)写法本身是没有问题的,只是由于上面的原因导致无法打印。改法一
举个例子:printf("abc")实际是把首元素a的地址传给printf函数,char *str="abc",str存的是“abc”首元素的地址,相当于数组名,所以printf(str)是合理的。
#include
#include
#include
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
运行截图
文章图片
改法二
#include
#include
#include
char* GetMemory(char* p)
{
*p = (char*)malloc(100);
return p;
}
void Test(void)
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
1.2题目二
#include
#include
#include
char* GetMemory(void)
{
char p[] = "hello world";
//这块空间是在栈区开辟的,出函数后空间自动销毁
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
当出了GetMemory函数后,“helloworld”这块空间已被释放,p已经没有使用权限了,是个野指针,当再次访问这块空间时,这块空间可能已经被覆盖了(非法访问空间)
举个例子:比如李华工作累了,不想回家休息,在外边找了个酒店住,房间是509,由于太累了,睡了一会,正巧李华的外国朋友John明天要到当地游玩,想找个地方住,就打电话给李华,李华:行,你明天过来住吧,我在509,第二天起床,李华就把房间给退了,john听到昨天李华说可以住509,就直接拖着行李过来酒店说:我就要住509,但是房间已经有人入住了.........
文章图片
改法:static修饰
#include
#include
#include
char* GetMemory(void)
{
static char p[] = "hello world";
//静态区
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
1.3题目三
#include
#include
#include
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;
}
动态开辟的空间用完后要用free释放 ,并把指针置空改法
#include
#include
#include
void GetMemory(char** p, int num)
{ *p = (char*)malloc(num);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
free(str);
str=NULL;
}
int main()
{
Test();
return 0;
}
1.4第四题
#include
#include
#include
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
//hello所在的空间已经还给操作系统,此时str为野指针
//free之后,一定要将指针置空
if (str != NULL)
{
strcpy(str, "world");
//world会把hello覆盖,(非法访问)
printf(str);
}
}
int main()
{
Test();
return 0;
}
运行截图
文章图片
改法
#include
#include
#include
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;
}
2.动态内存管理复习 c语言之动态内存管理_臻白林子的博客-CSDN博客
3.柔性数组
结构体中的最后一个元素允许是未知大小的数组,称为柔性数组成员例如:
struct s1
{
int age;
char name[20];
int arr[];
//柔性数组成员
};
有些编译器下会报错,可以试试下面这种写法。
struct s2
{
int age;
char name[20];
int arr[0];
//柔性数组成员,这里的0代表未知大小
};
3.1柔性数组的特点
eg:
- 结构中的柔性数组成员前面必须至少一个其他成员。否则结构体大小为0
- sizeof 返回的这种结构大小不包括柔性数组的内存。
- 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
#include
struct s2
{
int age;
//4
char name[20];
//20
int arr[0];
//0
};
int main()
{
printf("%d\n", sizeof(struct s2));
return 0;
}
文章图片
3.2柔性数组的使用
#include
#include
struct s3//4
{
int num;
int arr[];
};
int main()
{
struct s3* ps = (struct s3*)malloc(sizeof(struct s3) + 40);
//假设我们希望数组中有10个元素
ps->num = 100;
int i = 0;
//使用
for (i = 0;
i < 10;
i++)
{
ps->arr[i] = i;
}
//增容
struct s3* ptr = realloc(ps, sizeof(struct s3) + 80);
if (ptr != NULL)
{
ps = ptr;
}
for (i = 10;
i < 20;
i++)
{
ps->arr[i] = i;
}
for (i = 0;
i < 20;
i++)
{
printf("%d ", ps->arr[i]);
}
//释放
free(ps);
ps = NULL;
//置空
return 0;
}
另一种类似柔性数组的写法
struct s3//sizeof计算为8
{
int num;
int *arr;
};
int main()
{
struct s3* ps = (struct s3*)malloc(sizeof(struct s3));
ps->arr = (int*)malloc(sizeof(int) * 5);
int i = 0;
//使用
for (i = 0;
i < 5;
i++)
{
ps->arr[i] = i;
}
//增容
int * ptr = realloc(ps->arr, 10*sizeof(int));
if (ptr != NULL)
{
ps->arr = ptr;
}
for (i = 5;
i < 10;
i++)
{
ps->arr[i] = i;
}
for (i = 0;
i < 10;
i++)
{
printf("%d ", ps->arr[i]);
}
//释放
free(ps->arr);
free(ps);
ps = NULL;
//置空
return 0;
这两者的区别是
1.柔性数组所在的结构体大小为4,而下面这个结构体大小为8
2.柔性数组只存在于结构体中,而下面这个方法是通用的(动态开辟内存空间)
3.3柔性数组的优点
1.方便内存释放如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。2.有利于访问速度 .连续的内存有益于提高访问速度,也有益于减少内存碎片由于多次使用malloc开辟的空间不一定是连续的,中间会存在一些空隙,我们把这些空隙称为内存碎片
文章图片
博主能力有限,如有误区,欢迎各位铁汁批评斧正
【笔记|动态内存管理(续)+柔性数组】今天就到这里吧,感谢观看哈
推荐阅读
- spring|基于springboot社区疫情防控管理系统
- C语言|C语言static关键字的作用(有三个作用)
- SpringBoot|Spring Boot 参考文档(官网对照翻译)
- Java基础|Java程序员的重启人生-3.Java基础碾压
- CS4182解析
- 学习|使用c语言对sql server进行增删改查操作
- 使用C++实现trie树(单词查找树,字典树)
- python数据结构之set的用法详解
- Python字典(Dictionary)完全解读和用法详解