动态内存管理(续)+柔性数组

目录

1.几道笔试题

1.1题目一:

 1.2题目二

1.3题目三

1.4第四题

2.动态内存管理复习

 3.柔性数组

 3.1柔性数组的特点

 3.2柔性数组的使用

3.3柔性数组的优点 


1.几道笔试题

1.1题目一:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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柔性数组的特点

  1. 结构中的柔性数组成员前面必须至少一个其他成员。否则结构体大小为0
  2. sizeof 返回的这种结构大小不包括柔性数组的内存。
  3. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

 eg:

#include<stdio.h>
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<stdio.h>
#include<stdlib.h>
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开辟的空间不一定是连续的,中间会存在一些空隙,我们把这些空隙称为内存碎片

博主能力有限,如有误区,欢迎各位铁汁批评斧正

今天就到这里吧,感谢观看哈

猜你喜欢

转载自blog.csdn.net/weixin_63451038/article/details/123997636