C语言柔性数组讲解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C语⾔柔性数组讲解
#include<stdio.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
int len = 10;
printf("The struct's size is %d\n",sizeof(SoftArray));
}
我们可以看出,_SoftArray结构体的⼤⼩是4,显然,在32位操作系统下⼀个int型变量⼤⼩刚好为4,也就说结构体中的数组没有占⽤内存。
为什么会没有占⽤内
存,我们平时⽤数组时不时都要明确指明数组⼤⼩的吗?但这⾥却可以编译通过呢?这就是我们常说的动态数组,也就是柔性数组。
先不要乱,让我们再看⼀段代码
#include<stdio.h>
#include<malloc.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
int len = 10;
SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray) + sizeof(int)*len);
printf("After the malloc function the struct's size is %d\n”,sizeof(SoftArray));
return0;
}
是不是有点奇怪,为什么申请了内存后结构体⼤⼩还是4呢?原因是动态申请的内存只是申请给数组拓展所⽤,从上个程序我们可以看出结构体的⼤⼩在创建时已经
确定了,array明确来说不算是结构体成员,只是挂⽺头卖狗⾁⽽已。
下⾯我们来看看关于柔性数组的资料:
1、什么是柔性数组?
柔性数组既数组⼤⼩待定的数组, C语⾔中结构体的最后⼀个元素可以是⼤⼩未知的数组,也就是所谓的0长度,所以我们可以⽤结构体来创建柔性数组。
2、柔性数组有什么⽤途?
它的主要⽤途是为了满⾜需要变长度的结构体,为了解决使⽤数组时内存的冗余和数组的越界问题。
3、⽤法:在⼀个结构体的最后,申明⼀个长度为空的数组,就可以使得这个结构体是可变长的。
对于编译器来说,此时长度为0的数组并
不占⽤空间,因为数组名
本⾝不占空间,它只是⼀个偏移量,数组名这个符号本⾝代表了⼀个不可修改的地址常量(注意:数组名永远都不会是指针!),但对于这个数组的⼤⼩,我们
可以进⾏动态分配,对于编译器⽽⾔,数组名仅仅是⼀个符号,它不会占⽤任何空间,它在结构体中,只是代表了⼀个偏移量,代表⼀个不可修改的地址常量!
对于柔性数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:
typedef struct _SoftArray
{
Int len;
int array[];
}SoftArray;
这样的变长数组常⽤于⽹络通信中构造不定长数据包,不会浪费空间浪费⽹络流量,⽐如我要发送1024字节的数据,如果⽤定长包,假设定长包的长度为2048,就
会浪费1024个字节的空间,也会造成不必要的流量浪费。
4、举个简单是实例
#include<stdio.h>
#include<malloc.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
int len=10,i=0;
SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);
p->len=len;
for(i=0;i<p->len;i++)
{
p->array[i]=i+1;
}
for(i=0;i<p->len;i++)
{
printf("%d\n",p->array[i]);
}
free(p);
return0;
}
这代码的作⽤是⽤柔性数组动态创建数组并输出数组内容,这⾥我就直接解释解释这两句代码
SoftArray* p = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) *10);
p->len = 10;
第⼀句,主要是根据你要定义的数组长度和数据类型以及柔性数组本⾝的⼤⼩来开辟⼀块内存空间给柔性数组,第⼆个是定义len的长度,便于确定循环打印输出
是循环的次数。
5、运⾏错误的解决
#include<stdio.h>
#include<malloc.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
int len=10,i=0;
SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);
p->len=len;
for(i=0;i<11;i++)
{
p->array[i]=i+1;
}
for(i=0;i<11;i++)
{
printf("%d\n",p->array[i]);
}
free(p);
return0;
}
所谓初⽣⽜犊不怕死,我在写柔性数组程序时,为了做了个⼤胆的尝试,那就是我在上⼀个代码中申请内存时申请了10,但赋值时我把⼤⼩写了11,问题出现了,
话不多说,直接上图
我当时不知道是什么问题,我也蒙了~---~
但我⼜做出了⼀个伟⼤的决定,我把free(p)注释掉了,结果11成功打印出来了。
我当时真是One Face mengbi。
后来才发现其实是因为在动态分配内存的时候往往分配的是⼀个连续的地址,这⼀点从可以使⽤*[a+3]来取值就能够知道。
因此,在动态分配的时候,会在数组界限外加⼀个⽤来标识数组范围的标志,例如a数组,就会在array[-1]和array[11]有两个标志,如果我们在这两个位置赋值,赋
值和调⽤时并不会出错,⽽是在freed掉array申请的内存时出错,错误的名称就是“DAMAGE: before Normal block”和“DAMAGE: after
Normal block”。
⼀般是后者居多。
因此,当你遇见这个错误的时候,记得去检查⼀下⾃⼰数组的赋值吧。
6、注意说明
在定义这个结构体的时候,模⼦的⼤⼩就C89不⽀持这种东西,C99把它作为⼀种特例加⼊了标准。
但是,C99所⽀持的是 incomplete type,⽽不是 zero array,形同 int item[0];这种形式是⾮法的,C99⽀持的形式是形同 int item[];只不过有些编译器把 int item[0];作
为⾮标准扩展来⽀持,⽽且在C99发布之前已经有了这种⾮标准扩展了,C99发布之后,有些编译器把两者合⽽为⼀了。
当然,上⾯既然⽤malloc函数分配了内存,
肯定就需要⽤ free函数来释放内存:free(p);这两个函数是⼀对CP,就好像fopen()和fclose();记住不要乱拆CP,拆CP是有风险的哦。
最后再送⼤家⼀个代码玩玩:
1 #include<stdio.h>
2 #include<malloc.h>
3 typedef struct _SoftArray{
4int len;
5int array[];
6 }SoftArray;
7
8//打印输出斐波那契数列
9void printfln(SoftArray *p,int len)
10 {
11int i;
12
13for(i=0;i<len;i++) //循环进⾏打印输出
14 {
15 printf("%d\n",p->array[i]);
16 }
17 }
18
19//动态⽣成斐波那契数列
20void create(int len)
21 {
22int i;
23
24 SoftArray * p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len); //声明结构体指针p,动态申请内存,⼤⼩为结构体⼤⼩+10个int型⼤⼩
25
26for(i=0;i<len;i++) //循环进⾏数组赋值
27 {
28if( i <= 1 )
29 {
30 p->array[i] = 1;
31 }else if( i >= 2 )
32 {
33 p->array[i] = p->array[i-1] + p->array[i-2];
34 }else
35 {
36 printf("DAMAGE: before Normal block or after Normal block");
37return (-1);
38 }
39
40 }
41 printfln(p,len);
42
43free(p);
44 }
45
46//主函数
47int main()
48 {
49int i=0;
50int len;
51
52 printf("请输⼊⽣成斐波那契数列的⾏数:");
53 scanf("%d",&len);
54
55 create(len);
56
57return0;
58 }。