05动态内存管理(代码片段)

再吃一个橘子 再吃一个橘子     2023-01-06     303

关键词:

 我知道的只是  “ 肉随便加  ”和  “ 要加多少加多少  ” 这些词。    ———— 路飞 

阶段2目标:

此阶段开始大量刷题,多多参加编程类竞赛,在实战中锻炼编程思维和本领,并且要在不断复习夯实初阶的基础上,刻意地进行编程思维的训练。学无止境!为了精进编程,可以去学习一切为他服务的课程!

目录

本章重点:

一、为什么存在动态内存分配?

二、动态内存函数的介绍

1.malloc函数

2.free函数

3.calloc函数

 malloc与calloc的异同:

4.realloc函数   (为了更合理的时候内存)

 三、常见动态内存错误

1.对NULL指针的解引用操作

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

3.对非动态开辟内存使用free释放

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

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

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

切记: 动态开辟的空间一定要释放,并且正确释放

应用:动态通讯录(优化版)

四、经典面试题目

题目1

小知识点

题目2

延伸题目,深入理解

题3

总结:题1题2题3,都属于一类题目,返回栈空间地址的问题。注意栈空间地址不要轻易返回,因为栈出了范围会销毁。

注意:销毁的意思只是指   该栈空间的使用权限还给了操作系统,这块空间仍然存在!!

五、C/C++程序的内存开辟

六、柔性数组

1.什么是柔性数组

2.柔性数组的特点

3.柔性数组的使用

4.柔性数组的优势

总结:相比较而言,用柔性数组优势更多!


本章重点:

1.为什么存在动态内存分配

2.动态内存函数的介绍

  • malloc
  • free
  • calloc
  • realloc

3.常见的动态内存错误

4.几个经典的笔试题

5.柔性数组

一、为什么存在动态内存分配?

我们已经掌握的内存开辟方式有:

int val = 20;//在栈空间上开辟四个字节
char arr[10] = 0;//在栈空间上开辟10个字节的连续空间

但是,上述开辟空间的方式有两个特点:

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。 这时候就只能用动态内存开辟了。

二、动态内存函数的介绍

我们所知道,我们在堆区实现动态内存分配,利用malloc   、   calloc  、   realloc   、  free函数去进行相应的动态分配操作。如图:

1.malloc函数

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

void*   malloc(  size_t size   );

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

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

解释:

1.malloc函数的确官方定义是void* 指针,即:万能型指针。但是我们使用者在使用malloc的时候,需要用具体的类型,来接收,比如:int*  、char* 

这样写,在解引用取空间中的值得时候,才不会报错;而如果是void* 去接收,解引用时就会有错误,因为编译器面对void*  该万能型指针,并不清楚去解引用几个字节。

即:在接收时,需要用具体的数据类型来接收malloc的空间

”错误“  代码:

int main()

	//int arr[10] =  0 ;

	void* p = malloc(40);

	return 0;

 正确代码:

int* p = (int*)malloc(40);

2.如果开辟失败,则返回一个NULL指针,即:malloc的返回值一定要做检查

#include <stdio.h>
#include<stdlib.h>
int main()

	//int arr[10] =  0 ;

	//申请空间
	int* p = (int*)malloc(40);//开辟了40个字节空间,即:10个int类型空间

	//判断是否 申请失败
	if (p == NULL)
	
		printf("申请失败!");
		return -1;
	

	//开辟成功了

	//(初始化)/(赋值)
	int i = 0;
	for (i = 0; i < 10; i++)
	
		*(p + i) = i;
	

	//释放空间
	free(p);

	return 0;

我们用  *( p + i ) = i;的方式来赋予空间内以初值,用free函数释放掉指针p维护的10个int类型的空间。而我们调试发现,free掉p之后,仅仅是那10个空间被释放掉了,而指针p仍旧是指向那块空间的地址,构成了一个野指针,所以以后就很危险,需要将p=NULL;让程序更安全

#include <stdio.h>
#include<stdlib.h>
int main()

	//int arr[10] =  0 ;

	//申请空间
	int* p = (int*)malloc(40);//开辟了40个字节空间,即:10个int类型空间

	//判断是否 申请失败
	if (p == NULL)
	
		printf("申请失败!");
		return -1;
	

	//开辟成功了

	//(初始化)/(赋值)
	int i = 0;
	for (i = 0; i < 10; i++)
	
		*(p + i) = i;
	

	//释放空间
	free(p);
	p = NULL;
	return 0;

2.free函数

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

void  free( void *memblock );

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

  1. 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  2. 如果参数 ptr 是NULL指针,则函数什么事都不做。
     

解释:

1.如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

2.如果参数 ptr 是NULL指针,则函数什么事都不做。

假如  p指针并不是malloc来的,那么对于free(p);在C语言中是未定义的,即:free也不知道该怎么办了。

总结:

除非 p 本身等于NULL,否则free以后不会等于NULL。因为free不对指针的值做任何操作,而只是试图改变指针指向的一片连续的存储器空间的状态。如果这片存储器空间是malloc或其它兼容方式(例如POSIX库函数strdup)分配过来的,那么会释放这片空间,释放的空间可以之后再次被分配。如果指针本来就等于NULL,则调用free不会有任何作用。除以上两种情况外(包括再次free已经被free过的非空指针),free的行为是未定义的,比较有可能的是free这个指针进程在某个时刻突然莫名其妙地崩溃

3.calloc函数

C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配。原型如下:

void*  calloc( size_t num ,  size_t size );

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

#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()

	int* p = calloc(10, sizeof(int));

	//errno是存储错误信息
	//用strerror函数返回 错误码所对应的错误信息

	if (p == NULL)
	
		printf("%s\\n", strerror(errno));
		return -1;
	

	//开辟成功了

	int i = 0;
	for (i = 0; i < 10; i++)
	
		printf("%d ", *(p + i));
	

	//释放空间
	free(p);
	p = NULL;

	return 0;

可能对于malloc与calloc有些疑问?什么情况下会开辟失败??     当然,内存空间不是无限大的,如果你开辟的过多,就会开辟失败,如:

 malloc与calloc的异同:

同:都可以动态分配内存空间

异:

malloc函数仅仅是申请内存空间,并且返回起始地址,并不去初始化;而calloc函数既申请内存空间,并且返回起始地址,又去初始化每个字节为0。

总结:

在应用中,想要初始化就应用calloc,不想初始化就用malloc即可。

4.realloc函数   (为了合理的时候内存

(追加增容)

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

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

  1. ptr 是要调整的内存地址。
  2. size 是调整之后新大小空间。
  3. 返回值为调整之后的内存起始位置。(  起初整个内存的开头  )
  4. 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到的空间。
  5. realloc在调整内存空间的是存在两种情况:
  • 情况1:原有空间之后有足够大的空间
  • 情况2:原有空间之后没有足够大的空间
     

情况1 当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间原来空间的数据不发生变化

情况2 当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址

由于上述的两种情况,realloc函数的使用就要注意一些。

原有空间之后有足够大的空间

原有空间之后没有足够大的空间

#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()

	//calloc,申请空间,并初始化为0
	int* p = calloc(10, sizeof(int));

	//errno是存储错误信息
	//用strerror函数返回 错误码所对应的错误信息

	if (p == NULL)
	
		printf("%s\\n", strerror(errno));
		return -1;
	

	//开辟成功了

	int i = 0;
	for (i = 0; i < 10; i++)
	
		*(p + i) = i;
	

	//空间不够,增加空间至 20个int
	int* ptr = (int*)realloc(p, 20 * sizeof(int));
	if (ptr != NULL)
	
		p = ptr;
	
	//以防空指针,造成越界访问,程序崩溃
	else
	
		return -1;
	
	//给新开辟的空间赋值
	for (i = 10; i < 20; i++)
	
		*(p + i) = i;
	

	//打印
	for (i = 0; i < 20; i++)
	
		printf("%d ", *(p + i));
	
	//释放空间
	free(p);
	p = NULL;

	return 0;

 三、常见动态内存错误

1.对NULL指针的解引用操作

错误写法:

	int* p = (int*)malloc(20);
	*p = 20;//直接这样写,是有风险的!!

	free(p);

 改写:

	int* p = (int*)malloc(20);
	if (p == NULL)
	
		return -1;
	

	*p = 20;

	free(p);

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

错误写法:

int main()

	
	int* p = (int*)malloc(200);
	if (p == NULL)
	
		return -1;
	
	int i = 0;
	for (i = 0; i <= 80; i++)
	
		*(p + i) = i;//当i是10的时候越界访问
	
	free(p);
	p = NULL;

	return 0;

改写:

int main()

	//此处的200,不是200个空间,而是200个字节,对应到int类型只是50个空间
	//而 访问的是0 ~ 80,造成了越界访问
	int* p = (int*)malloc(200);
	if (p == NULL)
	
		return -1;
	
	int i = 0;
	for (i = 0; i <= 50/*80*/; i++)
	
		*(p + i) = i;//当i是10的时候越界访问
	
	free(p);
	p = NULL;

	return 0;

3.对非动态开辟内存使用free释放

错误代码:

int main()

	int a = 10;
	int* p = &a;
	free(p);
	p = NULL;

	return 0;

该错误在于,变量a在内存的栈区,而free是释放动态内存的,即:对堆区的空间才有用,此时程序会崩溃。

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

错误代码:

int main()

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	
		return -1;
	

	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	
		*p++ = i;
	

	free(p);
	p = NULL;

	return 0;

错误原因:

p最后指向的不再是起始地址,而free释放就要释放全部(   free的脾气   )。

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

错误代码:

int main()

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	
		return -1;
	

	//使用
	//...

	//释放
	free(p);
	free(p);
	p = NULL;

	return 0;

 对于不属于自己的指针(    已经释放过了,p不再维护该动态分配的空间了   ),再次进行free(p),程序就会崩溃;  请思考,这样写对不对呢?

	//释放
	free(p);
	p = NULL;

	free(p);
	p = NULL;

这样写,是对的,因为p已经置NULL了,而对于NULL,我们知道,free(BULL);是没错的,只不过是没有用处的写法罢了!

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

错误代码:

//动态开辟的内存忘记释放
//在堆区申请的空间,有2种方式可以回收
//1.主动free
//2.程序结束时,操作系统会自动回收

int main()

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	
		return -1;
	

	//使用
	//...

	//忘记释放了

	return 0;

错误原因:

我们在堆区开辟的内存,一直未释放,就会一直存在与堆区,造成内存被占用,对应到后端程序就是,运行变卡;这样一块内存,我们不能够对他进行使用,也没有去释放掉,就造成了 “   内存泄漏  ”。

忘记释放不再使用的动态开辟的空间会造成内存泄漏。

切记: 动态开辟的空间一定要释放,并且正确释放

应用:动态通讯录(优化版)

四、经典面试题目

题目1

#include<stdio.h>
#include<string.h>
void GetMemory(char* p)

    p = (char*)malloc(100);

void Test(void)

    char* str = NULL;
    GetMemory(str);
    strcpy(str, "hello world");
    printf(str);

int main()

    Test();
    return 0;

输出结果是什么? ————    程序会崩溃!!!

讲解:

其实,GetMemory(str);传递的是     ,所以单向值传递,并没有改变str指针的指向NULL,自然而然  hello  world  拷贝不到str中。

更改代码:

将GetMemory(&str);中的str取地址,传递过去;既然str是char*类型,那么&str传递,则用char**  来接收;

在void GetMemory(char** p)中,*p解引用,则取到str指针。

free(str);释放指针                 str = NULL;置空

#include<stdio.h>
#include<string.h>
void GetMemory(char** p)

    *p = (char*)malloc(100);

void Test(void)

    char* str = NULL;
    GetMemory(&str);
    strcpy(str, "hello world");
    printf(str);
    free(str);
    str = NULL;

int main()

    Test();
    return 0;

 当然,还有一种比较鸡肋的写法  (  价值不大  )

#include<stdio.h>
#include<string.h>
char* GetMemory()

	char* p = (char*)malloc(100);
	return p;

void Test(void)

	char* str = NULL;
	str = GetMemory();
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;

int main()

	Test();
	return 0;

小知识点

	printf(p);
	char* p = "hello world";
	printf("hello world");
	printf(p);
	printf("%s", p);

这三种写法都是一样的结果:

大概你可能会疑惑第二种写法,我们拿第一个写法举例,打印的是  hello world ,是因为传进去的其实并不是常量字符串,而是字符串的首地址,即:字符h的地址,然后完成打印。

同样的,我们指针p中存储的也是常量字符串“  hello world  ” ,printf(p);自然就是存储字符串的第一个字符h的地址,进而完成字符串的打印。

题目2

#include<stdio.h>
#include<string.h>
char* GetMemory(void)

	char p[] = "hello world";
	return p;

void Test(void)

	char* str = NULL;
	str = GetMemory();
	printf(str);

int main()

	Test();
	return 0;

输出结果是 乱码....................              为什么呢??

类似于宾馆退房

(char* GetMemory(void)中的p是局部变量!  函数调用完变量就销毁了,虽然返回了p的地址,但是后面再去访问这个地址,已经不是p去维护了,造成了非法访问空间,自然会打印出乱码。)

GetMemory函数栈帧创建完,会销毁,之后str是再找不到那块空间的了。

延伸题目,深入理解

#include<stdio.h>
#include<string.h>
int* Test()

	int n = 10;
	return &n;

int main()

	int* p = Test();
	printf("%d", *p);

	return 0;

讲解:

先创建main函数的函数栈帧,继而创建Test函数的函数栈帧,其中存放变量n = 10,返回的n的地址假设为0x0012ff43,再main函数中用指针p来接收n的地址0x0012ff43;而Test函数的栈帧调用完就会销毁,通过0x0012ff43地址再去访问那块空间,自然会造成非法访问;

当然,编译器有时候并不会很强大——报错。        对于该程序,Test函数的那块函数栈帧被销毁(即:该块空间的使用权限还给了操作系统【这块空间仍然存在,只是权限还回去了】,空间的值可能被覆盖也可能没有被覆盖,具体看是否又创建了栈帧覆盖该区域),再去解引用访问那块空间,就有可能访问的是随机值。

而该程序中,是有可能打印10的。是的,结果当然依旧打印出来也是10,这是因为打印之前,并没有其他的操作来占用这块释放的Test函数的函数栈帧,所以打印出来了10;那如果我这样呢?     -------------  结果如下:

这是因为,打印了" 嘿嘿 "创建了函数栈帧,覆盖掉了Test函数的栈帧(其实他已经被销毁了)。

题3

#include<stdio.h>
#include<string.h>
void Test(void)

	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	
		strcpy(str, "world");
		printf(str);
	

int main()

	Test();
	return 0;

其实是和上两个题目一个意思。该题中先创建main函数栈帧,然后创建了Test函数栈帧,malloc空间给str指针接收,拷贝hello进去,然后将str释放掉(注意,释放指的是该块空间的使用权限还给了操作系统),但是str仍然是指向malloc出来的那块空间的,只不过空间我们没有权限罢了;str!=NULL成立,而strcpy(str, "world");想要将world拷贝到str中,但是str指向的空间我们并没有权限在去访问,将    world   拷贝到str属于非法访问

总结:题1题2题3,都属于一类题目,返回栈空间地址的问题。注意栈空间地址不要轻易返回,因为栈出了范围会销毁。

注意:销毁的意思只是指   该栈空间的使用权限还给了操作系统,这块空间仍然存在!!

五、C/C++程序的内存开辟

C/C++程序内存分配的几个区域:

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS (操作系统 operating  system )回收 。分配方式类似于链表。
  3. 数据段(静态区)(static):存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码,常量字符串。

有了这幅图,我们就可以更好的理解在《C语言初识》中讲的static关键字修饰局部变量的例子了:

实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁所以生命周期变长

六、柔性数组

1.什么是柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。 C99   中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。

例如:

struct st_type

	int i;
	int a[0];//柔性数组成员
;

有些编译器会报错无法编译可以改成:

struct st_type

	int i;
	int a[];//柔性数组成员
;

2.柔性数组的特点

  1. 结构中的柔性数组成员前面必须至少一个其他成员
  2. sizeof 返回的这种结构大小不包括柔性数组的内存
  3. 包含柔性数组成员的结构用malloc( )函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
     

解释:
1.结构中的柔性数组成员前面必须至少一个其他成员

错误写法:

struct st_type

	int a[];
;

正确写法:

struct st_type

	int i;
	int a[];//柔性数组成员
;

2.sizeof 返回的这种结构大小不包括柔性数组的内存

struct st_type

	int i;
	int a[0];//柔性数组成员
;
printf("%d\\n", sizeof(st_type));
//输出的是4,
//因为sizeof 返回的这种结构大小不包括柔性数组的内存
//所以,仅有i的4字节大小

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

#include<stdio.h>
#include<string.h>
#include<errno.h>
struct st_type

	int n;
	int a[0];//柔性数组成员
    //int a[];//一个意思,不同写法而已,与a[?]无关
;
int main()

	//包含柔性数组成员的结构体的使用,要配了malloc这样的动态内存分配的函数使用
	//struct st_type st;
	//sizeof(struct st_type)是计算结构体中,除了柔性数组之外的其他成员的字节大小
	//10 * sizeof(int)即:开辟10个int类型的空间,作为柔性数组的空间
	struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int));
	if (ps == NULL)
	
		printf("%s\\n", strerror(errno));
		return -1;
	
	//开辟成功
	ps->n = 6;//初始化
	int i = 0;
	for (i = 0; i < 10; i++)
	
		ps->a[i] = i;
	

	for (i = 0; i < 10; i++)
	
		printf("%d ", ps->a[i]);
	

	//a数组空间不够用了,想要调整为20个空间
	struct st_type* ptr = (struct st_type*)realloc(ps,sizeof(struct st_type) + 20 * sizeof(int));
	if (ptr == NULL)
	
		printf("开辟空间失败!\\n");
		return -1;
	
	else
	
		ps = ptr;
	

	//使用
	//...
	//释放
	free(ps);
	ps = NULL;

	return 0;

3.柔性数组的使用

见   2.柔性数组的特点的第3点特点。

4.柔性数组的优势

与    2.柔性数组的特点的第3点特点,对比:

未用柔性数组实现

#include<stdio.h>
#include<string.h>
#include<errno.h>
struct st_type

	int n;
	int* a;
;
int main()

	struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type));

	//开辟成功
	ps->n = 100;
	ps->a = (int*)malloc(10 * sizeof(int));

	int i = 0;
	for (i = 0; i < 10; i++)
	
		ps->a[i] = i;
	

	for (i = 0; i < 10; i++)
	
		printf("%d ", ps->a[i]);
	

	//a空间不够用了,想要调整为20个空间
	int* ptr = (int*)realloc(ps->a, 20 * sizeof(int));
	if (ptr == NULL)
	
		printf("开辟空间失败!\\n");
		return -1;
	
	else
	
		ps->a = ptr;
	

	//使用
	//...
	//释放
	free(ptr);
	ptr = NULL;

	free(ps);
	ps = NULL;

	return 0;

 注意,释放的时候,需要两次free。先free(ptr);再free(ps)

因为如若先free(ps),那么等会想要再free(ptr),即:free(ps->a)的时候,已经找不到ps—>a的地址了,自然就完不成free了。

总结:相比较而言,用柔性数组优势更多!

1.方便内存释放

如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

2.有利于访问速度,减少内存碎片

连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)

而如果是代码2,则内存碎片比较多,空间利用率低。

动态内存管理(代码片段)

文章目录为什么存在动态内存分配动态内存函数的介绍mallocfreecallocrealloc常见的动态内存错误对NULL指针的解引用对开辟空间的越界访问对非动态开辟内存进行free使用使用free函数释放内存的一部分对同一块内存进行多次释放对动... 查看详情

关于动态内存管理的一些理解(代码片段)

动态内存管理文章目录动态内存管理为什么要存在动态内存分配动态内存函数的介绍mallocfreecallocrealloc注意事项:动态内存常见的错误对申请的动态空间不进行NULL检查对动态开辟的空间越界访问对非动态内存使用free释放使用... 查看详情

了解动态内存管理函数melloccallocfreerealloc,实现内存管理自由!(代码片段)

动态内存管理笔记自取链接:动态内存管理笔记文章目录动态内存管理导言一、mallco开辟动态内存空间二、free释放动态内存空间三、calloc初始化+开辟动态内存空间四、realloc调整动态内存空间大小小结导言众所周知~,... 查看详情

c语言进阶:动态内存管理(代码片段)

文章目录动态内存管理动态内存分配的意义动态内存函数的介绍开辟释放函数`malloc`&`free`函数声明函数用法内存开辟函数`calloc`函数声明函数用法内存调整函数`realloc`函数声明函数用法常见的动态内存... 查看详情

stm32内存管理(代码片段)

动态内存管理根据需要分配內存和回收内存通常在一块较大且连续的内存空间上进行分配和回收动态内存管理解决的问题内存资源稀缺,通过内存复用增加任务的并发性动态内存管理的本质时间换空间,通过动态分配和... 查看详情

c++动态内存管理(代码片段)

目录1.C/C++程序地址空间2.C语言动态内存管理(1)malloc(2)calloc(3)realloc(4)free3.C++动态内存管理(1)C++为什么要设计一套自己专属的动态内存管理方式?(2)new/delete定义1)new/delete操作内置类型2)new/delete操作自定义类型(3)new/d... 查看详情

动态内存管理(代码片段)

动态内存管理1.为什么要动态内存管理intval=20;//在栈空间上开辟四个字节chararr[10]=10;//在栈空间上开辟10个字节的连续空间但是上述的开辟空间的方式有两个特点:1.空间开辟大小是固定的。2.数组在申明的时候,必须指定数组的... 查看详情

动态内存管理(一次过)(代码片段)

动态内存管理为什么存在动态内存管理?什么是动态内存函数?常见的动态内存错误常见的笔试题C/C++程序的内存开辟为什么会有柔性数组?为什么存在动态内存管理?学了C语言之前的知识,我们应该知... 查看详情

c语言进阶动态内存管理(代码片段)

目录为什么存在动态内存分配动态内存函数介绍1.malloc函数2.Calloc函数3.realloc函数常见的动态内存错误1.对NULL指针的解引用操作2.对动态开辟空间的越界访问3.使用free释放分动态内存开辟的空间4.使用free释放动态内存中的一部分5.... 查看详情

动态内存管理与柔性数组(代码片段)

文章目录前言思维导图C/C++程序内存区域分类动态申请:malloc,calloc,reallocmalloccallocrealloc(重新分配已申请的空间)三者联系动态释放关键字:freefree内存泄露常见动态内存错误忘记free(内存泄漏)!!!!... 查看详情

动态内存管理详解(代码片段)

...束就释放内存(3)静态变量:程序运行结束就释放内存动态内存管理(即内存的申请和释放)目的:程序运行过程中,更灵活的进行内存的申请和释放~即:随时需要就申请ÿ 查看详情

动态内存管理详解(动态内存函数介绍+常见动态内存错误+经典笔试题)(代码片段)

文章目录为什么存在动态内存分配内存分配知识拓展动态内存函数malloc和free函数calloc函数realloc函数常见的动态内存错误1.对NULL指针的解引用操作2.对动态开辟空间的越界访问3.对非动态开辟内存使用free释放4.使用free释放一块动... 查看详情

c语言之动态内存管理(动态内存分配+经典笔试题+柔性数组)[建议收藏](代码片段)

本篇文章我要给大家梳理一下C语言中的动态内存管理相关知识。其中主要包括如何进行动态内存管理、一些常见的动态内存错误及柔性数组的介绍。❤️博主码云gitee链接:https://gitee.com/byte-binxin❤️文章目录为什么存在动... 查看详情

动态内存管理(下)(代码片段)

目录:上篇:(3条消息)动态内存管理(上)_执久呀的博客-CSDN博客      动态函数的介绍:malloc free calloc realloc     三、 calloc函数     calloc函数介绍:     calloc的使用例子:四、 realloc函... 查看详情

动态内存管理2(代码片段)

...uique_ptr来处理内存泄漏。一个类uique_ptr的对象维护了指向动态分配内存的一个指针,当一个uique_ptr对象的析构函数被调用时,它将对其指针数据成员执行delete操作。通过uique_ptr类的重载赋值运算符或拷贝构造函数,可以使一个uiq... 查看详情

从零开始学c++——c++动态内存管理(代码片段)

C++动态内存管理1.C/C++内存分布2.c++中的动态内存管理3.operatornew和operatordelete4.什么是内存泄露5.malloc/free和new/delete的区别1.C/C++内存分布接下来我们来看一下例子:intglobalVar=1;staticintstaticGlobalV 查看详情

一篇文章玩转c语言动态内存,轻松管理动态内存空间(代码片段)

C语言动态内存管理1、动态内存分配存在的原因2、动态内存函数的介绍2.1malloc函数2.2free函数2.3calloc函数2.4realloc函数3、常见的动态内存错误3.1对NULL空指针的解引用操作3.2对动态开辟空间的越界访问3.3对动态开辟空间的越界访问3.... 查看详情

弄懂动态内存管理(代码片段)

**为什么要存在内存管理?**我们通常使用,局部变量数组来开辟内存如intval=20;intarr[10]=0;但是上面内存开辟空间存在两个特点内存的空间开辟是固定的数组在申明时,必须要指定数组的长度,程序在编译是分配内... 查看详情