Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1080259
  • 博文数量: 646
  • 博客积分: 288
  • 博客等级: 二等列兵
  • 技术积分: 5375
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-08 14:33
个人简介

为了技术,我不会停下学习的脚步,我相信我还能走二十年。

文章分类

全部博文(646)

文章存档

2014年(8)

2013年(134)

2012年(504)

分类:

2012-07-20 14:05:42

原文地址:指针和空数组 作者:czysocket_dara

  今天在C专家编程上上看到一道题:void (int i[][10]);这样一个函数,参数该传什么去调用他呢?疑惑不解...看了看答案,说可以传个这样样的指针int (*i)[10],一看恍然大悟,如果说把i[]看做是指针,那么他的类型是什么呢?或者说i[]的跨度是多少呢?很明显,是int [10]这种类型的大小字节.记得以前老师说过,参数如果是数组类型,类似于这样 void (int []) 编译器会把他当做指针类型 void (int *),对于一维数组,这个指针的跨度是 地址=地址+sizeof(int) 的偏移.但是,对于多多维数组呢?很明显,传进去的指针是第一维数组首元素的地址,那么对于一维数组类型来说,他的每一个偏移都是在他往后的多维数组的维数乘积乘以sizeof(类型)字节大小.
  这让我联想到了汇编,例如一个 int i[10]; 访问i[5]<=>dword ptr i[5*sizeof(int)];  如果是多维呢?
int i[10][20][30]; i[5]<=>dword ptr i[5*20*30*sizeof(int)] .可见,他的每一维的首元素取地址后转成的指针,是指向他后面的多维数组的维数乘积乘以类型的大小跨度的数组指针类型.所以上面int i[][10]隐式地转换成int (*i)[10],原因是两种方式的i++之后的值都相等.同时也加深一点记性:不管有多少维数组,在内存中只有一维!
 
同时也在网上找了写指针和空数组用途的一点资料,引用一下:
 
下面是C99标准中的一段原文:
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. With two exceptions, the flexible array member is ignored. First, the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length. Second, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer.

C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中 包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且 分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

注意:在C99标准面试之前,柔性数组可以使用零数组充当,但是C99之后,准确地说使用零数组是非法的,应该使用空数组来代替。
在底层代码中,经常有如下写法:
这是个广泛使用的常见技巧,常用来构成缓冲区。比起指针,用空数组有这样的优势:
1 不需要初始化,数组名直接就是所在的偏移;
2 不占任何空间,指针需要占用int长度空间,空数组不占任何空间。
“这个数组不占用任何内存”,意味着这样的结构节省空间;“该数组的内存地址就和他后面的元素的地址相同”,意味着无需初始化,数组名就是后面元素的地址,直接就能当做指针使用。
这样的写法最适合制作动态buffer。因为可以这样分配空间:
malloc(sizeof(struct XXX)+ buff_len);
看出来好处没有?直接就把buffer的结构体和缓冲区一块分配了。用起来也非常方便,因为现在空数组其实变成了buff_len长度的数组了。
这样的好处是:一次内存分配解决问题,方便内存管理。大家知道为了防止内存泄漏,如果是分两次分配(结构体和缓冲区),那么要是第二次malloc失败了,必须回滚释放第一个分配的结构体。这样带来了编码麻烦。其次,分配了第二个缓冲区以后,如果结构里面用的是指针,还要为这个指针赋值。同样,在free这个buffer的时候,用指针也要两次free。如果用空数组,所有问题一次解决。其次,大家知道小内存的管理是非常困难的,如果用指针,这个buffer的struct部分就是小内存了,在系统内存在多了势必严重影响内存管理的性能。要是用空数组把struct和实际数据缓冲区一次分配大块问题,就没有这个问题。如此看来,用空数组既简化编码,又解决了小内存碎片问题提高了性能。
 
阅读(394) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~