繁体   English   中英

具有可变大小结构的结构数组的malloc()

[英]malloc() of struct array with varying size structs

如果每个结构都包含一个大小可变的字符串数组,那么如何正确分配一个结构数组?

因此,每个结构的大小可能都不同,因此无法

realloc(numberOfStructs * sizeof(structName))

malloc(initialSize * sizeof(structName)

如何为此分配内存并跟踪发生了什么?

如果您的结构具有char *,则它将占用一个指针的大小。 如果它有一个char [200],它将占用200个字节。

根据您提供的信息,我在这里做出一些猜测。 我可以看到想要的唯一原因realloc结构数组是,如果你想要更多的结构添加到该数组。 这很酷。 有很多理由想要这种动态存储。 处理它的最佳方法(尤其是在结构本身是动态的情况下)是保留指向这些结构的指针数组。 例:

1.数据结构:

typedef struct {
    int numberOfStrings;
    char ** strings;
}
stringHolder;

typedef struct {
    int numberOfStructs;
    stringHolder ** structs;
}
structList;

2.管理字符串的动态数组:

void createNewStringHolder(stringHolder ** holder) {
    (*holder) = malloc(sizeof(stringHolder));
    (*holder)->numberOfStrings = 0;
    (*holder)->strings = NULL;
}

void destroyStringHolder(stringHolder ** holder) {
    // first, free each individual string
    int stringIndex;
    for (stringIndex = 0; stringIndex < (*holder)->numberOfStrings; stringIndex++)
    { free((*holder)->strings[stringIndex]); }
    // next, free the strings[] array
    free((*holder)->strings);
    // finally, free the holder itself
    free((*holder));
}

void addStringToHolder(stringHolder * holder, const char * string) {
    int newStringCount = holder->numberOfStrings + 1;
    char ** newStrings = realloc(holder->strings, newStringCount * sizeof(char *));
    if (newStrings != NULL) {
        holder->numberOfStrings = newStringCount;
        holder->strings = newStrings;
        newStrings[newStringCount - 1] = malloc((strlen(string) + 1) * sizeof(char));
        strcpy(newStrings[newStringCount - 1], string);
    }
}

3.管理动态结构数组:

void createNewStructList(structList ** list, int initialSize) {
    // create a new list
    (*list) = malloc(sizeof(structList));
    // create a new list of struct pointers
    (*list)->numberOfStructs = initialSize;
    (*list)->structs = malloc(initialSize * sizeof(stringHolder *));
    // initialize new structs
    int structIndex;
    for (structIndex = 0; structIndex < initialSize; structIndex++)
    { createNewStringHolder(&((*list)->structs[structIndex])); }
}

void destroyStructList(structList ** list) {
    // destroy each struct in the list
    int structIndex;
    for (structIndex = 0; structIndex < (*list)->numberOfStructs; structIndex++)
    { destroyStringHolder(&((*list)->structs[structIndex])); }
    // destroy the list itself
    free((*list));
}

stringHolder * addNewStructToList(structList * list) {
    int newStructCount = list->numberOfStructs + 1;
    size_t newSize = newStructCount * sizeof(stringHolder *);
    stringHolder ** newList = realloc(list->structs, newSize);
    if (newList != NULL) {
        list->numberOfStructs = newStructCount;
        list->structs = newList;
        createNewStringHolder(&(newList[newStructCount - 1]));
        return newList[newStructCount - 1];
    }
    return NULL;
}

4.主程序:

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

int main (int argc, char * argv[]) {
    structList * allHolders;
    createNewStructList(&allHolders, 10);

    addStringToHolder(allHolders->structs[4], "The wind took it");
    addStringToHolder(allHolders->structs[4], "Am I not merciful?");
    addStringToHolder(allHolders->structs[7], "Aziz, Light!");

    printf("%s\n", allHolders->structs[4]->strings[0]);  // The wind took it
    printf("%s\n", allHolders->structs[4]->strings[1]);  // Am I not merciful?
    printf("%s\n", allHolders->structs[7]->strings[0]);  // Aziz, Light!

    stringHolder * newHolder = addNewStructToList(allHolders);
    addStringToHolder(newHolder, "You shall not pass!");
    printf("%s\n", newHolder->strings[0]);               // You shall not pass!
    printf("%s\n", allHolders->structs[10]->strings[0]); // You shall not pass!

    destroyStructList(&allHolders);
    return 0;
}

一般来说,您不会。 您可能要这样做有两个原因:

  1. 这样一个free()就会释放整个内存块。
  2. 为了避免内部内存碎片。

但是除非您有特殊情况,否则都不是很引人注目,因为此方法存在严重的缺点:

如果执行此操作,则block[i]是没有意义的。 您尚未分配数组。 如果不检查结构或没有有关块中结构大小/位置的外部信息,就无法说出下一个结构的起始位置。

还不清楚如何声明您的struct类型。 C99有一个特殊的结构,称为struct灵活数组成员:

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这称为灵活数组成员。

你可以做类似的事情

typedef struct myString myString;
struct myString { size_t len; char c[]; };

然后,您可以分配这样的野兽与

size_t x = 35;
myString* s = malloc(sizeof(myString) + x);
s->len = x;

并用

size_t y = 350;
{
  myString* tmp = realloc(s, sizeof(myString) + y);
  if (!tmp) abort(); // or whatever
  tmp->len = y;
}
s = tmp;

为了更舒适地使用它,您最好将其包装到宏或内联函数中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM