简体   繁体   English

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

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

How does one malloc an array of structs correctly if each struct contains an array of strings which vary in size? 如果每个结构都包含一个大小可变的字符串数组,那么如何正确分配一个结构数组?

So each struct might have a different size and would make it impossible to 因此,每个结构的大小可能都不同,因此无法

realloc(numberOfStructs * sizeof(structName)) realloc(numberOfStructs * sizeof(structName))

after

malloc(initialSize * sizeof(structName) malloc(initialSize * sizeof(structName)

How does one allocate memory for this and keep track of what is going on? 如何为此分配内存并跟踪发生了什么?

If your structure has a char *, it takes up the size of one pointer. 如果您的结构具有char *,则它将占用一个指针的大小。 If it has a char[200], it takes up two hundred bytes. 如果它有一个char [200],它将占用200个字节。

I am making some guesses here, based on the information you have provided. 根据您提供的信息,我在这里做出一些猜测。 The only reason I can see for wanting to realloc an array of structs is if you want to add more structs to that array. 我可以看到想要的唯一原因realloc结构数组是,如果你想要更多的结构添加到该数组。 That's cool. 这很酷。 There are plenty of reasons to want that kind of dynamic storage. 有很多理由想要这种动态存储。 The best way to handle it, especially if the structures are themselves dynamic, is to keep an array of pointers to these structures. 处理它的最佳方法(尤其是在结构本身是动态的情况下)是保留指向这些结构的指针数组。 Example: 例:

1. Data structure: 1.数据结构:

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

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

2. Managing dynamic arrays of strings: 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. Managing a dynamic array of structures: 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. Main program: 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;
}

You don't, generally. 一般来说,您不会。 There are two reasons you might want to do this: 您可能要这样做有两个原因:

  1. So that a single free() will release the entire block of memory. 这样一个free()就会释放整个内存块。
  2. To avoid internal memory fragmentation. 为了避免内部内存碎片。

But unless you have an exceptional situation, neither are very compelling, because there is crippling drawback to this approach: 但是除非您有特殊情况,否则都不是很引人注目,因为此方法存在严重的缺点:

If you do this, then block[i] is meaningless. 如果执行此操作,则block[i]是没有意义的。 You have not allocated an array. 您尚未分配数组。 There is no way to tell where your next struct starts without either examining the struct or having outside information about the size/position of your structs in the block. 如果不检查结构或没有有关块中结构大小/位置的外部信息,就无法说出下一个结构的起始位置。

It is not so clear how your struct type is declared. 还不清楚如何声明您的struct类型。 C99 has a special construct for such things, called flexible array member of a struct : C99有一个特殊的结构,称为struct灵活数组成员:

As a special case, the last element of a structure with more than one named member may have an incomplete array type; 作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; this is called a flexible array member. 这称为灵活数组成员。

You could do something like 你可以做类似的事情

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

You may then allocate such a beast with 然后,您可以分配这样的野兽与

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

and reallocate it with 并用

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

To use this more comfortably you'd probably better wrap this into macros or inline functions. 为了更舒适地使用它,您最好将其包装到宏或内联函数中。

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

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