具有不同大小结构的结构数组的 malloc()

发布于 2024-10-17 04:28:12 字数 280 浏览 7 评论 0原文

如果每个结构都包含一个大小不同的字符串数组,那么如何正确地 malloc 一个结构数组?

因此每个结构可能有不同的大小,并且不可能

realloc(numberOfStructs * sizeof(structName))

之后

malloc(initialSize * sizeof(structName)

如何为此分配内存并跟踪正在发生的情况?

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))

after

malloc(initialSize * sizeof(structName)

How does one allocate memory for this and keep track of what is going on?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浅浅 2024-10-24 04:28:12

如果你的结构体有一个 char *,它会占用一个指针的大小。如果它有一个char[200],它就占用两百个字节。

If your structure has a char *, it takes up the size of one pointer. If it has a char[200], it takes up two hundred bytes.

吲‖鸣 2024-10-24 04:28:12

我根据您提供的信息在这里做出一些猜测。我认为想要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;
}

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. 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:

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

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

2. Managing dynamic arrays of strings:

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:

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:

#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;
}
苍暮颜 2024-10-24 04:28:12

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

  1. 以便单个 free() 将释放整个内存块。
  2. 以避免内存碎片。

但除非您遇到特殊情况,否则两者都不是非常引人注目,因为这种方法存在严重缺陷:

如果您这样做,那么 block[i] 就没有意义。您还没有分配数组。如果不检查结构或不了解有关块中结构的大小/位置的外部信息,就无法知道下一个结构从哪里开始。

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.
  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. 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.

安人多梦 2024-10-24 04:28:12

目前尚不清楚您的 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;

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

It is not so clear how your struct type is declared. C99 has a special construct for such things, called flexible array member of a 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文