IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 动态内存管理 -> 正文阅读

[C++知识库]动态内存管理

动态内存管理

内存空间如果简单划分的话,分为3个区:栈区,堆区,静态区

栈区主要是存放:局部变量,函数的形参,函数的返回值。

堆区主要是存放:malloc calloc realloc free动态开辟的内存空间。

静态区主要是存放:由static修饰的静态的变量,包括局部变量和全局变量。

内存开辟的方式

  1. 在栈区开辟空间:
int i = 0;//在栈上开辟一块大小为4byte的空间
float f = 0.0f;//在栈上开辟一块大小为4byte的空间
double d = 0.0;//在栈上开辟一块大小为8byte的空间
int arr[10] = { 0 };//在栈上连续开辟一块大小为40byte空间

上述开辟空间的大小都是固定的,开辟好之后就不能被修改。

  1. 在堆区开辟空间:

这时候,就涉及到动态内存函数malloc calloc realloc free

malloc

void* malloc(size_t size);

malloc函数是用来向内存申请一块空间的,要是申请成功,则返回该空间的起始地址;申请失败,返回空指针NULL.

几点注意事项:

  1. 要是申请成功,该块空间并未初始化。
  2. 如果size是0,标准未定义该行为,结果取决于不同的编译器。
  3. void*类型的指针不能直接进行解引用操作,得先将其转化为具体类型的指针。

free

void free(void* ptr);

free函数是用来释放动态内存函数开辟的内存空间的,因为只开辟,不释放,会使得内存泄漏。

几点注意事项:

  1. ptr指针只能是指向的空间是malloc calloc realloc函数开辟的。
  2. 如果ptrNULL,则free函数什么也不干。
  3. 不能对一块由动态内存函数开辟的空间多次用free释放。

calloc

void* calloc(size_t num, size_t size);

malloc函数类似,calloc函数也是用来开辟内存空间的,不过于malloc不同的是,calloc函数是用来开辟num个大小为size的连续空间的。

需要注意的是:

  1. calloc同样是返回泛型指针void*,不能直接对其进行解引用操作。
  2. calloc函数开辟空间成功,返回的是空间的起始地址;开辟失败返回的是空指针NULL
  3. calloc在开辟空间的时候,顺便将空间的每个字节全部初始化为0。

realloc

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

realloc是用来调整由动态内存函数开辟空间的大小的函数。

需要注意的点是:

  1. ptr指向的是由动态内存函数开辟空间的起始地址;调整之后,新内存空间的大小是size
  2. 如果调整空间成功,返回调整空间的地址;要是失败,返回空指针NULL
  3. 如果给定的size大小是0,则该函数跟malloc一样,啥事也不干。
  4. realloc返回的地址可能是原来的地址,也有可能是经过调整之后新的地址。

realloc的两种开辟方式:
在这里插入图片描述

动态内存函数的使用

  1. calloc和free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(40);//动态开辟40个字节的空间,并将起始位置的地址赋值给整型指针ptr
    //因为开辟可能成功,也有可能失败,故在使用ptr指针时,需要先判断指针是否为空
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));//打印错误信息
        return 1;
    }
    
    //...
    //动态内存空间的使用
    
    //动态内存空间的释放
    free(ptr);//释放只是释放了指针指向的空间,但是ptr还是指向原来的那块空间,为了确保安全,需要把ptr置为NULL
    ptr = NULL;
    
    return 0;
}
  1. malloc和free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = malloc(sizeof(int), 10);//动态开辟10个整型的空间
    //判断返回值
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    //...
    //相关操作
    
    //内存释放
    free(ptr);
    ptr = NULL;
    
    return 0;
}
  1. realloc和free
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(40);
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    int* p = (int*)free(ptr, 80);
    //判断是否空间是否开辟成功
    if (p != NULL)
    {
        ptr = p;
        
    }
    //...
    //内存释放
    free(ptr);
    ptr = NULL;
    
    return 0;
}

动态内存开辟中有关的错误

  1. NULL进行解引用。
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int* p = malloc(10 * sizeof(int));
    *p = 20;
    free(p);
    p = NULL:
    return 0;
}

此代码中,使用malloc动态开辟10个整型的空间,可能开辟失败,返回空指针,如果一个指针没有明确的指向是不能直接进行解引用操作的!

  1. 操作越过动态开辟的空间。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(10 * sizeof(int));
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    for (int i = 0; i <= 10; i++)
    {
        ptr[i] = i;
        //p[i] <--> *(p + i)
    }
    //内存的释放
    free(ptr);
    ptr = NULL;
    return 0;
}
  1. 释放非动态开辟的内存
#include <stdio.h>
#inclue <stdlib.h>

int main()
{
    int a = 0;
    int* ptr = &a;
    //...
    free(ptr);
    ptr = NULL;
    return 0;
}
  1. 释放动态开辟内存的一部分
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(10 * sizeof(int));
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    for (int i = 0; i < 5; i++)
    {
        ptr++;
    }
    //ptr经过循环之后已经不再指向动态开辟内存的起始位置了。
    
    free(ptr);
    ptr = NULL;
    
    return 0;
}
  1. 对同一块动态开辟的内存多次释放
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(10 * sizeof(int));
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    //...
    free(ptr);
    ptr = NULL;
    //...
    free(ptr);
    ptr = NULL;
    
    return 0;
}
  1. 忘记释放动态开辟的内存(导致内存泄漏)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(10 * sizeof(int));
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    //...相关操作
    
    //...没有进行内存释放
    
    return 0;
}
  1. 动态内存释放后继续使用
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
    int* ptr = (int*)malloc(10 * sizeof(int));
    if (ptr == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    //...相关操作
    
    //内存释放
    free(ptr);
    //ptr = NULL;
    
    *ptr = 10;
    
    return 0;
}

柔性数组

有几点必须明确:

  1. 柔性数组只可能出现在结构体中。
  2. 柔性数组成员必须是结构体中的最后一个成员,也就是说,结构体中至少有两种成员。
  3. 使用sizeof计算结构体的大小时,柔性数组成员不算在内。
  4. 含有柔性数组成员的数组应使用malloc函数进行内存分配,大小应大于结构体自身的大小。

举例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

typedef struct S
{
  char c;
  int i;
  int arr[0];
}type_s;


int main()
{
    type_s* p = (type_s*)malloc(sizeof(type_s) + 100 * sizeof(int));
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
        return 1;
    }
    p->c = 'w';
    p->i = 0;
    for (int i = 0; i < 100; i++)
    {
        p->arr[i] = i;
    }
    //动态内存释放
 	free(p);
    p = NULL;
    
    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:19:47  更:2022-07-21 21:22:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:00:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码