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

C语言分配存储字符串Arr结构体的三维张量实现方案

问题背景

我实现了一个可存储字符串的类结构(二维数组/矩阵),目前功能运行正常,现在需要存储多个这类矩阵,因此需要使用calloc分配三维张量内存,但我仅掌握二维矩阵的分配方法,不清楚三维张量的后续实现逻辑。
我实现的二维数组代码如下:
头文件arr.h代码:

#pragma once

#include <stdlib.h>
#include <stdint.h> /* uints */
#include <string.h> /* char */

/* struct that holds data about the matrix, so it can be resized when needed */

struct Arr {

    char** cArr;

    unsigned int currentSize, maxSize;

};

/* initial allocation function that is used when a array needs te be calloced at first */

uint8_t initialAlloc(struct Arr* arr);

/* reallocate the array to a hardcoded size */

uint8_t reallocArr(struct Arr* arr);

/* add an element to the array in arr */

void addToArr(struct Arr* arr, char* element);

对应实现arr.c代码:

#include "arr.h"

uint8_t initialAlloc(struct Arr* arr) {

    arr->currentSize = 0;

    arr->maxSize = 2;

    arr->cArr = calloc(2, sizeof(char*));

    if (!arr->cArr) {
    
        return 0;

    }

    for (uint8_t x = 0; x < arr->maxSize; ++x) {

        arr->cArr[x] = calloc(600, sizeof(char));

        if (!arr->cArr[x]) {

            return 0;
        
        }

    }

    return 1;

}

void addToArr(struct Arr* arr, char* element) {

    if (arr->currentSize == arr->maxSize) {

        if (!reallocArr(arr)) {

            /* if the memory allocation fails something is bad wrong */

            exit(1);

        }

    }
    
    strncpy(arr->cArr[arr->currentSize], element, strlen(element));

    ++arr->currentSize;

}

uint8_t reallocArr(struct Arr* arr) {

    uint16_t resizeTo = arr->maxSize * 2;

    arr->cArr = realloc(arr->cArr, resizeTo * sizeof(char*));

    if (!arr->cArr) {

        return 0;

    }


    for (uint16_t x = arr->currentSize; x < resizeTo; ++x) {

        arr->cArr[x] = calloc(600, sizeof(char));

        if (!arr->cArr[x]) {

            return 0;

        }
    }

    arr->maxSize = arr->maxSize * 2;

    return 1;

}

我希望在三维张量中使用上述Arr结构体,已编写的张量头文件代码如下:

#pragma once

#include <stdlib.h> /* basic functions */
#include <stdint.h> /* uint */

/* user includes */

#include "characterArr.h" 

/* user includes */


struct Tensor {

    char*** mArr;

    unsigned int currentSize, maxSize;

};

uint8_t initialAllocTensor(struct Tensor* tensor);

uint8_t reallocTensor(struct Tensor* tensor);

void addToTensor(struct Tensor* tensor, struct Arr* arr);

张量初始分配的实现目前仅完成部分:

/* user includes */

#include "tensor.h"

/* user includes */


/* initial allocation function that is used when a array needs te be calloced at first */

uint8_t initialAllocTensor(struct Tensor* tensor) {

    tensor->currentSize = 0;

    tensor->maxSize = 2;

    tensor->mArr = calloc(2, sizeof(struct *Arr));

    if (!tensor->mArr) {
    
        return 0;

    }

    for (uint8_t x = 0; x < arr->maxSize; ++x) {

        arr->cArr[x] = calloc(600, sizeof(char));

        if (!arr->cArr[x]) {

            return 0;
        
        }

    }

    return 1;

}
核心疑问

在分配完用于存储Arr结构体指针的内存后,我就不清楚后续该如何实现了:我后续需要使用Arr结构体中的全部信息,完全没必要将已有Arr结构体中的数据重新拷贝到新创建的三维张量中。

  • 我是否可以直接在Tensor中存储指向Arr结构体的指针来完成功能?
  • 如果采用这种实现方式,我是否可以正常访问Arr结构体的内容?
  • 由于相关内存是通过malloc/calloc类函数分配在堆上的,我是否不需要担心变量离开作用域后内存被回收的问题?

解答

方案修正

你当前的Tensor结构体定义和实现逻辑存在错误,不需要用char***类型存三维字符数组,直接存储Arr结构体指针是完全可行的,也是这类场景下最高效的方案,不需要做任何数据深拷贝。
首先修正Tensor结构体定义:

struct Tensor {
    // 直接存储Arr结构体指针的数组,不需要三级char指针
    struct Arr** arrList;
    unsigned int currentSize, maxSize;
};

问题答复

  • 是否可以直接在Tensor中存储指向Arr结构体的指针完成功能?
    完全可以。你只需要给Arr*类型的数组分配堆内存即可,存入的指针直接指向你已经初始化好的Arr实例,不需要额外拷贝内部字符串数据。
  • 采用这种实现方式是否可以正常访问Arr结构体的内容?
    可以正常访问。你通过数组下标拿到Arr*指针后,和普通指针用法完全一致,直接用->操作符就能访问cArr、currentSize、maxSize所有成员,和你之前操作单个Arr没有区别。
  • 堆分配内存是否不需要担心作用域回收问题?
    堆上分配的内存不会随栈变量离开作用域自动回收,只要你没有主动调用free释放对应内存,指针指向的内容就一直有效。但需要注意:如果你把栈上创建的Arr结构体的地址存进去,那栈变量离开作用域后地址会失效,必须保证存入Tensor的Arr*指向的也是堆上分配的实例,或者Arr实例的生命周期长于Tensor的生命周期。

修正后的参考实现

张量初始化函数

uint8_t initialAllocTensor(struct Tensor* tensor) {
    tensor->currentSize = 0;
    tensor->maxSize = 2;
    // 分配存储2个Arr*的内存,注意sizeof的参数是struct Arr*
    tensor->arrList = calloc(2, sizeof(struct Arr*));
    if (!tensor->arrList) {
        return 0;
    }
    return 1;
}

张量扩容函数

uint8_t reallocTensor(struct Tensor* tensor) {
    uint16_t resizeTo = tensor->maxSize * 2;
    struct Arr** newList = realloc(tensor->arrList, resizeTo * sizeof(struct Arr*));
    if (!newList) {
        return 0;
    }
    tensor->arrList = newList;
    // 新扩容的位置初始化为NULL,避免野指针
    for (uint16_t x = tensor->currentSize; x < resizeTo; ++x) {
        tensor->arrList[x] = NULL;
    }
    tensor->maxSize = resizeTo;
    return 1;
}

向张量添加Arr的函数

void addToTensor(struct Tensor* tensor, struct Arr* arr) {
    if (tensor->currentSize == tensor->maxSize) {
        if (!reallocTensor(tensor)) {
            exit(1);
        }
    }
    // 直接存入指针,不需要拷贝数据
    tensor->arrList[tensor->currentSize] = arr;
    ++tensor->currentSize;
}

访问示例

// 读取第i个矩阵的第j个字符串
char* str = tensor.arrList[i]->cArr[j];

注意事项

  • 你之前写的initialAllocTensor实现里引用了未定义的arr变量,逻辑是错误的,Tensor初始化阶段不需要操作任何Arr实例的内部成员,只需要分配好存储指针的数组即可。
  • 你原有addToArr里的strncpy用法有问题,没有给字符串末尾补'\0',会导致字符串越界读取,建议改成strncpy(arr->cArr[arr->currentSize], element, 599); arr->cArr[arr->currentSize][599] = '\0';,因为你每个字符串块分配了600字节,最多存599个有效字符加结束符。
  • 释放内存的时候需要先遍历释放每个Arr实例内部的字符串数组和cArr本身,再释放Tensor的arrList,避免内存泄漏。
  • 不要在初始化Tensor的时候提前给Arr的内部字符串数组分配内存,等你实际创建Arr实例的时候用原来写的initialAlloc分配即可,Tensor只负责存指针。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:24:19