前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入探索C语言动态内存分配:释放你的程序潜力

深入探索C语言动态内存分配:释放你的程序潜力

作者头像
Kevin_17
发布2024-03-24 10:43:11
750
发布2024-03-24 10:43:11
举报
文章被收录于专栏:Base_CDNKevinBase_CDNKevin

动态内存分配的意义

假如我们创建一个存放一百个元素的数组:

代码语言:javascript
复制
char arr[100] = {0};

如果我们要用这个数组来存储数据的话只能存储100个char型的数据,如果再想要往数组内添加数据的话就会越界。

所以在这个时候有两种方法,第一个方法是再创建一个数组然后将两个数组拼接,第二个方法时用动态内存分配。动态内存分配的快捷,实用性和可操控要比第一种方法强很多,那么究竟强在哪里呢?在这篇博客中我将进行具体阐述。

动态内存分配相关函数

1. malloc

malloc函数用来向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针。

该函数原型如下:

代码语言:javascript
复制
void* malloc (size_t size);

可以看出,该函数的返回值是void*说明返回类型可以改变,传的参数size作用是向内存申请size大小的内存,用size_t类型可以不用担心申请的内存过大而不能完成申请。

对于开辟内存的结果和操作:

  • 如果开辟成功,则返回⼀个指向开辟好空间的指针。
  • 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。
  • 返回值 的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃⼰来决定。
  • 如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器

2. free

free函数用来释放动态分配的内存(只能释放动态分配的内存),函数原型如下:

代码语言:javascript
复制
void free (void* ptr);

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。
  • 如果参数 ptr 是NULL指针,则无事发生。

在了解到malloc和free函数后就可以利用这两个函数进行一个简单的实例代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int num = 0;
    scanf("%d", &num);
    int arr[num] = {0};
    int* ptr = NULL;
    ptr = (int*)malloc(num*sizeof(int));
    if(NULL != ptr)//判断ptr指针是否为空
    {
    	int i = 0;
        for(i=0; i<num; i++)
        {
        	*(ptr+i) = 0;
        }
    }
    free(ptr);//释放ptr所指向的动态内存
    ptr = NULL;//是否有必要?
    return 0;
}

该段代码就是实现动态分配,然后释放分配的空间。

3. calloc

calloc 函数也⽤来动态内存分配。原型如下:

代码语言:javascript
复制
void* calloc (size_t num, size_t size);

  • 函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0。
  • 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全 0.

示例代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL != p)
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	free(p);
	p = NULL;
	return 0;
}

示例代码结果:

代码语言:javascript
复制
0 0 0 0 0 0 0 0 0 0

从函数的特性出发,如果我们对函数有初始化的需求的话可以直接使用 calloc 函数来进行内存空间的开辟,效果与 malloc 一样。

4. realloc

realloc 函数实现的是对原本开辟的空间进行调整大小,函数原型如下:

代码语言:javascript
复制
void* realloc (void* ptr, size_t size);  

  • ptr 是要调整的内存地址
  • size 调整之后新⼤⼩
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动(copy)到新的空间。
  • realloc在调整内存空间的是存在两种情况:

​ 情况1:原有空间之后有⾜够⼤的空间 ​ 情况2:原有空间之后没有⾜够⼤的空间 ​ 以上所说两种空间是在内存上的空间,不是当前动态分配到的空间

4.1 原有空间足够大

当原有空间足够大时,我们要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。

4.2 原有空间不够

当原有的空间不够时,我们在堆空间上另找⼀个合适大小的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

realloc使用示例代码:

代码语言:javascript
复制
#include <stdlib.h>
int main()
{
	int* ptr = (int*)malloc(100);
	if (ptr != NULL)
	{
		//业务处理
	}
	else
	{
		return 1;
	}
	//扩展容量
	//代码1 - 直接将realloc的返回值放到ptr中
	ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)
	//代码2 - 先将realloc函数的返回值放在p中,不为NULL,在放ptr中
	int* p = NULL;
	p = realloc(ptr, 1000);
	if (p != NULL)
	{
		ptr = p;
	}
	//业务处理
	free(ptr);
	return 0;
}

常见动态内存错误

1. 对NULL指针解引用

代码语言:javascript
复制
void test()
{
	int* p = (int*)malloc(INT_MAX / 4);
	*p = 20;//如果p的值是NULL,就会有问题
	free(p);
}

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

代码语言:javascript
复制
void test()
{
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	if (NULL == p)
	{
		exit(EXIT_FAILURE);
	}
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;//当i是10的时候越界访问
	}
	free(p);
}

3. 对⾮动态开辟内存使⽤free释放

代码语言:javascript
复制
void test()
{
	int a = 10;
	int *p = &a;
	free(p);//error
}

4. 使⽤free释放⼀块动态开辟内存的⼀部分

代码语言:javascript
复制
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}

5. **对同⼀块动态内存多次释放 **

代码语言:javascript
复制
void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);//重复释放
}

6. 动态开辟内存忘记释放(内存泄漏)

代码语言:javascript
复制
void test()
{
	int* p = (int*)malloc(100);
	if (NULL != p)
	{
		*p = 20;
	}
}
int main()
{
	test();
	while (1);
}

结语

以上就是关于动态内存管理的博客内容。值得强调的是关于 free 掉内存这件事,一个程序如果不在不需要的时候free掉内存的话就会一直占用内存直到程序运行结束。

在我们平时的代码练习中不会有明显的影像,但是在大型程序中,如果内存一直占用,占用的内存不断增多,内存是有限的,不可能一直被占用,当内存爆满时程序就会出现问题了。

所以要注意关于内存空间的释放!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态内存分配的意义
  • 动态内存分配相关函数
    • 1. malloc
      • 2. free
        • 3. calloc
          • 4. realloc
            • 4.1 原有空间足够大
            • 4.2 原有空间不够
        • 常见动态内存错误
          • 1. 对NULL指针解引用
            • 2. 对动态开辟空间的越界访问
              • 3. 对⾮动态开辟内存使⽤free释放
                • 4. 使⽤free释放⼀块动态开辟内存的⼀部分
                  • 5. **对同⼀块动态内存多次释放 **
                    • 6. 动态开辟内存忘记释放(内存泄漏)
                    • 结语
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档