⭐本篇重点:C/C++内存分布,C语言动态内存管理
⭐本篇代码:c++学习/04.c++-动态内存管理 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)
目录
一. C/C++内存分布(C/C++内存地址空间)
二. C语言动态内存管理
2.1 malloc与free
2.2 calloc
2.3 realloc
三. 易错辨析
3.1 malloc/calloc/realloc的区别?
3.2 malloc的实现原理?
四:下篇内容:C++动态内存管理new和delete
一. C/C++内存分布(C/C++内存地址空间)
在之前一篇Linux的文章中,我们提到了C/C++地址空间:Linux基础4-进程5(程序地址空间详解)-CSDN博客
当时,我们画出的地址空间图如下
当然,实际上在命令行参数的上面还有内核空间
为了更好理解动态内存分布,我们来看一些题目。代码如下
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. 选择题: 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?____ staticGlobalVar在哪里?____ staticVar在哪里?____ localVar在哪里?____ num1 在哪里?____ char2在哪里?____ *char2在哪里?___ pChar3在哪里?____ *pChar3在哪里?____ ptr1在哪里?____ *ptr1在哪里?____
globalVar:这个是全局变量,应该位于数据段(全局数据区)
staticGlobalVar:这个是静态数据,位于数据段
staticVar:静态数据位于数据段
localVar:定义的非静态局部变量,位于栈区
num1:非静态局部变量,位于栈区
char2:非静态局部变量,位于栈区
*char2:解引用一个数组名的结果是数组的首个元素,是局部非静态变量,位于栈区
pChar3:非静态局部变量,位于栈区
*pChar3:“abcd”,位于常量区
ptr1:非静态局部变量,位于栈区
*ptr1:结果为malloc开辟的空间,位于堆区
2. 填空题: sizeof(num1) = ____; sizeof(char2) = ____; strlen(char2) = ____; sizeof(pChar3) = ____; strlen(pChar3) = ____; sizeof(ptr1) = ____;
sizeof(num1):使用sizeof计算一个单独的数组名,得到的大小是整个数组的大小:即 10*4 = 40 字节(int占4字节)
sizeof(char2):与上面同理:为 4*1 + 1 = 5 字节(不要忘记了C语言字符串后面有'\0')
strlen(char2):strlen用于计算一个字符串的长度,不包含'\0'(遇到'\0'就会停止)。4*1 = 4 字节
sizeof(pChar3):pChar3是一个指针,在32位操作系统下,指针大小是4字节,64位下指针大小是8字节。8字节
strlen(pChar3):计算字符串长度,遇到'\0'停止。为4字节
sizeof(ptr1):计算指针:为4/8字节
3. sizeof 和 strlen 区别?
sizeof用于计算一个变量所占内存的大小是C/C++提供的一个关键字!
strlen用于计算一个字符串的长度,是C语言提供的一个函数
说明:
非静态局部变量,函数的参数,返回值都位于栈区
用户动态开辟的空间(malloc,new等)位于堆区
代码区:用于存储代码
常量区:用于存放常量,自定义的常量,字符常量等
全局(静态)区:用于存放全局变量和静态变量
二. C语言动态内存管理
学习C++动态内存管理之前,先回顾一个C语言动态内存管理
2.1 malloc与free
malloc用于在堆区申请空间,free用于销毁申请的空间
//头文件
#include <stdlib.h>
//函数原型
void* malloc(size_t size);
//size是申请的空间大小
//申请成功返回一个void*的指针,指向这个空间的起始地址
//我们需要将void*强制转化为我们需要的类型指针
//申请失败返回NULL
用法如下:
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
//申请10个int的数组
int size = 10;//申请的空间大小
int* arr = (int*)malloc(sizeof(int) * size);
if (NULL == arr)
return -1;
for (int i = 0; i < 10; i++)
{
*(arr + i) = i;
}
for (int i = 0; i < 10; i++)
{
cout << *(arr + i) << " ";
}
return 0;
}
运行结果
但是这样是有问题的!
我们在使用malloc申请的空间后,需要使用free去释放这个空间
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
//申请10个int的数组
int size = 10;//申请的空间大小
int* arr = (int*)malloc(sizeof(int) * size);
if (NULL == arr)
return -1;
for (int i = 0; i < 10; i++)
{
*(arr + i) = i;
}
for (int i = 0; i < 10; i++)
{
cout << *(arr + i) << " ";
}
free(arr);//释放空间
arr = NULL;//防止野指针
return 0;
}
2.2 calloc
//所需头文件
#include <stdlib.h>
//函数原型
void *calloc(size_t nmemb, size_t size);
//与malloc一样申请空间,但是calloc会将申请的空间都初始化为0
//返回值和malloc一样
//nmemb,申请空间元素的个数
//size,申请空间每一个元素的大小
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
//申请10个int的数组
int count = 10;//申请的空间大小
int* arr1 = (int*)malloc(sizeof(int) * count);
int* arr2 = (int*)calloc(count, sizeof(int));
if (arr1 == NULL || arr2 == NULL)
return -1;
for (int i = 0; i < count; i++)
{
cout << *(arr1 + i) << " ";
}
cout << endl;
for (int i = 0; i < count; i++)
{
cout << *(arr2 + i) << " ";
}
free(arr1);
arr1 = NULL;
free(arr2);
arr2 = NULL;
return 0;
}
2.3 realloc
realloc和malloc,calloc有着很大区别,realloc只要用于给申请的空间扩容(当空间满了不够用的时候)
//所需头文件
#include <stdlib.h>
//函数原型
void *realloc(void *ptr, size_t size);
//ptr,需要扩容空间的原指针
//size,扩容后的空间大小
//返回值:扩容后空间的起始地址
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
//申请10个int的数组
int count = 10;//申请的空间大小
int* arr1 = (int*)malloc(sizeof(int) * count);
if (arr1 == NULL)
return -1;
for (int i = 0; i < count; i++)
{
*(arr1 + i) = i;
}
count = 20;//不够了,要扩容
int* newarr = (int*)realloc(arr1, sizeof(int) * count);
if (newarr == NULL)
return -1;
arr1 = newarr;
for (int i = 0; i < count; i++)
{
*(arr1 + i) = i * 10;
}
for (int i = 0; i < count; i++)
{
cout << *(arr1 + i) << " ";
}
free(arr1);
arr1 = NULL;
return 0;
}
运行结果:
三. 易错辨析
3.1 malloc/calloc/realloc的区别?
见 2.1 2.2 2.3
3.2 malloc的实现原理?
可以看这个视频:malloc实现原理