可変長となるのは,gTest[*].testSmall と gTest[*].testChar 用の
配列ですから,これらをまとめて確保した後,各 gTest[*].testSmall と
gTest[*].testChar に配分すればいいことになります.
gTest[i].testSmall の要素数が質問に明記されていないので,
とりあえず gSmallCount[i] としておきます.
また,↓の「配列数」というのは testSmall と同じ要素数という意味でしょうか?
> char *testChar; // SIZE_A分の領域*配列数
確信が持てないので,一般性を持たせて gCharCount[i] としておきます.
gSmallCount[*] の合計を totalSmallCount,gCharCount[*] の合計を
totalCharCount とすると,確保すべきメモリ領域は次のような構造体に相当します.
typedef char testCharT[SIZE_A];
struct VariableStruct {
testSmallStructT testSmall[totalSmallCount];
testCharT testChar[totalCharCount];
};
(totalSmallCount と totalCharCount は変数なので,
上記のような構造体宣言をソースとして書くことはできません.
これと同じ構造のメモリ領域を確保する,という話です.)
VariableStruct を確保・解放するコードは次のようになります.
(インデントが潰れるのを防ぐため,半角空白を全角空白に置換しています.)
//--------------------------------------------------------------------------
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define OK 0
#define FAIL (-1)
#define NTESTS 10 // gTest[] の要素数
#define SIZE_A 5
typedef char testCharT[SIZE_A];
// 7バイト構造体
typedef struct {
char str1[3];
char str2[4];
} testSmallStructT;
// 親構造体
typedef struct {
int testInt;
testSmallStructT *testSmall; // 配列要素数:gSmallCount[i]
testCharT *testChar; // 配列要素数:gCharCount[i]
} testBigStructT;
// 大域変数 ----------------------------------------------------------------
testBigStructT gTest[NTESTS];
testSmallStructT *gVariableStruct = NULL; // VariableStruct を指すポインタ
// gSmallCount[i] は gTest[i].testSmall[] の要素数に初期化されているものとする.
unsigned gSmallCount[NTESTS];
// gCharCount[i] は gTest[i].testChar[] の要素数 に初期化されているものとする.
unsigned gCharCount[NTESTS];
/*--------------------------------------------------------------------------
機能 :VariableStruct を確保し,各 gTest[*].testSmall および
gTest[*].testChar に配分する.
戻り値:成功ならば OK,失敗ならば FAIL.
--------------------------------------------------------------------------*/
int VariableStructAlloc(void)
{
unsigned totalSmallCount = 0; // gSmallCount[*] の合計
unsigned totalCharCount = 0; // gCharCount[*] の合計
unsigned i;
size_t size;
// totalSmallCount および totalCharCount を求める.
for(i = 0; i < NTESTS; i++) {
totalSmallCount += gSmallCount[i];
totalCharCount += gCharCount[i];
}
{ // VariableStruct のサイズ size を計算する.
size = sizeof(testSmallStructT) * totalSmallCount;
// 注意:VariableStruct::testChar[*] は char 型の配列なので今回は不要だが,
// [unsigned] char 型 (の配列) 以外の場合はここで size のアラインメント
// 調整が必要になる.
// shinemik さんが初心者ということなので,ここではこれ以上深入りは
// しませんが,[unsigned] char 型以外で同様のことをしたい場合は
// アラインメントについて勉強してください.
// (でも,その前にポインタと malloc/free をちゃんと使えるように
// ならなきゃ.#1 さんのおっしゃるように,free(gTest) なんて
// やってちゃだめですよ~.(笑))
size += sizeof(testCharT) * totalCharCount;
}
// VariableStruct を確保する.
if((gVariableStruct = malloc(size)) == NULL) return FAIL;
{ // VariableStruct を各 gTest[*].testSmall
// および gTest[*].testChar に配分する.
testSmallStructT *p = gVariableStruct;
testCharT *q = (testCharT*)&gVariableStruct[totalSmallCount];
for(i = 0; i < NTESTS; i++) {
gTest[i].testSmall = p;
gTest[i].testChar = q;
p += gSmallCount[i];
q += gCharCount[i];
}
assert(p == &gVariableStruct[totalSmallCount]);
assert((char*)q == (char*)gVariableStruct + size);
}
return OK;
}
/*--------------------------------------------------------------------------
機能 :確保していた VariableStruct を解放する.
--------------------------------------------------------------------------*/
void VariableStructFree(void)
{
if(gVariableStruct != NULL) {
free(gVariableStruct);
gVariableStruct = NULL;
}
}
/*--------------------------------------------------------------------------
テスト用 main()
--------------------------------------------------------------------------*/
int main(void)
{
unsigned i, j, k;
int c;
// gSmallCount[] と gCharCount[] をテキトーに初期化する.
for(i = 0; i < NTESTS; i++) {
gSmallCount[i] = i + 1;
gCharCount[i] = 2 * (i + 1);
}
// メモリを確保する.
if(VariableStructAlloc() == FAIL) {
fprintf(stderr, "Error: %s\n", strerror(errno));
return EXIT_FAILURE;
}
// 文字列を設定する.
for(i = 0; i < NTESTS; i++) {
k = i % 10;
for(j = 0; j < gSmallCount[i]; j++) {
c = j % 26;
sprintf(gTest[i].testSmall[j].str1, "%u%c", k, 'A' + c);
sprintf(gTest[i].testSmall[j].str2, "%u%c%c", k, 'a' + c, 'a' + c);
}
for(j = 0; j < gCharCount[i]; j++) {
sprintf(gTest[i].testChar[j], "%u-%02u", k, j % 100);
}
}
// 設定した文字列を表示する.
for(i = 0; i < NTESTS; i++) {
for(j = 0; j < gSmallCount[i]; j++)
printf("gTest[%u].testSmall[%u]: str1=\"%s\" str2=\"%s\"\n",
i, j, gTest[i].testSmall[j].str1, gTest[i].testSmall[j].str2);
}
for(i = 0; i < NTESTS; i++) {
for(j = 0; j < gCharCount[i]; j++)
printf("gTest[%u].testChar[%u]: \"%s\"\n", i, j, gTest[i].testChar[j]);
}
// メモリを解放する.
VariableStructFree();
return EXIT_SUCCESS;
}