/*
訪问成员数组名事实上得到的是数组的相对地址。而訪问成员指针事实上是相对地址里的内容
*/
/*关于长度为0的数组,柔性数组意义*/
/*第一个意义是,方便内存释放。假设我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,
并把整个结构体返回给用户。用户调用free能够释放结构体,可是用户并不知道这个结构体内的成员
也须要free。所以你不能指望用户来发现这个事。所以,假设我们把结构体的内存以及其成员要的内存
一次性分配好了,并返回给用户一个结构体指针。用户做一次free就能够把全部的内存也给释放掉。
訪问成员数组名事实上得到的是数组的相对地址。而訪问成员指针事实上是相对地址里的内容
*/
struct buf_str { int length; char buf[0]; }; struct foo { buf_str* pbuf; }; void test_funny() { foo f = {0}; printf("%x ", f.pbuf); printf("%x ", &f.pbuf->length); printf("%x ", &f.pbuf->buf); printf("%x ", f.pbuf->buf); if (f.pbuf->buf) //没有申请内存,可是能够訪问相对地址,*数组名就是相对地址* { //printf(f.pbuf->buf); //crash,等价于printf("%s", f.pbuf->buf);指针的内容 } } struct buf_str1 { int length; char *buf; }; struct foo1 { buf_str1* pbuf; }; void test_funny1() { foo1 f = {0}; printf("%x ", &f.pbuf->length); printf("%x ", &f.pbuf->buf); //指针的相对地址。 和前面的比較。也和以下的比較 printf("%x ", f.pbuf->buf); //指针所指内容的地址,*訪问指针,就是訪问相对地址里面的内容* crash if (f.pbuf->buf) //crash, 訪问内容 { printf(f.pbuf->buf); } }
/*关于长度为0的数组,柔性数组意义*/
/*第一个意义是,方便内存释放。假设我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,
并把整个结构体返回给用户。用户调用free能够释放结构体,可是用户并不知道这个结构体内的成员
也须要free。所以你不能指望用户来发现这个事。所以,假设我们把结构体的内存以及其成员要的内存
一次性分配好了,并返回给用户一个结构体指针。用户做一次free就能够把全部的内存也给释放掉。
(读到这里,你一定会认为C++的封闭中的析构函数会让这事easy和干净非常多)
第二个原因是。这样有利于訪问速度。
连续的内存故意于提高訪问速度,也故意于降低内存碎片。
(事实上。我个人认为也没多高了,反正你跑不了要用做偏移量的加法来寻址)
*/
void test_funny2() { printf("buf_str size : %d ", sizeof(buf_str));//只输出4,零长度的数组是存在于结构体内的。可是不占结构体的size int buf_len = 10; ////////////////////////////////////////////////////////////////////////// //长度为0数组的使用方法 buf_str* pBuf = (buf_str*)malloc(sizeof(buf_str) + sizeof(char)*(buf_len+1));//连续的内存 pBuf->length = buf_len+1; memset(pBuf->buf, 'a', sizeof(char) * buf_len); pBuf->buf[buf_len] = '