您现在的位置是:首页 >技术杂谈 >C/C++中程序数据的分类与内存分布,C++内存管理方式之new / delete 操作符与malloc / free的区别网站首页技术杂谈

C/C++中程序数据的分类与内存分布,C++内存管理方式之new / delete 操作符与malloc / free的区别

Shensk 2024-06-15 06:01:02
简介C/C++中程序数据的分类与内存分布,C++内存管理方式之new / delete 操作符与malloc / free的区别

TIPS

  1. const修饰数据类型并不会影响它在内存当中某个区域的存储位置,比方说原先是在栈区上面的,然后用const修饰了一下,并不就是说你现在已经变到静态区里面去了,你还是在栈上面
  2. 指针与指针之间的等号赋值也需要考虑到权限的放大与缩小问题,bty,地址等于指针。也就是说从右往左的过程当中,权限只能够平移或者缩小,权限不能够放大。

C/C++中程序数据的分类与内存分布

在这里插入图片描述

  1. 在程序当中需要存储一些数据,然后数据的分类有局部数据,还有就是静态数据和全局数据,他们的特点就是生命周期在全局可以一直用,还有常量数据和动态申请的数据。
  2. 在平时写程序的过程当中,局部数据用的最多,比如说在当前函数当中去创建各种各样的变量,所以说局部数据通常就是在函数里面定义的各种局部变量,他就是跟着函数走,本质上就是存储在函数调用的时候开辟的函数栈帧里面;静态数据与全局数据的话,他们的生命周期就是整个程序存在的时间;常量数据就是不能够去修改的,比如常量字符串等等;然后动态申请的数据基本上在数据结构当中用的会比较多一点.
  3. 然后一般我们在编译器上写程序的话,***我们写的这些代码实际上都是在磁盘里面,因为相当于我们是在文件里面去写代码,所以说我们写的这些东西是在磁盘文件里面,然后对于写的这些代码进行编译加链接,就会生成一个可执行程序,这个可执行程序也是以一个磁盘文件的形式存在于磁盘里面。***然后接下来我们把这个可执行程序给他运行起来,运行起来的本质就是以一个进程的角度在操作系统之上进行运行。
  4. 然后这个可执行程序里面都是一些计算机能够看懂的二进制指令,当然还有一些数据。然后当这个可执行程序运行起来以后,也就是载入到内存当中,这个被可执行程序exe使用的内存区域每个进程呢都把它叫做虚拟进程地址空间。这个进程地址空间就需要对不同数据进行存储,因此就会内部划分区域。最上面的话是高地址,主要是给操作系统的内核用的;然后接下来就是几个熟悉的区域:栈,堆,静态区/数据段,常量区/代码段。
  5. 然后对于局部数据而言,一般都是存在栈上面,比方说要去调用一个函数,那么就会去建立函数栈帧,建立函数栈帧最本质的一个要点就在于需要去存储局部数据。然后到函数结束的时候,函数栈帧销毁,那么里面的这些局部数据也就会一起去销毁。其实局部数据的感觉就有点类似于一次性的那种感觉,就是短期用用的。对于栈区的话还有一个作用就是方便我们去进行递归就是不断的去建立函数栈帧,然后再进行销毁,然后再进行空间的复用(比如说二叉树)
  6. 但有时候的话也需要用一些静态数据全局数据,也就是说随着时间的推移,要能够保持一定的连续性,这些数据的话它不能够存在栈区里面,所以说就需要单独去找一个区域给他存起来,所以说,就在静态区/数据段这个地方把这些数据给他存起来,然后这些数据的话,在整个程序在的时候,他都也都是在的,不是说函数结束它就销毁了。
  7. 然后对于一些常量以及在可执行程序当中的一些指令的话,都是放在常量区/代码段的
  8. 然后还有一些数据,比方是需要程序员他自己要去动态开辟的,并且是自己申请自己释放空间,相当于就是说是自主权比较大一点,对于这种动态申请的数据,它就是放在堆上面
  9. 然后为什么要划分成这么多的区域?主要就是因为我们的程序有很多需求.
    10.在这里插入图片描述
    在这里插入图片描述

经典检测

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}

在这里插入图片描述

  1. 这个肯定是个全局变量,全局变量是放在静态区的C
  2. 这个也是一个静态变量,那么他想当然肯定也是放在静态区的C
  3. 这个也是一个静态变量,那么他想当然肯定也是放在静态区的C
  4. 这个的话相当于是一个函数里面的局部变量而已,肯定是在内存栈区里面A
  5. 这个也是一个函数里面的一个数组而已,在函数栈帧里面,所以说也是在内存栈区里面A
    在这里插入图片描述
  6. 这是一个在函数里面的一个数组而已,那么肯定也是在函数栈帧里面,肯定是在内存栈区里面A
  7. 这个char2是一个数组的名字,这就是数组首元素的地址,然后相当于是对数组首元素的地址进行解引用,那不就是相当于是在访问处于内存栈区的数组元素吗?所以说访问出来的东西还是在内存的栈区里面A
  8. 他其实相当于是一个指针,不过这边需要注意,虽然他是const的修饰,但这并不意味着它是一个静态变量了,不意味着他就跑到静态区里面去了。他无非还就是一个内存栈区里面的普通指针罢了,不过有点类似于常变量的这种感觉。然后这个指针变量里面存放的就是这个字符串常量第一个字符的地址。不过指针变量是在栈区的A
  9. 然后对于这个指针变量pchar进行解引用,首先这个指针变量它指向的是处于内存常量区的字符串常量的第一个字符,那么这样子解引用出来就得到了一个字符,这个字符就是处于内存常量区里面的那个字符,所以在常量区D
  10. ptr1无非就是一个指针而已,肯定是在内存栈区的,不过它指向的那块内存空间是属于内存堆区的罢了A
  11. 然后对这个指针ptr1进行解引用操作,这时候访问到的就是属于内存堆区里面的数据,所以在堆区B
    在这里插入图片描述
  12. sizeof数组名,计算的是整个数组所占内存字节大小,所以是40
  13. 这个与第一个道理是一样的,也是计算整个数组所占内存字节的大小,sizeof是计算进入字符串终止符的,所以大小为5
  14. 相当于就是统计字符串的长度,然后碰到就会停下来,的话是不会统计进去的,所以为4
  15. 这个相当于是在计算一个指针的大小,那这个非常简单,在32位机器下面是四个字节
  16. 这个也是在统计字符串的长度,为4,很简单
  17. 这个也是在计算一个指针的大小,也非常简单,就是四个字节(32位下)

C++内存管理方式之new / delete 操作符

  1. 首先复习回顾C,C的那些动态申请内存的各种方法在cpp当中也是可以去使用的
    在这里插入图片描述
  2. C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
  3. 在这里插入图片描述
  4. 如:用new向内存堆区动态申请一个int类型的空间
    在这里插入图片描述
  5. 如:用new向内存堆区动态申请一个int类型的空间并初始化为522
    在这里插入图片描述
  6. 如:用new向内存堆区动态申请10个int类型的空间
    在这里插入图片描述
  7. 注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用,如:
    在这里插入图片描述

new/delete 与 malloc/free 区别

  1. 在C++向内存堆区申请与释放空间的话,一般是用new与delete。然而在C的话用malloc/free。
  2. 然后如果向内存堆区申请的,这块空间是给内置类型来用的,其实这两种方法的话,差距并不是很大,甚至说没有。
  3. 真正体现优劣的地方就在于如果说向内存堆区申请的这块空间是给那些自定义类型变量(实例化对象)的,对于malloc/free来讲,他们只会单纯的去开辟一块多少多少大小的空间,然后等会儿把这块空间给他全部释放掉;但对于new与delete,如果 “自定义类型* p = new 自定义类型(构造函数参数)”, 就像这样子相当于在向内存堆区申请空间的同时,还能够直接进行调用构造函数初始化;然后delete p; 在把这块空间释放前会去调用析构函数。
    在这里插入图片描述
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。