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

阶段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,申请空间,并初始化为0int* 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个intint* 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,则内存碎片比较多,空间利用率低。

C进阶⚡- 05动态内存管理相关推荐

  1. 【C进阶】动态内存管理

    ⭐博客主页:️CS semi主页 ⭐欢迎关注:点赞收藏+留言 ⭐系列专栏:C语言进阶 ⭐代码仓库:C Advanced 家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们 ...

  2. 【带你吃透C++】C++动态内存管理

    C++动态内存管理 前言 1. C/C++内存分布 例题理解 2.C语言中动态内存管理方式( malloc/calloc/realloc和free) 3.C++中动态内存管理方式 new和delete ...

  3. C语言进阶——动态内存管理

    目录 一.为什么存在内存分配 二.动态内存函数 1.malloc 2.free 3.calloc 4.realloc 三.常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访 ...

  4. C语言进阶(七)——动态内存管理

    文章目录 动态内存管理 前言 一.为什么存在动态内存分配? 二.动态内存函数的介绍 1.malloc函数的介绍 2.free函数的介绍 3.malloc函数和free的配合使用 4.calloc函数的 ...

  5. 【C语言进阶】详解C语言动态内存管理

    前言: 今天这篇博客将为大家讲解如何通过开辟动态内存,从而写出更加优秀的的程序.同时今天的内容对于以后想要继续学习c++的同学来说也尤为重要.那就让我们进入正题吧. 一.动态内存概述: 什么是动态内存 ...

  6. 《C++应用程序性能优化::第五章动态内存管理》学习和理解

    <C++应用程序性能优化::第五章动态内存管理>学习和理解 说明:<C++应用程序性能优化> 作者:冯宏华等 2007年版. 2010.8.29 cs_wuyg@126.com ...

  7. 【C++】动态内存管理/move/以及移动构造与移动赋值运算符

    文章目录 1 .对象移动与右值引用 实际应用过程中遇到的问题及其解决方案 c++中临时变量不能作为非const的引用参数 2. 动态内存管理类 3. 对象移动与右值引用 4. 移动构造与移动复制运算符 ...

  8. C和C++安全编码笔记:动态内存管理

    4.1 C内存管理: C标准内存管理函数: (1).malloc(size_t size):分配size个字节,并返回一个指向分配的内存的指针.分配的内存未被初始化为一个已知值. (2).aligne ...

  9. C语言之动态内存管理与动态内存函数

    文章目录 一.为什么存在动态内存分配? 二.动态内存函数的介绍 1.malloc和free 2.calloc函数 3.realloc函数 一.为什么存在动态内存分配? 学习动态内存的管理方法之前,我们 ...

最新文章

  1. 持续集成之jenkins基础
  2. 《树莓派Python编程入门与实战(第2版)》——1.7 排除树莓派的故障
  3. 机器视觉行业市场现状及发展前景分析
  4. Re:从零开始的Vue项目搭建
  5. Android 蓝牙4.0在实际开发中的运用
  6. 权限管理系统_在Gitee狂揽11K Star!这个SpringCloud的权限管理系统你必须知道
  7. 【Java从0到架构师】SpringMVC - 返回值
  8. 京东面试撞上重感冒(纯粹面试之感)。。。。。。
  9. 转载的 matlab破解版下载与安装教程
  10. windows10应用商店下安装kali子系统
  11. PPT中如何插入页码和母版修改
  12. USACO 1.1.2 - Greedy Gift Givers(模拟)
  13. 2020中国汽车后市场白皮书
  14. 【canvas画图】画一个彩虹
  15. K8S 1.18.0 以及KubeEdge 1.10.3 三机安装部署(含过程记录及遇到的报错和解决方法)
  16. 为什么onenote一直在加载_OneNote: 沉睡于电脑中的宝藏笔记软件,高效管理你的学习生活...
  17. 利用Python画一只小猪佩奇
  18. 【饭谈】【测试圈相亲平台开发流程】:页面样式开发心得【工匠、智者、航海家】
  19. 什么是DHT网络(DHT network)
  20. [__NSCFNumber isEqualToString:]: unrecognized selector sent to instance 0x7a97d4c0'报错

热门文章

  1. 如何充实地度过大学四年?
  2. 查询结构树下的所有子节点包括要查询的节点
  3. ArcGIS教程:面积制表
  4. ajax怎样替换文本,JavaScript Document.Write在使用AJAX时替换所有正文内容
  5. 魔兽世界最新服务器推荐,魔兽世界服务器人数最新数据!萌新入坑,老玩家转服慎重选择!...
  6. 街霸 隆(Ryu)波动拳(Hadoken)动画(二)细节
  7. Java工厂设计模式
  8. L4W4作业1 人脸识别 - the Happy House
  9. 有声双语阅读器-学英语背单词,做泛读的好帮手
  10. 互联网公司为什么普遍996而不是666