《c++深度探索对象模型》 P20:
c++中凡是处于同一个access section(访问区段,也就是private,public这些)中的数据,必定保证以声明顺序出现在内存布局当中。但是多个access section中的各笔数据,排列顺序就不一定了。
对于从c发展来的结构体,除了与类在默认访问权限上不同,内存布局上也存在区别。对于struct,是按照声明顺序来存放数据的。
可以利用这点,完成一个可变长数组,方法如下:
将单一元素的数组放到struct末尾。示例:
// 深度探索c++对象模型_chapter_1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <string>
using namespace std;
namespace StructClassCompare {
//struct 数据成员内存按照声明顺序排列,将单一元素的数组放到struct末尾,即可完成一个可变长数组.
//这样完成一个可变长数组的好处: 内存连续,减少内存碎片
struct mumble{
int a = 0;
char pc[1];//这里如果直接使用指针,那么需要先分配结构体一次,然后再为结构体内指针分配一次内存,
//这样结构体内部的内存就不是连续的了
};
void test( ) {
const char* pstr = "123";
struct mumble* pmumb1 = (struct mumble*) malloc( sizeof(struct mumble) + strlen(pstr) + 1);//+1是因为char* 末尾的结束符
cout << sizeof(struct mumble) << " : " <<strlen(pstr)<< endl;// 8 3
cout << sizeof(pmumb1->a) << " : " << sizeof(pmumb1->pc) << endl;// 4 1
cout << &pmumb1->a << " : " << &pmumb1->pc << endl;//00CAFBB0 : 00CAFBB4内存连续的
strcpy_s(pmumb1->pc, strlen(pstr)+1, pstr);//在拷贝时,pstr大小是超出pmumb1->pc大小的,
//但是并没有超出pmumb1大小,并且由于结构体内存连续,且pc数组位于结构体末尾,因此可以完成拷贝并读取
cout << pmumb1->pc << endl;//输出123
cout << &pmumb1->a << " : " << &pmumb1->pc << endl;//00CAFBB0 : 00CAFBB4
cout << sizeof(pmumb1->a) << " : " << sizeof(pmumb1->pc) << endl;//4 : 1
}
}
int main()
{
StructClassCompare::test();
}
从上面的输出可以看到 拷贝前(strcpy_s(pmumb1->pc, strlen(pstr)+1, pstr);语句前) 输出pumub1->pc大小是1
拷贝后(strcpy_s(pmumb1->pc, strlen(pstr)+1, pstr);语句后) 输出pumub1->pc大小也是1
但是pumub1->pc一样输出了 pstr指向的“123”。
这是因为
1.数组是连续存储的空间,因此读取字符数组只要有首地址即可。因此,这里要做的只是将字符串存储在以pc[0]开头的首地址后续的那片存储空间
2.虽然pmumb1->pc的大小只有1,但是给pmumb1 多分配了strlen(pstr) + 1大小的空间,足够存放pstr指向的“123”,所以空间是足够的。
参考:https://blog.csdn.net/xiongping_/article/details/53579953
https://blog.csdn.net/damotiansheng/article/details/40958299?utm_source=blogxgwz1
https://www.cnblogs.com/cy568searchx/p/3655193.html