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

【C语言】动态内存管理

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

【C语言】动态内存管理

动态内存分配存在的原因:

        节省内存空间。若预先开辟一块空间,小了导致不够用数组越界,大了用不完造成内存空间浪费。

malloc函数、calloc函数与free函数

malloc

#include 

void* malloc (size_t size)  
//void*方便后续使用 需要什么类型的指针 强制类型转换一下即可
//size的大小是字节的大小

//例如要用malloc模拟int arr[10] = {0}
int* p = (int *) malloc(40);

calloc

#include 

void* calloc (size_t num, size_t size)  
//num表示元素个数
//size表示每个元素的大小

//例如要用calloc模拟int arr[10] = {0}
int* p = (int *) calloc(10,sizeof(int));

        对malloc,若开辟成功,函数返回一个void*指针;若因为堆内存空间不足开辟失败,函数返回NULL。      

        malloc和calloc函数的区别一个是参数不一样,另一个是malloc不会初始化数组,而calloc会初始化数组元素为0。所以直接返回地址的malloc效率会更高一些。

realloc

#include 

void* realloc(void* ptr, size_t size);
//ptr表示一个由malloc, calloc, realloc开辟的指针
//若ptr是空指针 那realloc和malloc的作用是相同的

        realloc的作用是扩容,但是扩容会有几种不同的情况发生。

Ⅰ:在堆中,ptr后面有充足的空间,则顺利扩容,返回的指针值和ptr相同

Ⅱ:若ptr的直接后面没有足够的目标空间开辟,即后面的空间可能已经被别的数据占用,则函数会在另一个位置重新开辟完整的空间,返回的指针值就和ptr不同,是一个全新的地址,同时原来ptr代表的一块内存空间也被释放销毁

Ⅲ:若整个堆中都找不到足够的空间,函数会返回空指针,开辟失败

        针对情况Ⅲ,使用realloc函数时候要注意:

        ①不直接用函数返回的指针赋值给原来的指针,因为要是开辟失败返回空指针,那原来的地址也找不到了

        ②对返回的指针进行判断,不是空指针再继续使用 

int* ptr = (int*) malloc(100);
int* tmp = (int*) realloc(ptr, 1000);

if (NULL != tmp)
    ptr = tmp;

free

        内存开辟后,若使用完毕了最好还是能够回收内存,就需要用上free函数

#include 

void free (void* p)

        注意!malloc函数得到的指针最开始是存有一个堆中的地址的,free之后,原来堆中被占用的内存可以给别处用了,但是指针存的地址还在,这就导致形成了一个野指针,所以需要把指针赋一个NULL,这样他就无法再次被使用了。

        有一个感觉没啥用的函数strerror(errno)

#include 
#include   //需要头文件
#include 

int main()
{
	int* arr = (int*)malloc(40000000000000000);
	if (NULL == arr)
	{
		printf("%sn", strerror(errno));
		return 0;
	}

    free (arr);
    arr = NULL;

	return 0;
}

//输出Not enough space
常见的动态内存问题

对空指针NULL解引用

对动态开辟的空间越界访问

对非动态内存进行free释放        

使用free释放内存的一部分

没有对动态内存释放导致内存泄漏

函数返回栈区地址问题

        探究这个问题之前我们还是先来复习一下内存的区域功能划分,如图: 

        临时的数据都是再栈上开辟的,而动态内存时在堆区开辟的。两者的区别在于栈区的数据会在局部函数结束后被销毁,比如说形参,局部函数中的变量,而堆区则会在程序执行结束后,或者主动释放后才销毁回收。这两者的区别就造成了返回栈区地址的问题。

        常见错误的代码如下:

char* GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
void Test(void)
{
    char* str = NULL;
    str = GetMemory();
    printf(str);
}

        p确实存储了字符数组p的首元素地址,但是在GetMemory函数调用结束后,p[]所在的栈空间就被销毁回收了,字符数组的内容不复存在,返回值p代表的指针也成了空指针。

        又如:

int* test(int* p)
{
	int a = 10;
	return &a;
}
int main()
{
	int* i = 0;
    i= test(&i);
	printf("%d", *i);
    //输出10
	return 0;
}

        这里同样时返回了栈区地址,为什么可以正确得到10的结果?

        因为栈空间确实已经释放,但是原来10的空间暂时还没有被其他数据替换、占用,所以10的值并没有改变。假若在printf("%d", *i);前一行打印任何东西,就可以发现不再能输出结果10。

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

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

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