各構造体にサイズが異なる文字列の配列が含まれている場合、構造体の配列を正しくmallocするにはどうすればよいですか?
したがって、各構造体のサイズが異なる可能性があり、
realloc(numberOfStructs * sizeof(structName))
後
malloc(initialSize * sizeof(structName)
これにメモリを割り当て、何が起こっているかを追跡するにはどうすればよいですか?
構造体にchar*がある場合、1つのポインターのサイズを占めます。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;
}
一般的にはそうしません。これを実行する理由は2つあります。
free()
でメモリのブロック全体が解放されるようにします。ただし、例外的な状況がない限り、どちらも非常に説得力がありません。これは、このアプローチには重大な欠点があるためです。
これを行うと、block[i]
意味がありません。アレイを割り当てていません。構造体を調べるか、ブロック内の構造体のサイズ/位置に関する外部情報がなければ、次の構造体がどこから始まるかを知る方法はありません。
struct
タイプがどのように宣言されているかはそれほど明確ではありません。struct
C99には、そのようなもののための特別な構造があります。これは、 :の柔軟な配列メンバーと呼ばれます。
特殊なケースとして、複数の名前付きメンバーを持つ構造体の最後の要素は、不完全な配列型を持つ場合があります。これは、柔軟な配列メンバーと呼ばれます。
あなたは次のようなことをすることができます
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;
これをより快適に使用するには、おそらくこれをマクロまたはインライン関数にラップする方がよいでしょう。