黑龙江省建设教育网站查询,福建省住房与城乡建设部网站,网站查不到备案,天津网站优化排名文章目录前言一、new/delete1. 序言2. 使用方法2.1. new 和 delete 基本语法2.2. new 和 delete 的底层实现原理3. 底层原理3.1. operator new 和 operator delete3.2. new 和 delete 的底层实现原理4. 注意事项5. 总结二、malloc/free1. 序言2. 使用方法2.1. malloc 和 free 基…
文章目录前言一、new/delete1. 序言2. 使用方法2.1. new 和 delete 基本语法2.2. new 和 delete 的底层实现原理3. 底层原理3.1. operator new 和 operator delete3.2. new 和 delete 的底层实现原理4. 注意事项5. 总结二、malloc/free1. 序言2. 使用方法2.1. malloc 和 free 基本语法2.2. malloc 和 free 的底层实现原理3. 底层原理3.1. sbrk 函数3.2. 内存块管理3.3. 内存对齐4. 注意事项5. new/delete 与 malloc/free 的区别6. 总结前言
对C学习感兴趣的可以看看这篇文章哦C/C教程
一、new/delete
1. 序言
在 C 的程序设计中动态内存分配是非常常见的操作。new 和 delete 是 C 中提供的动态内存分配运算符它们可以用于动态分配任意类型的内存并且不需要显式地指定内存块的大小。
2. 使用方法
2.1. new 和 delete 基本语法
new 和 delete 是 C 中的关键字用于动态分配和释放内存。下面是 new 和 delete 的基本语法
// 动态分配一个对象
Type* p new Type;// 释放已经分配的对象
delete p;其中 Type 表示要动态分配的数据类型p 是一个指向该数据类型的指针。当执行 new Type 操作时系统会为该类型的对象分配一块内存并返回指向这个内存块的指针。当不再需要这个对象时可以通过 delete 操作来释放这块内存。
如果需要同时分配多个对象可以使用如下语法
// 动态分配一个数组
Type* p new Type[n];// 释放已经分配的数组
delete [] p;其中 n 表示要分配的对象个数p 是一个指向 Type 类型数组的指针。
需要注意的是在使用 new 进行动态内存分配时如果发生内存不足的情况则会抛出 std::bad_alloc 异常。因此在程序中应该对这种异常进行处理。
2.2. new 和 delete 的底层实现原理
new 和 delete 在底层实现上也有一些细节需要注意。在执行 new Type 操作时实际上是依次进行了以下几个步骤
调用 operator new 函数来申请一块大小为 sizeof(Type) 的内存。调用类的构造函数来初始化申请到的内存空间。返回指向申请到的内存空间的指针。
而在执行 delete p 操作时实际上是依次进行了以下几个步骤
调用类的析构函数来释放对象占用的资源。调用 operator delete 函数来释放对象所占用的内存。
其中 operator new 和 operator delete 都是 C 中提供的关键字。operator new 函数负责申请内存而 operator delete 函数负责释放内存。
需要注意的是和 malloc/free 不同的是new/delete 能够调用类的构造和析构函数并自动计算所需的内存空间大小。这也是使用 new/delete 的一大优势。
3. 底层原理
3.1. operator new 和 operator delete
C 中的 operator new 函数和 operator delete 函数是用来动态分配和释放内存的。operator new 函数负责申请内存而 operator delete 函数负责释放内存。
下面是 operator new 的一种实现方式
void* operator new(size_t size) {if (size 0) {size 1;}void* ptr malloc(size);if (!ptr) {throw std::bad_alloc();}return ptr;
}其中 size 表示要申请的内存空间大小。如果该值为 0则将其设置为 1。然后调用 malloc 函数来申请指定大小的内存空间如果申请失败则抛出 std::bad_alloc 异常。
下面是 operator delete 的一种实现方式
void operator delete(void ptr) noexcept {free(ptr);
}其中 ptr 是要释放的内存空间指针。这里使用了 noexcept 关键字来表明该函数不会抛出任何异常。
注意在使用 operator new 和 operator delete 函数时需要自己负责调用类的构造函数和析构函数。
3.2. new 和 delete 的底层实现原理
new 和 delete 关键字在底层实现上实际上是对 operator new 和 operator delete 函数进行了封装和重载以方便程序员使用。下面是 new 和 delete 的一种实现方式
void* operator new(size_t size) {if (size 0) {size 1;}void* ptr malloc(size);if (!ptr) {throw std::bad_alloc();}return ptr;
}void operator delete(void* ptr) noexcept {free(ptr);
}void* operator new[](size_t size) {if (size 0) {size 1;}void* ptr malloc(size);if (!ptr) {throw std::bad_alloc();}return ptr;
}void operator delete[](void* ptr) noexcept {free(ptr);
}可以看到new 和 delete 实际上是对 operator new 和 operator delete 进行了重载。 注意对于复杂数据结构使用new[] 申请多个内存时会多申请一块4字节的内存用于存储当前申请的数量用于delete[]知道调用几次对象的析构函数但这个数据对外不可见 4. 注意事项
在使用 new/delete 进行动态内存分配时需要注意以下几点
内存泄漏必须及时释放不再使用的内存否则可能会导致内存泄漏。悬空指针已经释放的内存块指针不能再被访问否则可能会导致程序崩溃或出现其他的不可预测的错误。不要重复释放内存同一个内存块只能被释放一次否则可能会导致程序崩溃或出现其他的不可预测的错误。多线程环境在多个线程同时访问同一块内存时需要采用适当的同步机制来保证线程安全。
5. 总结
在 C 编程中应该根据具体情况选择适当的动态内存分配方式在使用动态内存分配时应该遵循良好的编程习惯确保程序的正确性和稳定性。同时也需要注意避免内存泄漏、悬空指针、重复释放内存等问题保证程序的健壮性和稳定性。
二、malloc/free
1. 序言
malloc 和 free 是 C 中提供的动态内存分配函数它们可以用于动态分配任意类型的内存并且不需要显式地指定内存块的大小
2. 使用方法
2.1. malloc 和 free 基本语法
malloc 和 free 是 C中的函数用于动态分配和释放内存。下面是 malloc 和 free 的基本语法
// 动态分配一块内存
Type* p (Type*)malloc(sizeof(Type));// 释放已经分配的内存
free(p);其中 Type 表示要动态分配的数据类型p 是一个指向该数据类型的指针。当执行 malloc(sizeof(Type)) 操作时系统会为该类型的对象分配一块内存并返回指向这个内存块的指针。当不再需要这个对象时可以通过 free 操作来释放这块内存。
需要注意的是在使用 malloc 进行动态内存分配时如果发生内存不足的情况则会返回空指针。因此在程序中应该对这种情况进行处理。
2.2. malloc 和 free 的底层实现原理
malloc 和 free 在底层实现上也有一些细节需要注意。在执行 malloc(sizeof(Type)) 操作时实际上是依次进行了以下几个步骤
调用系统函数 sbrk 来扩展程序的数据段。windows则会调用win API来实现这一功能将申请到的内存块与已经使用的内存块链接起来。返回指向申请到的内存空间的指针。
而在执行 free(p) 操作时实际上是依次进行了以下几个步骤
将 p 所指向的内存块标记为未使用。将 p 所指向的内存块与其他未使用的内存块合并起来。如果合并后的内存块没有被占用则释放该内存块。
需要注意的是在使用 malloc/free 进行动态内存分配时需要自己负责调用类的构造函数和析构函数并且无法计算所需的内存空间大小。
3. 底层原理
3.1. sbrk 函数
sbrk 函数是一个系统调用用于扩展程序的数据段。在 Linux 系统中sbrk 函数可以返回当前堆顶部地址并且可以将堆顶部地址向上或向下移动指定的字节数。
下面是一个简单的示例演示了如何使用 sbrk 函数来获取当前堆顶部地址
#include unistd.h
#include iostreamint main() {void* p1 sbrk(0); // 获取当前堆顶部地址std::cout p1 p1 std::endl;void* p2 sbrk(1024); // 将堆顶部地址向上移动 1024 字节std::cout p2 p2 std::endl;void* p3 sbrk(-512); // 将堆顶部地址向下移动 512 字节std::cout p3 p3 std::endl;void* p4 sbrk(0); // 再次获取当前堆顶部地址std::cout p4 p4 std::endl;return 0;
}而window系统也有自己的win API可以用于分配堆内存 3.2. 内存块管理
malloc 和 free 在底层实现上还需要进行内存块的管理。在使用 malloc 进行动态内存分配时系统会为申请的内存块添加一些额外的信息
例如内存块的大小、指向下一个内存块的指针等。这些信息会被保存在内存块的开始位置并且不会影响用户程序对内存空间的访问。
下面是一个简单的示例演示了如何通过 malloc 函数获取一块内存以及内存块中包含的信息
#include iostream
#include cstdlibint main() {int* p (int*)malloc(sizeof(int) * 10); // 动态分配一块内存可以存放 10 个 int 类型的变量if (!p) {std::cout Memory allocation failed std::endl;return -1;}std::cout Allocate memory at address p std::endl;std::cout The size of the memory block is sizeof(int) * 10 bytes std::endl;int* next_p (int*)(((char*)p) sizeof(int) * 10);std::cout The pointer to the next memory block is next_p std::endl;free(p); // 释放内存return 0;
}3.3. 内存对齐
在使用 malloc 进行动态内存分配时需要考虑内存对齐的问题。
所谓内存对齐就是指将数据类型放置在内存中的地址必须满足一定的条件。
具体来说每个数据类型都有一个与之相关联的对齐值这个对齐值通常等于该数据类型的大小例如 int 的对齐值为 4 字节。在进行内存分配时系统会确保申请到的内存块的起始地址是对齐值的整数倍。
下面是一个简单的示例演示了如何通过 malloc 函数获取一块内存并展示内存对齐的效果
#include iostream
#include cstdlibstruct MyStruct {double x;char c;int i;
};int main() {std::cout Size of MyStruct is sizeof(MyStruct) bytes std::endl;MyStruct* p1 (MyStruct*)malloc(sizeof(MyStruct));if (!p1) {std::cout Memory allocation failed std::endl;return -1;}std::cout Allocate memory at address p1 std::endl;char* p2 (char*)p1;for (int i 0; i sizeof(MyStruct); i) {std::cout (int)p2[i] ;}std::cout std::endl;free(p1); // 释放内存return 0;
}可以看到在分配 MyStruct 类型的内存时系统会确保返回的起始地址是 double 类型大小的整数倍。
4. 注意事项
在使用 malloc/free 进行动态内存分配时需要注意以下几点
内存泄漏必须及时释放不再使用的内存否则可能会导致内存泄漏。悬空指针已经释放的内存块指针不能再被访问否则可能会导致程序崩溃或出现其他的不可预测的错误。不要重复释放内存同一个内存块只能被释放一次否则可能会导致程序崩溃或出现
其他的不可预测的错误。
内存越界访问已经释放的内存块或者访问超出分配的内存块范围的地址都可能会导致程序崩溃或出现其他的不可预测的错误。不要混用 malloc/free 和 new/delete在同一个程序中应该统一使用一种内存分配方式不要混用 malloc/free 和 new/delete否则可能会导致内存管理出现问题。
5. new/delete 与 malloc/free 的区别
new 和 delete 是 C 中提供的动态内存分配运算符它们和 malloc/free 在功能上是类似的。
new/delete 的使用方法比 malloc/free 更简单直观。另外new/delete 还有以下几个优点
类型安全new/delete 可以根据类型自动计算所需的内存空间大小无需手动指定。自动调用构造函数和析构函数new 可以自动调用类的构造函数delete 可以自动调用类的析构函数更方便地管理对象的生命周期。支持重载new/delete 运算符可以被重载从而可以实现一些特殊的功能。
需要注意的是在使用 new/delete 进行动态内存分配时同样可能会出现内存泄漏、悬空指针、内存越界等问题。因此在编写程序时必须仔细处理动态内存分配和释放的问题避免出现以上问题。
6. 总结
在使用动态内存分配的过程中需要注意内存泄漏、悬空指针、内存越界等问题同时还需要根据具体情况选择合适的内存分配方式。