栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

2.5动态内存分配

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2.5动态内存分配

文章目录
      • 动态内存分配
          • 内存空间
      • 使用的函数
            • realloc()
            • 动态内存出现的常见错误类型
        • 柔性数组

动态内存分配

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

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

关于动态内存函数: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 errorn");
        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("%dn", *(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("%dn",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.有利于提升访问速度

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869957.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号