变长结构体
1 struct test 2 { 3 int nSize; 4 char data[]; // 或者 char data[0];但建议使用 char data[]; 注意:c98 时不支持柔性数组,其仅作为非标准扩展。到c99时纳入标准 5 };
如上面代码即为一变长结构体,其中 char data[]; 为一变长数组,称之为柔性数组。正是因其为变长数组,故结构体才可变长。使用 test 结构体时,可用 malloc 申请大于 sizeof(test) 长度的空间。如下:
1 const auto nSizeTest = sizeof(test); 2 const auto nExtraSize = 3 * (sizeof(char)); 3 4 test* stpTest = (test*)malloc(nSizeTest + nExtraSize); 5 6 stpTest->nSize = nSizeTest + nExtraSize; 7 memset((void*)stpTest->data, 0x0L, nExtraSize); 8 const auto nTempLen = strlen(stpTest->data); 9 for (auto nIndex = 0; nIndex < nExtraSize - 1; ++nIndex) { 10 stpTest->data[nIndex] = char(96 + nIndex); 11 } 12 stpTest->data[nExtraSize - 1] = ‘\0‘; 13 14 // some code here........ 15 16 free(stpTest); // 此处 free 的是刚才所申请的全部内存空间 17 stpTest = nullptr;
使用柔性数组有以下几个好处:
- 首先柔性数组不占内存,值代表地址;
- 可以通过stpTest->data来访问字符串,符合常规用法。
- 字符串长度为动态分配。
关于柔性数组的注意点:
- 柔性数组只能放置于结构体的末尾声明
- 由于柔性数组是动态可变长的,则一般情况下只会用在没有继承关系、没有虚表的变长结构体(或类中)中,如果有继承关系的或虚表,则后果将非常严重。(有看过对象模型的人,肯定清楚为什么,此处就不多说)
- 上面变长结构体中的柔性数组除了 char 型别外,还可以是其他任何类型,甚至是自定义的类类型。但是:如果是自定义的类类型,则需要自己手动调用构造与析构。因为 malloc 与 free 时,不会自动调用构造与析构。从而可能导致不可预知的结果,以及内存泄漏的可能。比如:
1 class obj 2 { 3 public: 4 int nIndex; 5 ~obj() { 6 std::cout << "obj " << nIndex << " destroy" << std::endl; 7 } 8 }; 9 10 struct test 11 { 12 int nSize; 13 obj data[]; 14 }; 15 16 int _tmain(int argc, _TCHAR* argv[]) 17 { 18 19 const auto nSizeTest = sizeof(test); 20 const auto nExtraSize = 3 * (sizeof(obj)); 21 22 test* stpTest = (test*)malloc(nSizeTest + nExtraSize); 23 24 stpTest->nSize = nSizeTest + nExtraSize; 25 memset((void*)stpTest->data, 0x0L, nExtraSize); 26 for (auto nIndex = 0; nIndex < 3; ++nIndex) { 27 stpTest->data[nIndex].nIndex = nIndex + 1; 28 } 29 30 auto nSize = sizeof(test); 31 std::cout << "sizeof(test) = " << nSize << std::endl; // 此处输出 4.说明柔性数组并不会占用 test 的空间. 32 33 nSize = sizeof(*stpTest); 34 std::cout << "sizeof(*stpTest) = " << nSize << std::endl; // 此处输出 4 35 36 obj* ptr = stpTest->data; 37 38 free(stpTest); // 此处将释放前面所申请的全部空间,但是:不会调用 ~obj() 函数!!! 39 stpTest = nullptr; 40 41 //ptr->nIndex = 777; // 如果调用此句会蹦,因为前面 free 时已经全部释放掉所申请空间了,包括柔性数组 data 的那3个 obj 对象的空间 42 43 system("pause"); 44 45 return 0; 46 }
参考文献:
时间: 2024-10-27 18:24:14