第38课 动态内存分配

动态内存分配的意义:

malloc和free:

注意:

思考:

malloc(0)将返回什么?

运行结果如下:

可以看到,返回了具体的地址。

我们所说的内存包括起始地址和长度。我们平时说内存的时候更多的是关注起始地址,而忽略了长度。

如果动态的综合这两部,我们使用malloc(0)返回了一个地址就不会奇怪了,因为这块内存的长度是0。这块内存我们可能无法正常使用,因为长度是0。

我们如果不停的malloc(0),会使系统的内存耗尽吗?

答案是会的,因为我们malloc的时候,得到的内存往往要比实际申请的大。

现在的内存申请一般都是四字节对齐的。

因此,malloc(0)也要使用free来释放这片内存。

避免内存泄漏的内存泄漏检测模块:

mleak.h如下:

 1 #ifndef _MLEAK_H_
 2 #define _MLEAK_H_
 3
 4 #include <malloc.h>
 5
 6 #define MALLOC(n) mallocEx(n, __FILE__, __LINE__)
 7 #define FREE(p) freeEx(p)
 8
 9 void* mallocEx(size_t n, const char* file, const line);
10 void freeEx(void* p);
11 void PRINT_LEAK_INFO();
12
13 #endif

mleak.c如下:

 1 #include "mleak.h"
 2
 3 #define SIZE 256
 4
 5 /* 动态内存申请参数结构体 */
 6 typedef struct
 7 {
 8     void* pointer;
 9     int size;
10     const char* file;
11     int line;
12 } MItem;
13
14 static MItem g_record[SIZE]; /* 记录动态内存申请的操作 */
15
16 void* mallocEx(size_t n, const char* file, const line)
17 {
18     void* ret = malloc(n); /* 动态内存申请 */
19
20     if( ret != NULL )
21     {
22         int i = 0;
23
24         /* 遍历全局数组,记录此次操作 */
25         for(i=0; i<SIZE; i++)
26         {
27             /* 查找位置 */
28             if( g_record[i].pointer == NULL )
29             {
30                 g_record[i].pointer = ret;
31                 g_record[i].size = n;
32                 g_record[i].file = file;
33                 g_record[i].line = line;
34                 break;
35             }
36         }
37     }
38
39     return ret;
40 }
41
42 void freeEx(void* p)
43 {
44     if( p != NULL )
45     {
46         int i = 0;
47
48         /* 遍历全局数组,释放内存空间,并清除操作记录 */
49         for(i=0; i<SIZE; i++)
50         {
51             if( g_record[i].pointer == p )
52             {
53                 g_record[i].pointer = NULL;
54                 g_record[i].size = 0;
55                 g_record[i].file = NULL;
56                 g_record[i].line = 0;
57
58                 free(p);
59
60                 break;
61             }
62         }
63     }
64 }
65
66 void PRINT_LEAK_INFO()
67 {
68     int i = 0;
69
70     printf("Potential Memory Leak Info:\n");
71
72     /* 遍历全局数组,打印未释放的空间记录 */
73     for(i=0; i<SIZE; i++)
74     {
75         if( g_record[i].pointer != NULL )
76         {
77             printf("Address: %p, size:%d, Location: %s:%d\n", g_record[i].pointer, g_record[i].size, g_record[i].file, g_record[i].line);
78         }
79     }
80 }

主程序如下:

 1 #include <stdio.h>
 2 #include "mleak.h"
 3
 4 void f()
 5 {
 6     MALLOC(100);
 7 }
 8
 9 int main()
10 {
11     int* p = (int*)MALLOC(3 * sizeof(int));
12
13     f();
14
15     p[0] = 1;
16     p[1] = 2;
17     p[2] = 3;
18
19     FREE(p);
20
21     PRINT_LEAK_INFO();
22
23     return 0;
24 }

运行结果如下:

我们将第19行释放p的语句也注释掉,再次运次:

calloc和realloc:

示例程序:

 1 #include <stdio.h>
 2 #include <malloc.h>
 3
 4 #define SIZE 5
 5
 6 int main()
 7 {
 8     int i = 0;
 9     int* pI = (int*)malloc(SIZE * sizeof(int));
10     short* pS = (short*)calloc(SIZE, sizeof(short));
11
12     for(i=0; i<SIZE; i++)
13     {
14         printf("pI[%d] = %d, pS[%d] = %d\n", i, pI[i], i, pS[i]);
15     }
16
17     printf("Before: pI = %p\n", pI);
18
19     pI = (int*)realloc(pI, 2 * SIZE * sizeof(int));
20
21     printf("After: pI = %p\n", pI);
22
23     for(i=0; i<10; i++)
24     {
25         printf("pI[%d] = %d\n", i, pI[i]);
26     }
27
28     free(pI);
29     free(pS);
30
31     return 0;
32 }

运行结果如下:

bcc32的运行结果如下:

vc编译器的结果如下;

realloc重置之后地址值会发生变化。

可以得到结论:

calloc得到的内存是绝对会初始化的,malloc不会初始化。realloc会重置内存空间的大小,重置后扩大的内存部分可能是随机值。

小结:

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9551389.html

时间: 2024-11-09 05:12:28

第38课 动态内存分配的相关文章

28._动态内存分配

动态内存分配 传统数组的缺点(静态内存分配):   1.数组长度必须事先指定,且只能是常整数,不能是变量    例子:     int a[5]; //OK     int len = 5; int a[len]; //error   2.传统形式定义的数组,该数组的内存程序员无法手动编    程释放,在一个函数运行期间,系统为该函数中数组所     分配的空间会一直存在,直到该函数运行完毕时,数组    元素所占存储空间才会被系统释放 3.数组的长度一旦定义,长度就能被改变     4.A函数

动态内存分配类实现

今天学习了C++语言的内存动态分配,并借助所学的知识实现了一个动态内存分配类. 问题的背景为:在已经实现了一个点类的基础上,实现一个动态内存分配类,这个类 的功能为:实现根据输入的数目size,动态的生成size个点类对象:并在提供一个借口 可以对pos位置的对象进行操作:在对象生存期结束时,可以自动释放分配的内存空间. 根据描述的问题描述的需求,规划了如下的类图: 写出了一个包含三个方法的对点动态分配内存的类: 1: #ifndef _ARRAYOFPOINTS_H 2: #define _A

C++动态内存分配

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解>电子工业出版社等. CSDN视频网址:http://edu.csdn.net/lecturer/144 C / C ++中的动态内存分配是指程序员手动执行内存分配, 动态分配的内存分配给堆,非静态和局部变量获取在Stack上分配的内存.详情查看上篇博文:C程序的内存布局. 什么是应用程序? 动态分配的

【C语言天天练(九)】动态内存分配

引言:数组的元素存储于内存中连续的位置上.当一个数组被声明时.它所须要的内存在编译时就被分配. 可是,我们能够使用动态内存分配在执行时为它分配内存. 一块内存的生命周期能够分为四个阶段:分配.初始化.使用.释放. 内存的分配一般使用C函数库里的malloc函数(原型:void *malloc(size_t size)). 关于malloc函数应该注意一下几点: 1.malloc的參数就是须要分配的内存的字节数. 2.malloc所分配的是一块连续的内存. 3.分配成功.则返回指向分配内存起始地址

SQLite剖析之动态内存分配

SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存.建立数据库文件的内存Cache.以及保存查询结果.我们做了很多努力来让SQLite的动态内存分配子系统可靠.可预测.健壮并且高效.本文概述SQLite的动态内存分配,软件开发人员在使用SQLite时可以据此获得最佳性能. 1.特性    SQLite内核和它的内存分配子系统提供以下特性:    (1)对内存分配失败的健壮处理.如果一个内存分配请求失败(即malloc()或realloc()返回NULL),SQ

继承和动态内存分配

假设基类使用了动态内存分配,而且定义了析构函数.复制构造函数和赋值函数,但是在派生类中没有使用动态内存分配,那么在派生类中不需要显示定义析构函数.复制构造函数和赋值函数. 当基类和派生类采用动态内存分配时,派生类的析构函数.复制构造函数.赋值运算符都必须使用相应的基类方法来处理基类元素.这种要求是通过三种不同的方式来满足的.对于析构函数.这是自动完成的,也就是说在派生类的析构函数中无需显示调用基类的析构函数.对于构造函数,这是通过在初始化成员类别中调用基类的复制构造函数来完成的,如果不这样做,将

【Cpp】考点·堆栈&amp;动态内存分配

动态内存分配 堆内存分配与释放 C/C++定义了四个内存区间:代码区,全局变量与静态变量区,局部变量区(栈区),动态内存区(堆区) 通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间.这种内存分配称为静态存储分配.有些操作对象只在程序运行时才确定,这样编译时无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配.所有动态存储分配都在堆区中进行. 当程序运行到需要一

C++ 动态内存分配(6种情况,好几个例子)

1.堆内存分配 : C/C++定义了4个内存区间: 代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆(heap)区或自由存储区(free store). 堆的概念: 通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间.这种内存分配称为静态存储分配: 有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分

一维和二维数组 动态内存分配

一维数组的动态内存分配 #include "stdafx.h" #include <iostream> using namespace std; int main() { int length,i; int *p; cin>>length; p=new int[length]; for(i=0;i<length;i++) { p[i]=i; //不要写成*p[i]=i; cout<<p[i]<<endl; //不要写成cout<