You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用realloc操作数组时双指针的必要性探究

为什么手动内存管理中有时需要双指针,有时不需要?

核心原因很直接:C/C++里函数参数是值传递。如果你的函数需要修改外部指针变量本身的指向(比如让它指向realloc返回的新内存地址),就必须用双指针(指针的指针);如果只是用指针操作它指向的内存,单指针就够,但你的第二个函数其实是错误写法,只是碰巧“正常”而已。

双指针实现的正确逻辑

先看你的第一个函数:

struct pathToCity{ 
  int lengthCities;
  char cities[100];
};

void appendToPathToCitiesArray(pathToCity **array, int *length, pathToCity newCity) {
  if (*length == 0) {
    *array = (pathToCity*) malloc(sizeof(pathToCity));
  }
  else {
    *array = (pathToCity*) realloc(*array, (*length + 1) * sizeof(pathToCity));
  }
  // 注意:这里应该检查*array是否为NULL,而非array本身
  if (*array == NULL) {
    cout << "Error allocating memory." << endl;
    exit(-1);
  }
  (*array)[*length] = newCity;
  (*length)++;
}

调用时传递的是&queue(指针的地址),函数里的*array就是外部的queue指针本身。realloc的行为分两种:如果原内存块后有足够空间扩容,就返回原地址;如果没有,就分配新内存、拷贝旧数据、释放旧内存后返回新地址。不管哪种情况,把realloc的结果赋值给*array,都会同步修改外部的queue指针,确保后续所有操作都在正确的内存地址上进行,这才是可靠的写法。

无双指针实现的“假象正常”

你的第二个函数本质是错误的,只是测试场景刚好没触发问题:

#include <iostream>
using namespace std;

struct shortText {
    int lengthText;
    char text[3];
};

void append(shortText *array, int *length, shortText newCity) {
  if (*length == 0) {
    array = (shortText*) malloc(sizeof(shortText));
  }
  else {
    array = (shortText*) realloc(array, (*length + 1) * sizeof(shortText));
  }
  if (array == NULL) {
    cout << "Error allocating memory" << endl;
    exit(-1);
  }
  array[*length] = newCity;
  (*length)++;
}

int main() {
  int length = 3;
  shortText *arr = (shortText*) malloc(sizeof(shortText) * length);
  arr[0] = {2, "ab"};
  arr[1] = {2, "ab"};
  arr[2] = {2, "ab"};
  shortText s = {2, "ab"};
  append(arr, &length, s);
  arr[3] = {8, "ji"};
  cout << length << endl;
  cout << arr[3].lengthText << endl;
  free(arr);
}
  • 函数里的array是外部arr指针的副本,函数内给array赋值realloc的结果,完全不会改变外部的arr指针。
  • 你测试时length初始是3,realloc尝试扩容到4个元素。如果操作系统在原内存块后面刚好有足够的空闲空间,realloc会直接原地扩容,返回的地址和原地址一样,这时候外部的arr指针还能访问到新空间,看起来正常。
  • 但如果原内存块后面没有足够空间,realloc会分配新内存,拷贝旧数据后释放旧内存。这时候函数内的array指向新地址,但外部的arr还是指向已被释放的旧地址:
    • 后续arr[3]的赋值是访问无效内存,会触发崩溃;
    • 最后free(arr)会导致二次释放旧内存,同样崩溃;
    • 新分配的内存地址只有函数内的array知道,函数结束后就丢失了,造成内存泄漏。

总结

  • 只要你的函数需要修改外部指针变量的指向(比如初始化内存、重新分配内存),就必须用双指针,这样函数内部的修改才能同步到外部。
  • 你的第二个函数只是运气好没出问题,实际项目中这种写法会导致各种难以排查的崩溃和内存泄漏,绝对不能用。

内容的提问来源于stack exchange,提问作者Markus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:53:26