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

如何实现无需显式长度变量的动态数组?解决内存释放与指针问题

动态数组实现问题

我想实现一个支持Array_Push(array, val)和Array_Del(array, index)操作的动态数组。一开始我用结构体来存数据和大小:

struct Array {  
  int *data;  
  int size;  
}

但访问数组元素时得写array.data[i],感觉太啰嗦。

于是我想把数组大小存在数组的某个索引里,不想用[0]怕混淆,就打算存在[-1]的位置。但[-1]超出了常规数组的范围,所以我先通过int *array = malloc(sizeof(int))分配内存,然后把指针自增1(array += 1),这样返回的指针指向的位置,它的[-1]就是之前分配的内存,用来存size。但现在释放内存的时候,直接free(array)会释放非malloc分配的地址,而且我怀疑在函数里调用malloc/realloc的时候没法修改外部的原指针,不知道怎么解决。

下面是相关代码:

array.h

#pragma once

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

int *Array_Create() {
  int *array = malloc(sizeof(int));

  // 如果malloc分配失败
  if (array == NULL) {
    printf("Error creating array: malloc() failed to allocate memory");
    exit(12);
  }

  array[0] = 0;

  array += 1;

  return array;
}

void Array_Push(int *array, int value) {
  if (array[-1] == 0) {
    array = malloc(sizeof(int));
  } else {
    // array = realloc(array, sizeof(int) * array[-1]);
    printf("ERROR READING ARRAY SIZE IN: Array_Push()");
  }
}

main.c

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

#include <dynamic_array.h>

int main() {
  int *array = Array_Create();

  printf("%d", array[-1]);

  Array_Push(array, 1);

  free((array - 1));
  free(array);

  return 0;
}

解决方案

核心问题分析

  • 内存释放错误:返回的指针是malloc地址+1,直接free(array)会释放非法内存,且main里的两次free属于双重释放,是严重错误。
  • 指针修改无效:Array_Push里的array = malloc(...)只修改了函数内的局部指针,外部原指针不会同步变化,必须用指针的指针传递参数才能修改外部指针变量。

修改后的完整实现

array.h

#pragma once

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

// 创建动态数组,返回指向数据区的指针,size存在[-1]位置
int *Array_Create() {
    // 初始分配1个存size的空间 + 0个数据空间
    int *base = malloc(sizeof(int) * (1 + 0));
    if (base == NULL) {
        fprintf(stderr, "Error creating array: malloc() failed\n");
        exit(12);
    }
    base[0] = 0; // 初始size为0
    return base + 1; // 返回数据区起始指针
}

// 向数组末尾添加元素,需传指针的指针以同步指针变化
void Array_Push(int **array, int value) {
    int *size_ptr = *array - 1;
    int current_size = *size_ptr;

    // 重新分配内存:原size+1个数据 + 1个size存储位
    int *new_base = realloc(size_ptr, sizeof(int) * (current_size + 1 + 1));
    if (new_base == NULL) {
        fprintf(stderr, "Error pushing element: realloc() failed\n");
        exit(13);
    }

    // 更新size和数据区指针
    *new_base = current_size + 1;
    *array = new_base + 1;
    // 存入新元素
    (*array)[current_size] = value;
}

// 删除指定索引的元素,需传指针的指针
void Array_Del(int **array, int index) {
    int *size_ptr = *array - 1;
    int current_size = *size_ptr;

    if (index < 0 || index >= current_size) {
        fprintf(stderr, "Error deleting element: index out of bounds\n");
        return;
    }

    // 把索引后元素前移覆盖
    for (int i = index; i < current_size - 1; i++) {
        (*array)[i] = (*array)[i + 1];
    }

    // 缩小内存分配
    int *new_base = realloc(size_ptr, sizeof(int) * (current_size - 1 + 1));
    if (new_base == NULL) {
        fprintf(stderr, "Error deleting element: realloc() failed\n");
        exit(14);
    }

    // 更新size和数据区指针
    *new_base = current_size - 1;
    *array = new_base + 1;
}

// 释放数组内存,只需传入数据区指针
void Array_Free(int *array) {
    free(array - 1); // 释放最初分配的基地址
}

main.c

#include <stdio.h>
#include "array.h"

int main() {
    int *array = Array_Create();

    // 推入测试元素
    Array_Push(&array, 10);
    Array_Push(&array, 20);
    Array_Push(&array, 30);

    // 打印当前数组
    int size = array[-1];
    printf("Array size: %d\nElements: ", size);
    for (int i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    // 删除索引1的元素
    Array_Del(&array, 1);
    size = array[-1];
    printf("After delete index 1:\nSize: %d\nElements: ", size);
    for (int i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    // 释放内存
    Array_Free(array);
    return 0;
}

关键改进点

  • 规范内存管理:始终通过array - 1访问存储size的基地址,释放时仅需free该基地址,避免内存泄漏或双重释放。
  • 指针同步更新:Array_Push和Array_Del使用int **array参数,确保realloc后的新指针能同步到外部变量。
  • 封装操作逻辑:提供Array_Free函数,避免用户手动计算基地址出错,同时简化调用流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:02:08