C语言中的柔性数组

今天浏览酷壳上一篇文章http://coolshell.cn/articles/11377.html时,发现了有关“零长度的数组”的一些知识,其实之前在论坛中也见过这种用法,但是当时对此不太理解,时间一长就慢慢淡忘了该知识点。于是今天特意查了资料,总算弄清“零长度的数组”即柔性数组这一知识点,现在记录如下。


零长度的数组一般见于结构体中,而直接声明零长度数组,例如,

char str[0];
是无法编译通过的。而网上说零长度的数组一般是放在结构体的最后一个成员的位置处,但是我试了下,放在中间也是可以的。

先说说放在最后位置处的情况:

结构体声明如下:

struct str
{
	int len;
	int b;
	char s[0];
};
注意这里可能也无法编译通过(C99编译失败,C11编译成功),没关系,改为char s[];这样就可以了。这里的char s[0]指的是一个变长数组,也相当于指针吧,不过跟指针却有本质的区别,如果声明成指针,那么指针指向的内存空间可能跟成员b的空间不连续,而声明成char s[0]则是连续的。

这里你可能对结构体struct str的大小不太明确,到底是是多少呢?经过测试发现是8,即sizeof(int) + sizeof(int),也就是说s指向的空间不属于结构体str,这块空间紧跟着结构体str所代表的空间。

上文指出char s[0]指向的空间紧跟着结构体所代表的空间,因此对于一个struct str *型的指针变量申请内存有如下方法:

s = (struct str *)malloc(sizeof(struct str) + 10);
表示给成员s申请了10个字节的空间。
下面看一个例子:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct str
{
	int len;
	int b;
	char s[0];
};


int main(int argc, char *argv[])
{
	struct str *s = NULL;
	
	printf("sizeof(struct str) = %d\n", sizeof(struct str));
	
	s = (str *)malloc(sizeof(struct str) + 10);
	s->len = 100;
	s->b = 50;
	
	strcpy(&s->s[0], "abc");
	puts(s->s);
	
	printf("sizeof(struct str) = %d\n", sizeof(struct str));
	
	printf("addr of len = %p, value of len = %d\n", &s->len, s->len);
	printf("addr of b = %p, value of b = %d\n", &s->b, s->b);
	printf("addr of s = %p, value of s = %s\n", &s->s, s->s);
	
	return 0;
}


执行结果为:

sizeof(struct str) = 8
abc
sizeof(struct str) = 8
addr of len = 0x9831008, value of len = 100
addr of b = 0x983100c, value of b = 50
addr of s = 0x9831010, value of s = abc

可以看出s确实是排在成员b的后面!尽管表面上看s是结构体str的成员,但实际上并不是;这样做的好处就是可以一次性将所需的内存空间申请出来(所以内存是连续的,内存碎片也减少了),因为如果是以指针形式声明的,那么就必须做两次内存申请(结构体一次,成员s一次)。

再看看成员char s[0]放在结构体中间位置处:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct str
{
	int len;
	char s[0];
	int b;
};


int main(int argc, char *argv[])
{
	struct str *s = NULL;
	
	printf("sizeof(struct str) = %d\n", sizeof(struct str));
	
	s = (str *)malloc(sizeof(struct str) + 10);
	s->len = 100;
	s->b = 50;
	
	strcpy(&s->s[0], "abc");
	puts(s->s);
	
	printf("sizeof(struct str) = %d\n", sizeof(struct str));
	
	printf("addr of len = %p, value of len = %d\n", &s->len, s->len);
	printf("addr of s = %p, value of s = %s\n", &s->s, s->s);
	printf("addr of b = %p, value of b = %d\n", &s->b, s->b);
	
	return 0;
}

执行结果为:

sizeof(struct str) = 8
abc
sizeof(struct str) = 8
addr of len = 0x8da6008, value of len = 100
addr of s = 0x8da600c, value of s = abc
addr of b = 0x8da600c, value of b = 6513249

可以清楚的看出s和b的地址是一样的,对s赋值,结果将b的值给覆盖重写了,有点像联合体哈!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值