数据结构拓展:详解realloc(C++)

前言

在C++中,realloc 是C标准库提供的一个内存管理函数,用于动态调整已分配内存块的大小 。尽管C++更推荐使用 new/delete 或智能指针,但在某些场景(如与C代码交互或底层内存操作)中仍可能用到 realloc。以下是详细分析:

一、realloc 的核心行为

cpp 复制代码
void* realloc(void* ptr, size_t new_size);
  • 功能 :调整 ptr 指向的内存块大小(原内存块由 malloc/calloc/realloc 分配)。
  • 返回值
    • 成功:返回指向新内存块的指针(可能与原指针不同)。
    • 失败:返回 NULL原内存块保持不变
  • 底层逻辑
    1. new_size 为0且 ptr 非空:等价于 free(ptr),返回 NULL
    2. ptrNULL:等价于 malloc(new_size)
    3. 若当前内存块后有空闲空间:直接扩展内存,原数据保留。
    4. 若空间不足:分配新内存块 → 复制原数据 → 释放旧内存块。

二、realloc 在C++中的风险

1. 不适用于非POD类型
  • 问题realloc 不会调用构造函数或析构函数,可能导致对象生命周期管理错误。
cpp 复制代码
struct NonPOD {
    int* ptr;
    NonPOD() { ptr = new int(42); }    // 构造函数分配内存
    ~NonPOD() { delete ptr; }          // 析构函数释放内存
};

NonPOD* arr = (NonPOD*)malloc(10 * sizeof(NonPOD));
// 错误!构造函数未被调用
arr = (NonPOD*)realloc(arr, 20 * sizeof(NonPOD)); 
// 若内存地址改变,旧内存被释放,但析构函数未执行 → 内存泄漏
2. 返回值处理不当导致内存泄漏
  • 错误示例
cpp 复制代码
int* ptr = (int*)malloc(100);
ptr = (int*)realloc(ptr, 200);  // 若 realloc 失败,ptr 被设为 NULL,原内存泄漏!

正确做法:使用临时变量保存结果。

cpp 复制代码
int* tmp = (int*)realloc(ptr, 200);
if (tmp) {
    ptr = tmp;  // 成功后再赋值
} else {
    // 处理失败,原 ptr 仍有效
}

三、C++中的替代方案

1. 使用 new/delete 和手动复制
cpp 复制代码
int* old_arr = new int[10];
int* new_arr = new int[20];
std::copy(old_arr, old_arr + 10, new_arr);
delete[] old_arr;  // 正确释放旧内存
2. 使用 std::vector
  • 推荐方案:自动处理内存分配、复制和释放。
cpp 复制代码
std::vector<int> vec(10);
vec.resize(20);  // 自动重新分配内存并复制数据
3. 智能指针 + realloc 替代方案
  • 若必须使用 realloc,可结合 unique_ptr 自定义删除器:
cpp 复制代码
auto deleter = [](int* ptr) { free(ptr); };
std::unique_ptr<int[], decltype(deleter)> ptr((int*)malloc(100), deleter);
// 调整大小
int* tmp = (int*)realloc(ptr.get(), 200);
if (tmp) {
    ptr.release();  // 解除原有指针管理
    ptr.reset(tmp); // 接管新指针
}

四、realloc 的适用场景

场景 是否推荐 原因
处理POD类型(如基本类型) 谨慎使用 需手动管理内存,但无构造/析构函数风险
非POD类型(类对象) 禁止使用 破坏对象生命周期,导致未定义行为
高性能动态数组 有限使用 可能比 new + 复制更快,但需确保内存连续且类型简单

五、realloc 的优缺点

优点 缺点
可能原地扩展内存,减少复制开销 不适用于C++对象(无法处理构造/析构)
语法简洁 返回值处理不当易导致内存泄漏
兼容C代码 内存分配失败需手动回退
需显式类型转换(C++中强制要求)

六、总结

  • 在C++中尽量避免直接使用 realloc ,优先选择 std::vectorstd::unique_ptr 或手动 new/delete
  • 若必须使用
    1. 仅用于POD类型(如基本类型、结构体无构造/析构函数)。
    2. 严格检查返回值,避免内存泄漏。
    3. 考虑与智能指针结合,增强安全性。

扩展:代码(初阶)

SeqList.h

cpp 复制代码
#pragma once

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

//定义动态顺序表结构

typedef int SLDataType;

struct SeqList {
	int* arr;
	int capacity;
	int size;
};

typedef struct SeqList SL;

//初始化

void SLInit(SL* ps);

//销毁

void SLDestory(SL* ps);

//插入数据

void SLPushBack(SL* ps, SLDataType x);

void SLPushFront(SL* ps, SLDataType x);

Test.cpp

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS  1
#pragma warning(disable:6031)

#include"SeqList.h"

void SLTest01() {
	SL s;
	SLInit(&s);
}

int main() {
	SLTest01();
	return 0;
}

SeqList.cpp

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS  1
#pragma warning(disable:6031)

#include"SeqList.h"

//初始化

void SLInit(SL* ps) {
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//销毁

void SLDestory(SL* ps) {
	if (ps->arr != NULL) {
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//插入数据

void SLPushBack(SL* ps, SLDataType x) {
	//判断空间是否充足

	if (ps->size == ps->capacity) {
		//增容
		ps->arr=realloc
	}

	ps->arr[ps->size] = x;
	ps->size++;
}
相关推荐
为何创造硅基生物2 小时前
C语言 结构体内存对齐规则(通俗易懂版)
c语言·开发语言
仰泳之鹅2 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
jolimark3 小时前
C语言自学攻略:小白入门三步走
c语言·编程入门·学习路线·实践项目·自学攻略
于小猿Sup3 小时前
VMware在Ubuntu22.04驱动Livox Mid360s
linux·c++·嵌入式硬件·自动驾驶
cen__y3 小时前
Linux12(Git01)
linux·运维·服务器·c语言·开发语言·git
社交怪人4 小时前
【算平均分】信息学奥赛一本通C语言解法(题号2071)
c语言·开发语言
卢锡荣5 小时前
单芯通吃,盲插标杆 —— 乐得瑞 LDR6020,Type‑C 全场景互联 “智慧芯”
c语言·开发语言·计算机外设
Mr. zhihao5 小时前
深入解析redis基本数据结构
数据结构·数据库·redis
念何架构之路5 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星5 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi