前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C/C++动态内存开辟详解(含常见错误以及经典面试题)

C/C++动态内存开辟详解(含常见错误以及经典面试题)

作者头像
利刃大大
发布2023-04-12 13:55:25
7530
发布2023-04-12 13:55:25
举报
文章被收录于专栏:编程语言/linux/算法

1.四个重要的内存函数

1.1 malloc和free

C语言提供了一个动态内存开辟的函数:

void malloc (size_t size);*

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

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

C语言还提供了另外一个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:

void free(void ptr);

free函数用来释放动态开辟的内存。

  • 如果参数ptr指向的空间不是 动态开辟(如数组名) 的,那free函数的行为是未定义的。
  • 如果参数ptrNULL指针,则函数什么事也不做。

malloc和free都声明在stdlib.h头文件中。

1.2 calloc

C语言还提供了一个函数叫calloccalloc函数也用来动态内存开辟。原型如下:

void calloc(size_t num,size_t size);*

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

1.3 realloc

  • realloc函数的出现让动态内存管理更加灵活。
  • 有时我们会发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的使用内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小的调整

函数原型如下:

void realloc(void ptr,size_t size);**

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

情况1: 原有空间之后有足够大的空间

情况2: 原有空间之后没有足够大的空间

2.常见错误

2.1 对NULL指针进行解引用操作

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int *p = (int*)malloc(100000000000);//开辟内存过大,可能会开辟失败,返回空指针
	int i = 0;
	for(i = 0;i<10;i++)
	{
		*(p+i) = i;
	}
}

解决方法:在申请空间后对p进行判断

if(p == NULL) return 1;

2.2 对动态开辟内存的越界访问

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int *p = (int*)malloc(10*sizeof(int));//申请10个int空间大小
	if(p==NULL)
		return 1;
		
	int i=0;
	// 越界访问
	for(i=0;i<40;i++)
	{
		*(p+i)=i;
	}
}

2.3 使用free释放非动态开辟的空间

代码语言:javascript
复制
int main()
{
	int arr[10]={0}//存于栈区
	int *p=arr;

	free(p);//使用free释放了数组申请的空间
	p=NULL;
	return 0;
}

2.4 使用free释放了动态开辟内存的一部分

代码语言:javascript
复制
int main()
{
	int* p=(int*)malloc(10*sizeof(int));
	if(p==NUL)
		return 1;
	
	int i=0;
	for(i=0;i<5;i++)
	{
		*p++ = i;
	}
	free(p);
	p=NULL;
	return 0;
}

解读:p指向开辟内存的首地址,而在循环赋值中,p只对其中5个int大小进行了赋值,而后就对该空间释放。除此之外p受++运算符不断向后移动,使得p的初始位置改变,这很容易导致内存泄漏

2.5 对同一块动态内存开辟的空间多次释放

代码语言:javascript
复制
int main()
{
	int* p=(int*)malloc(100);
	//使用
	//释放
	free(p);
	p=NULL;

	//释放
	free(p);
	return 0;
}

2.6 动态开辟的空间忘记释放,造成内存泄漏

解决方法:在该指向这块空间的指针的生命周期结束前使用free函数释放。

3.经典面试题

第一题

代码语言:javascript
复制
void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str=NULL;
	GetMemory(str);
	strcpy(str,"hello,liren");
	printf(str);
}

请问运行Test函数会有什么样的结果?

答案:程序奔溃

解读:str传给GetMemory函数的时候是值传递(因为并不是使用str所指地址的值而是改变str本身的值),所以GetMemory函数的形参pstr的一份临时拷贝。在GetMemory函数内部动态申请空间的地址,存放在p中,不会影响外边str,所以当GetMemory函数返回之后,str仍然是NULL,所以strcpy会失败。(当GetMemory函数返回之后,形参p销毁,使得动态开辟的100个字节存在内存泄露)

第二题

代码语言:javascript
复制
char* getmemory(void)
{
	char p[]="hello,liren";
	return p;
}
void test(void)
{
	char* str=NULL;
	str=getmemory();
	printf(str);
}
int main()
{
	test();
	return 0;
}

这种题称为返回栈空间地址的问题

答案:一堆乱码

解答:getmemory函数内部创建数组是在栈区上创建的,出了函数,p数组的空间就还给了操作系统,返回的地址是没有实际的意义的,如果通过返回的地址,去访问内存就是非法访问内存的。

第三题

代码语言:javascript
复制
void getmemory(char** p,int num)
{
	*p = (char*)malloc(num);
}
void test(void)
{
	char* str=NULL;
	getmemory(&str,100);
	strcpy(str,"liren");
	printf(str);
}
int main()
{
	test();
	return 0;
}

答案:程序奔溃!

解答:应在test函数里面使用free函数释放str,并将其设为空指针

第四题

代码语言:javascript
复制
void test(void)
{
	char* str=(char*)malloc(100);
	strcpy(str,"liren");
	free(str);
	if(str!=NULL)
	{
		strcpy(str,"love tongtong");
		printf(str);
	}
}
int main()
{
	test();
	return 0;
}

答案:程序奔溃

解答:test函数中提前free了一次,造成下面的非法访问内存。(注:使用free后并不会将指针置空,必须要手动置空

到此为止,应该对动态内存开辟有相当的了解了吧,那接下来我会更新如何运用动态内存开辟制作一个通讯录,持续更新!(还将设计文件操作的知识)

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.四个重要的内存函数
  • 1.1 malloc和free
  • 1.2 calloc
  • 1.3 realloc
  • 2.常见错误
    • 2.1 对NULL指针进行解引用操作
      • 2.2 对动态开辟内存的越界访问
        • 2.3 使用free释放非动态开辟的空间
          • 2.4 使用free释放了动态开辟内存的一部分
            • 2.5 对同一块动态内存开辟的空间多次释放
              • 2.6 动态开辟的空间忘记释放,造成内存泄漏
              • 3.经典面试题
                • 第一题
                  • 第二题
                    • 第三题
                      • 第四题
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档