空数组的使用技巧
数组
数组(Array)是有序的元素序列。一个长度为0的数组我们称之为“空数组”,空数组是一个真正的对象,只是包含元素个数为0。。
空数组
我们可以先做个实验。(本文实验在 64位机测试)
测试空数组
int aa[1];
int bb[0];
printf("aa address %p \r\n",&aa);
printf("aa sizeof %ld \r\n",sizeof(aa));
printf("bb address %p \r\n",&bb);
printf("bb sizeof %ld \r\n",sizeof(bb));
查看输出结果
aa address 0x7ffffef2fe5c
aa sizeof 4
bb address 0x7ffffef2fe58
bb sizeof 0
可得出结论:
- 空数组有地址
- 空数组不占空间
结构体中的空数组
还是先上代码
#include <stdio.h>
struct stu_test1
{
int a;
int b;
};
struct stu_test2
{
int a;
char str[0];
int b;
};
struct stu_test3
{
int a;
char str[1];
int b;
};
struct stu_test4
{
int a;
char *str;
int b;
};
int main()
{
int a;
struct stu_test2 test2;
/*没有空数组*/
a = sizeof(struct stu_test1);
printf("stu_test1 lengh is %d \r\n",a);
/*包含空数组*/
a = sizeof(struct stu_test2);
printf("stu_test2 lengh is %d \r\n",a);
/*数组长度为1*/
a = sizeof(struct stu_test3);
printf("stu_test3 lengh is %d \r\n",a);
/*char类型的指针*/
a = sizeof(struct stu_test4);
printf("stu_test4 lengh is %d \r\n",a);
/*打印结构体的地址*/
printf("test2 a address is %p \r\n",&test2);
printf("test2 char address is %p \r\n",&(test2.str));
printf("test2 b address is %p \r\n",&(test2.b));
return 0;
}
可以看一下测试结果
/*没有空数组*/
stu_test1 lengh is 8
/*包含空数组*/
stu_test2 lengh is 8
/*数组长度为1*/
stu_test3 lengh is 12
/*char类型的指针*/
stu_test4 lengh is 24
/*打印结构体的地址*/
test2 a address is 0x7ffffef2fe60
test2 char address is 0x7ffffef2fe64
test2 b address is 0x7ffffef2fe64
五组测试可得出结论:
- 结构体的大小等于两个
int
类型的大小; - 结构体的大小等于两个
int
类型的大小,空数组不占用结构体大小; - 结构体的大小等于三个
int
类型的大小,编译器优化的结果; - 结构体的大小等于两个
int
类型的大小 加上一个指针的大小; - 空数组的起始地址,是下一个成员的起始地址一致。
空数组的使用
空数组如何使用,我们可以从他的特性出发。
- 不需要初始化,数组名直接就是所在的偏移
- 不占任何空间,指针需要占用int长度空间,空数组不占任何空间。
空数组数组不占用任何内存,可以节省空间;
空数组的内存地址就和他后面的元素的地址相同,所以数组名就是后面元素的地址,直接就能当做指针使用。
这样的写法可以来制作动态缓存区。
所以我们可以这样来使用他:
struct stu_test
{
int a;
int b;
char str[0];
};
malloc(sizeof(struct stu_test)+ buff_len);
buff_len
来指定 str
的长度,就可以直接使用了。
这样就只需要申请一次内存。如果是分两次分配(结构体和缓冲区),那么要是第二次malloc失败了,必须回滚释放第一个分配的结构体。这样带来了编码麻烦。其次,分配了第二个缓冲区以后,如果结构里面用的是指针,还要为这个指针赋值。同样,在free这个buffer的时候,用指针也要两次free。如果用空数组,所有问题一次解决。
另外小内存的管理是非常困难的,如果用指针,这个buffer的struct部分就是小内存了,在系统内存在多了势必严重影响内存管理的性能。要是用空数组把struct和实际数据缓冲区一次分配大块问题,就没有这个问题。
总结
空数组不占用任何空间,需要使用的时候可以在指定长度,这样就实现了动态数组,既不定长数组。