2.5动态内存分配

动态内存分配

为什么存在,静态的通讯录(出现的警告提示)

  • 栈上开辟的空间,不能过大。

关于动态内存函数:malloc(sizeof(int)、free(ps)、calloc(10, sizeof(int))、realloc(ps,20*sizeof(int))

内存空间

内存空间

  • 动态内存分配的内存存储在堆区。

使用的函数

malloc()函数、alloc()、realloc()

int main()
{
    //假设开辟10个整形的空间  - 10* sizeof(int)
    int arr[10];//栈区
    //动态内存开辟
    //void* p = malloc(10*sizeof(int));
    int* p = (int*)malloc(10*sizeof(int));//将void* 类型转换成int*类型。
    
    //使用这些空间的时候
    if(p == NULL)
    {
        //printf("malloc error\n");
        perror("main");//错误信息打印,main: xxxxxxxxxxx   
        return 0;
    }
    //使用
    //……
    //回收空间
    free(p);
    p = NULL;
    
    return 0;
}

malloc()

void* malloc(size_t size);

向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,返回一个指向开辟空间的指针。
  • 如果不成功,返回一个空指针,因此malloc()的返回值一定要做检查。
  • 返回的是一个void*类型的指针类型,具体类型需要自己定义。
  • 如果参数size为0,malloc()的行为是标准未定义的,取决于编译器。

free();

  • 如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数ptr是NULL指针,则函数什么事情都不做。
  • alloc()
int main()
{
	int* p = (int*)calloc(10, sizeof(int));//最好加上强制类型转换。

	if (p == NULL)
	{
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", *(p + i));
	}
	free(p);
	p = NULL;

	return 0;
}

alloc()函数,和malloc()函数主要有两个区别:
void* calloc(size_t number,size_t size)

第一个:参数的不同,第二个会全部初始化成0;

realloc()
  • 使动态内存管理更加灵活。
  • 有时候会发现申请的空间太小了,或者说太大了。
int main()
{
	int* p = (int*)calloc(10, sizeof(int));//10个int的空间。
	if (p == NULL)
	{
		perror("main");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 5;
	}
	//这里需要p指向的空间更大,需要20个int的空间。
	//realloc()调整空间

	int* ptr = (int*)realloc(p, 20 * sizeof(int));
	if (ptr != NULL)
	{
		p = ptr;
	}
	for (i = 0; i < 20; i++)
	{
		*(p + i) = 5;
	}
	free(p);
	p = NULL;

	return 0;
}

realloc()函数动态内存分配的时候,会出现3种情况,一种找不到空间,一种找到了,但需要重新分配空间if条件判断中的p = ptr,还有一种是,在原来动态内存分配空间的基础上,向后开辟空间。

是两种开辟空间的时候的返回类型。1.原有空间之后有足够大的空间。2. 没有足够大的空间。

  • realloc() - 功能类似于malloc(),就是直接在堆区开辟40个字节。
int main()
{
    int* p = (int*)realloc(NULL, 40);
    //int* p1 = (int*)malloc(10*sizeof(int));
    for (int i = 0; i < 10; i++)
    {
        *(p + i) = 0;
    }
    return 0;
}

相较于动态内存分配管理,数组这种数据结构就是静态的。

动态内存出现的常见错误类型
  1. 对NULL指着的解引用操作。
int main()
{
    int* p = (int*)malloc(10*sizeof(int));
    //int* p = (int*)malloc(1000000000*sizeof(int));
    //可能找不到开辟的空间。
    if(p ==NULL)
    {
        return 1;
    }//解决方法
    
    return 0;
}
  1. 对动态开辟空间的越界访问
int main()
{
    int* p = (int*)malloc(10*sizeof(int));
    if(p == NULL)
    {
        return 1;
    }
    int i = 0;
    for(i= 0;i<20;i++)
    {
        *(p+i) = 5;
    }//越界访问内存,只开辟了10个int的空间大小。
    
    return 0;
}
  1. 使用free()释放非动态开辟的空间
int main()
{
    int arr[10] = {0};
    int* pa = arr;
    free(pa);
    pa = NULL;
    //pa不是动态开辟的内存。
    
    return 0;
}
  1. 使用free()释放动态内存中的一部分。
int main()
{
    int* p = (int*)malloc(10*sizeof(int));
    if(p == NULL)
    {
        return 1;
    }
    int i = 0;
    for(i = 0;i<5;i++)
    {
        *p++ = 5;
    }
    free(p);
    p = NULL;
    //p指向的位置变了。
    return 0;
}
  1. 对同一块动态开辟的空间,多次释放
int main()
{
    int* p = (int*)malloc(10*sizeof(int));
    if( p == NULL)
    {
        return 1;
    }
    free(p);
    //p = NULL;
    free(p);
    
    return 0;
}
  1. 动态开辟的空间忘记释放 - 内存泄漏 - 比较
void test()
{
    int* p = (int*)malloc(10*sizeof(int));
    if( p == NULL)
    {
        return;
    }
  //执行完test()后,p的空间会被销毁,
    //但malloc()开辟的空间不会被销毁。
    //需要free()
      free(p);
    p = NULL;
}
int main()
{
    test();
    return 0;
}

动态开辟的空间,2种回收方式。

  1. 主动free
  2. 程序结束 - - 就是main()函数执行完 。服务器环境中,不释放,内存泄漏。
柔性数组

C99语法中规定的,结构中的最后一个元素,是未知大小的数组。

struct S
{
	int n;
	int arr[];//大小未知。
};
//||
struct s
{
	int n;
	int arr[0];//大小未知。
};
int main()
{
    struct S s={0};
    printf("%d\n",sizeof(s));//4
	return 0;
}

结构中的 柔性数组中至少要包含一个其他成员。

sizeof返回的柔性数组大小不包含柔性数组的内存。 上面的代码。

包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适用柔性数组的期望大小。

  • 柔性数组的使用
struct S
{
	int a;
	int arr[0];
};
int main()
{
	//使用
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	ps->a = 10;
	
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	//扩容
	struct S* ptr = (struct S*)realloc(ps,sizeof(struct S) + 20*sizeof(int));
	if (ptr != NULL)
	{
		ps = ptr;
	}
	//释放
	free(ps);
	ps = NULL;
	return 0;
}
  • 不使用柔性数组
struct S
{
	int n;
	int* arr;
};

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S)); //为什么不是sizeof(strucnt S)
	if (ps == NULL)
		return 1;
	ps->n = 10;
	ps->arr= (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
		return 1;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	//扩容
	int* ptr = realloc(ps ->arr,20 * sizeof(int));
	if (ptr != NULL)
	{
		ps->arr = ptr;
	}
	
	//使用

	//释放
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;

	return 0;
}

概念:内存碎片、内存池;
方法1:
1.方便内存释放 2.有利于提升访问速度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值