结构数据中char[1]的妙用和疑惑#includeiostream#includestdlib.h#includestring.husing namespace
结构数据中char[1]的妙用和疑惑
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
union testObj
{
testObj *next;
char data_client[1];
//char data_client[0];
};
int main(void)
{
char *a = (char*)malloc(16);
memset(a,'\0',16);
cout<<"testObj size:"<<sizeof(testObj)<<endl;
strncpy(a,"1,2,3,4,5,6,7,8",15);
testObj *myObj1 = (testObj*)a;
testObj *myObj2 = (testObj*)(a + 3);
cout<<"data_client:"<<myObj1->data_client<<endl;
/*此处就相当于把a全都给free掉聊*/
free(myObj1);
cout<<"after free myObj1 a:"<<a<<endl;
cout<<"data_client:"<<myObj2->data_client<<endl;
return 1;
}
如上面的例子,myObj1指向a(这是妙用),myObj2指向a+3,如果把myObj1 free掉,那么myObj2指向的就是一块已经free掉的内存,这明显不是想要的结果,怎么才能使myObj1,myObj2分别管理自己所指向的内存,而不影响别人?(这是疑惑)
[解决办法]这只是特定场合下的特定优化技巧,不能扩大到一般情况下使用.
在(SGI)STL中,这么做是为了在不浪费额外空间的情况下管理空闲的内存.SGI内部维护16个free-lists,分别管理8, 16, 24, ..., 128 bytes的小额区块.对于N bytes的free-list而言,每一小块的大小为N个字节.现在是从这N个字节中将前面一个指针大小的空间拿出来,当作一个指针来看待,用于构成一个空闲区块的单向链表.
例如,一块内存被分为10个小块,其中有几块被使用了,有几块没有被使用,[7]是这个单向链表的头结点:
[0] // 全是用户数据
[1] // 空闲,指向下一个空闲区域[9],其开头处一个指针大小的内存中存储的是[9]的地址
[2] // 全是用户数据
[3] // 全是用户数据
[4] // 空闲,指向下一个空闲区域[1],其开头处一个指针大小的内存中存储的是[1]的地址
[5] // 全是用户数据
[6] // 全是用户数据
[7] // 空闲,指向下一个空闲区域[4],其开头处一个指针大小的内存中存储的是[4]的地址
[8] // 全是用户数据
[9] // 空闲,没有后续的空闲区域了,其开头处一个指针大小的内存中存储的是NULL
链接关系是:[7]->[4]->[1]->[9]->NULL
未分配的区块,N个bytes都是空着的,不用白不用.至于那些被分配出去的内存,N个字节都是被用户使用的,彼此之间没有关联,只是在回收的时候,将其加入到单向链表中.加入链表的时候,区块头部部分才被改为指针的值.在这种使用场景下,绝对不会也不应该存在多个指针指向同一块内存区域的情况.
至于union中的那个data_client,没什么作用,只是提示代码的阅读者,我这个testObj真实占据着一定的内存区间.数组长度1也是有讲究的,其他长度要么不合法(如0),要么不合理(>=2).
[解决办法]控制麻烦
倒是方便
玩得不好死得很惨
[解决办法]语法不是这样。
ISO C有,ISO C++不支持。