设为首页 加入收藏

TOP

C语言中变长数组引发的思考
2014-11-24 11:27:58 来源: 作者: 【 】 浏览:0
Tags:言中 引发 思考

看到老师写的一个结构体很好奇,结构体的最后是一个长度为0的数组,当时感觉老师是不是写错了,这样写意义何在呢?都没有分配空间,貌似没有存在的意义。


后来网上查了一下,其实这是在很多高级的东东里面都用到的东西,linux kernel, MFC, openoffice, 估计更多的地方都用到了。


先说说我的理解:


struct example{
__u16 tag_type;
__u16 tag_len;
char tag_data[0];
} __attribute ((packed));



1. 存在的意义:当结构体的长度变长时,例如里面有一个字符串时,为了方便管理内存。


这个结构体不要用struct example a的方式定义, 而应用struct example *a; a = (struct example *)malloc(sizeof(struct example) + extrasize);的形式。extrasize是想额外申请的空间,就是字符串的长度。


2. 如何使用里面的数据?


前面的数据项不用说了,后面的tag_data直接就是我们申请的额外的地址的开始地址。所以,很好用


3. 如何释放申请的地址空间?


直接free(a)就好。有些人可能认为后面的空间没有释放,其实不然。因为malloc申请的空间系统是需要进行管理的,你申请了多少,当你释放的时候,就释放多少。并不是根据你的数据类型来的,否则你说 char *p; p = malloc(20); 然后free(p);系统该释放多少空间呢。 至于系统如何管理的,貌似是通过一个链表进行的,记不清了。


4. 附1


为了解决这个疑惑,后来看了几篇文章,感谢他们。


后来就是人提到过有些编译器不支持0长数组,那怎么办呢 很简单,将数组长度定为1即可,这样仅仅浪费一个字节的空间(字节对齐的话另当别论)。这样做还有另外一个好处就是不用记录这个字符串的长度, 因为本来就存了一个字节的空间,可用这一个字节的空间来标识这个字符串是否为空。


5.附2


有人可能会问,为什么最后一个数据项不设置成一个指针呢?char tag_data[0]; 和char *tag_data;有什么区别呢?


第一个问题:最好不要设置成指针,因为这样的话,你得为tag_data指针重新申请空间,申请的空间还不连续;其次,释放的时候很麻烦,必须先释放内部的指针,但是这个往往是人最容易忽略而造成内存呢泄露的原因。


第二个问题:这个问题貌似问的很傻,因为这是两种不同类型的数据,占据的地址大小都不同。其实不然,这个问题设计到指针和数组的区别问题。


指针和数组很多人都把他们之间画成等号了,这是个错误,希望各位不要犯。他们俩只有在作为函数参数的时候才是真正的一摸一样,都是指针变量,其他情况都不一样。最大的区别:数组是直接寻址的,指针是间接寻址的。array[0]中, array 是一个常量,等于&(a[0]); 而指针变量是一个变量。像array = a就不允许赋值(常量怎么可能作为赋值运算符的左操作数呢?),a = array就是允许的。


6.最后


这个东西用在内存池的管理中用得很多。内存池,这个东西,说起来很吓唬人,其实就是那么回事。一个程序或者动态库维护的一个全局的数组而已,无它。比如说一个c/s架构的服务器,客户端调用一个预先编好的动态库中的函数,一般来说不会没发一个请求网络就帮你投递过去,那样数据太小了。一般都是在动态库中维护一个数组,把请求往里面填,填到满的时候发送出去;或者用户强行要求发送出去。


这个就跟标准i/o库很像了,其实里面也是一段缓存,通过这个缓存使得内存和外存的数据交换不是那么频繁,提高了效率。用户也可以使用fflush()函数强行写到外存。原理都是类似的。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言中通过函数指针实现函数重载 下一篇Python dict 获取 value 方法之比..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·C 内存管理 | 菜鸟教 (2025-12-26 20:20:37)
·如何在 C 语言函数中 (2025-12-26 20:20:34)
·国际音标 [ç] (2025-12-26 20:20:31)
·微服务 Spring Boot (2025-12-26 18:20:10)
·如何调整 Redis 内存 (2025-12-26 18:20:07)