C++动态数组两种实现方式详解(std::vector vs malloc)
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1. std::vector:现代C++的推荐方式</li><ul class="second_class_ul"><li>1.1 基本语法与参数</li><li>1.2 如何访问和操作元素</li><li>1.3 完整示例</li></ul><li>2. malloc:C风格的动态内存分配</li><ul class="second_class_ul"><li>2.1 基本语法与参数</li><li>2.2 如何访问和操作元素</li><li>2.3 完整示例</li></ul><li>3. 详细对比与选择指南</li><ul class="second_class_ul"><li>3.1 内存管理对比</li><li>3.2 性能与安全对比</li></ul><li>4. 高级用法与技巧</li><ul class="second_class_ul"><li>4.1 std::vector的高级特性</li><li>4.2 malloc的高级用法与陷阱</li></ul></ul></div><p>在C++中,动态数组是处理可变大小数据集合的常见需求。本文将详细介绍两种主要的实现方式:使用C++标准库的<code>std::vector</code>和使用C风格的<code>malloc</code>,并对比它们的差异、使用方法以及最佳实践。</p><p class="maodian"></p><h2>1. std::vector:现代C++的推荐方式</h2>
<p class="maodian"></p><h3>1.1 基本语法与参数</h3>
<div class="jb51code"><pre class="brush:cpp;">// 基本语法
std::vector<T> name(size);
// 实际示例
std::vector<uint8_t> occlusions(points_cnt);
</pre></div>
<p><strong>参数详解:</strong></p>
<ul><li><strong>模板参数</strong> <code>T</code>:指定向量中元素的类型,这里是<code>uint8_t</code>(无符号8位整数,通常就是<code>unsigned char</code>)</li><li><strong>构造函数参数</strong> <code>size</code>:指定向量初始的大小,这里是<code>points_cnt</code>(必须是整数类型)</li><li><strong>向量名称</strong> <code>occlusions</code>:变量名,遵循C++命名规则</li></ul>
<p class="maodian"></p><h3>1.2 如何访问和操作元素</h3>
<p><strong>访问单个元素:</strong></p>
<div class="jb51code"><pre class="brush:cpp;">// 使用下标运算符(不进行边界检查)
occlusions = 255; // 设置第一个元素
uint8_t value = occlusions; // 获取第一个元素
// 使用at()方法(进行边界检查,安全但稍慢)
occlusions.at(0) = 255; // 如果索引越界会抛出std::out_of_range异常
uint8_t value = occlusions.at(0);
// 使用迭代器
auto it = occlusions.begin();// 获取起始迭代器
*it = 255; // 通过迭代器访问元素
</pre></div>
<p><strong>遍历所有元素:</strong></p>
<div class="jb51code"><pre class="brush:cpp;">// 方法1:使用下标循环
for (size_t i = 0; i < occlusions.size(); ++i) {
occlusions = i % 256;// 赋值
std::cout << (int)occlusions << " ";// 访问
}
// 方法2:使用范围for循环(C++11起)
for (uint8_t& val : occlusions) {
val = 128;// 可以直接修改
}
// 方法3:使用迭代器
for (auto it = occlusions.begin(); it != occlusions.end(); ++it) {
*it = 64;
}
</pre></div>
<p class="maodian"></p><h3>1.3 完整示例</h3>
<div class="jb51code"><pre class="brush:cpp;">#include <iostream>
#include <vector>
#include <cstdint>
void vectorExample() {
size_t points_cnt = 10;
// 创建并初始化向量
std::vector<uint8_t> occlusions(points_cnt, 0);// 所有元素初始化为0
// 修改元素
for (size_t i = 0; i < points_cnt; ++i) {
occlusions = static_cast<uint8_t>(i * 25);
}
// 添加新元素
occlusions.push_back(255);// 自动调整大小
occlusions.emplace_back(128);// C++11:原地构造
// 读取并显示所有元素
std::cout << "Vector contents: ";
for (const auto& val : occlusions) {
std::cout << (int)val << " ";
}
std::cout << std::endl;
// 获取向量信息
std::cout << "Size: " << occlusions.size() << std::endl;
std::cout << "Capacity: " << occlusions.capacity() << std::endl;
// 注意:不需要手动释放内存!
// 当occlusions离开作用域时,vector会自动清理
}
</pre></div>
<p class="maodian"></p><h2>2. malloc:C风格的动态内存分配</h2>
<p class="maodian"></p><h3>2.1 基本语法与参数</h3>
<div class="jb51code"><pre class="brush:cpp;">// 基本语法
T* name = (T*)malloc(count * sizeof(T));
// 实际示例
unsigned char* occlusions = (unsigned char*)malloc(points_cnt * sizeof(unsigned char));
</pre></div>
<p><strong>参数详解:</strong></p>
<ul><li><strong><code>malloc</code>函数参数</strong>:需要分配的字节数 = <code>points_cnt * sizeof(unsigned char)</code></li><li><strong>返回值类型转换</strong>:<code>malloc</code>返回<code>void*</code>,需要强制转换为目标指针类型</li><li><strong>指针变量 <code>occlusions</code></strong>:指向分配内存起始地址的指针</li></ul>
<p class="maodian"></p><h3>2.2 如何访问和操作元素</h3>
<p><strong>访问单个元素:</strong></p>
<div class="jb51code"><pre class="brush:cpp;">// 使用数组下标语法
occlusions = 255; // 设置第一个元素
unsigned char value = occlusions;// 获取第一个元素
// 使用指针算术
*(occlusions) = 255; // 等价于occlusions = 255
*(occlusions + 1) = 128; // 等价于occlusions = 128
unsigned char value = *(occlusions + 2);// 等价于occlusions
</pre></div>
<p><strong>遍历所有元素:</strong></p>
<div class="jb51code"><pre class="brush:cpp;">// 使用指针遍历
unsigned char* ptr = occlusions;
for (size_t i = 0; i < points_cnt; ++i) {
*ptr = static_cast<unsigned char>(i * 25);
++ptr;// 移动指针
}
// 使用下标遍历
for (size_t i = 0; i < points_cnt; ++i) {
occlusions = i % 256;
}
</pre></div>
<p class="maodian"></p><h3>2.3 完整示例</h3>
<div class="jb51code"><pre class="brush:cpp;">#include <iostream>
#include <cstdlib>// malloc, free
#include <cstring>// memset
void mallocExample() {
size_t points_cnt = 10;
// 分配内存
unsigned char* occlusions =
(unsigned char*)malloc(points_cnt * sizeof(unsigned char));
// 重要:检查分配是否成功
if (occlusions == nullptr) {
std::cerr << "Memory allocation failed!" << std::endl;
return;
}
// 重要:初始化内存(malloc不初始化内存!)
memset(occlusions, 0, points_cnt * sizeof(unsigned char));
// 填充数据
for (size_t i = 0; i < points_cnt; ++i) {
occlusions = static_cast<unsigned char>(i * 25);
}
// 显示内容
std::cout << "Malloc array contents: ";
for (size_t i = 0; i < points_cnt; ++i) {
std::cout << (int)occlusions << " ";
}
std::cout << std::endl;
// 重要:必须手动释放内存!
free(occlusions);
occlusions = nullptr;// 避免野指针
}
</pre></div>
<p class="maodian"></p><h2>3. 详细对比与选择指南</h2>
<p class="maodian"></p><h3>3.1 内存管理对比</h3>
<table><thead><tr><th>特性</th><th>std::vector</th><th>malloc/free</th></tr></thead><tbody><tr><td>初始化</td><td>默认初始化元素</td><td>不初始化,内容是随机的</td></tr><tr><td>内存释放</td><td>自动(RAII)</td><td>必须手动调用free()</td></tr><tr><td>异常安全</td><td>是,构造函数失败会抛出异常</td><td>否,需要检查返回值</td></tr><tr><td>重新分配</td><td>自动(resize/push_back)</td><td>需要realloc(),数据可能被移动</td></tr></tbody></table>
<p class="maodian"></p><h3>3.2 性能与安全对比</h3>
<div class="jb51code"><pre class="brush:cpp;">// std::vector的安全性示例
void safeVectorExample() {
std::vector<uint8_t> vec(10);
try {
vec.at(20) = 100;// 抛出std::out_of_range异常
} catch (const std::out_of_range& e) {
std::cout << "安全地捕获了越界访问: " << e.what() << std::endl;
}
// vec = 100;// 未定义行为,可能崩溃或数据损坏
}
// malloc的不安全性示例
void unsafeMallocExample() {
unsigned char* arr = (unsigned char*)malloc(10);
// 常见错误1:忘记检查分配是否成功
if (arr == nullptr) { /* 必须检查! */ }
// 常见错误2:忘记初始化
// arr可能是任意值!
// 常见错误3:越界访问
arr = 100;// 未定义行为,可能破坏其他内存
// 常见错误4:忘记释放内存(内存泄漏)
// free(arr);// 如果忘记这行,内存泄漏!
}
</pre></div>
<p class="maodian"></p><h2>4. 高级用法与技巧</h2>
<p class="maodian"></p><h3>4.1 std::vector的高级特性</h3>
<div class="jb51code"><pre class="brush:cpp;">void advancedVectorUsage() {
// 多种初始化方式
std::vector<uint8_t> v1(10, 0xFF); // 10个元素,每个都是0xFF
std::vector<uint8_t> v2 = {0, 1, 2, 3, 4};// 初始化列表(C++11)
std::vector<uint8_t> v3(v1); // 拷贝构造
// 内存预分配
v1.reserve(1000);// 预分配内存,避免多次重新分配
// 安全访问
if (!v1.empty()) {
uint8_t first = v1.front();// 第一个元素
uint8_t last = v1.back(); // 最后一个元素
}
// 范围操作
v1.insert(v1.begin(), {10, 20, 30});// 开头插入多个元素
v1.erase(v1.begin() + 1, v1.begin() + 3);// 删除第2-3个元素
// C++17:并行算法支持
std::sort(std::execution::par, v1.begin(), v1.end());
}
</pre></div>
<p class="maodian"></p><h3>4.2 malloc的高级用法与陷阱</h3>
<div class="jb51code"><pre class="brush:cpp;">void advancedMallocUsage() {
size_t count = 10;
// 正确:使用calloc自动初始化为0
unsigned char* arr1 = (unsigned char*)malloc(count * sizeof(unsigned char));
// arr1的所有元素都是0
// 正确:使用realloc调整大小
arr1 = (unsigned char*)realloc(arr1, count * 2);
// 注意:realloc可能移动内存,原有指针失效
// 陷阱:错误的大小计算
// 错误:可能溢出
size_t large = 1000000000;
// unsigned char* bad = malloc(large * large);// 溢出!
// 正确:检查溢出
if (large > SIZE_MAX / sizeof(unsigned char)) {
// 处理溢出错误
}
// 释放内存
free(arr1);
}
</pre></div>
<p>到此这篇关于C++动态数组两种实现方式详解(std::vector vs malloc)的文章就介绍到这了,更多相关C++动态数组内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>C++动态数组vector的使用小结</li><li>C++动态数组类的封装实例</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]