C语言柔性数组和动态数组
【前言】经常看到C语言里的两个数组,总结一下。
一、柔性数组
参考:https://www.cnblogs.com/veis/p/7073076.html
#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,也就说结构体中的数组没有占用内存。为什么会没有占用内存,我们平时用数组时不时都要明确指明数组大小的吗?但这里却可以编译通过呢?这就是我们常说的动态数组,也就是柔性数组。
1、什么是柔性数组?
柔性数组既数组大小待定的数组。C语言中结构体的最后一个元素可以是大小未知的数组,也就是所谓的0长度,所以我们可以用结构体来创建柔性数组。
2、柔性数组有什么用途 ?
它的主要用途是为了满足需要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。
3、用法 :
在一个结构体的最后 ,申明一个长度为空的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,我们可以进行动态分配,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!
对于柔性数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:
typedef struct _SoftArray
{
Int len;
int array[];
}SoftArray;
这样的变长数组常用于网络通信中构造不定长数据包,不会浪费空间浪费网络流量,比如我要发送1024字节的数据,如果用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会造成不必要的流量浪费。
4、举例
#include<stdio.h> #include<malloc.h>
//其中有两个成员:一个是len,代表数组的长度;一个是array[],代码数组的内容 typedef struct _SoftArray{ int len; int array[]; }SoftArray; int main() { int len=10,i=0; //分配空间的格式。此时softarray大小仍然为4 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); return 0; }
这代码的作用是用柔性数组动态创建数组并输出数组内容,这里我就直接解释解释这两句代码:
SoftArray* p = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) *10); p->len = 10;
第一句,主要是根据你要定义的数组长度和数据类型以及柔性数组本身的大小来开辟一块内存空间给柔性数组p,第二个是定义len的长度,便于确定循环打印输出是循环的次数。
5、柔性数组在“不确定数组大小”中的应用
对不确定len值大小的数组,使用了数组的方法。若不定义柔性数组,定义普通数组len需要确定的值!如10,11...
#include<stdio.h> #include<malloc.h>
typedef struct _SoftArray{ int len; int array[]; }SoftArray; //打印输出斐波那契数列 void printfln(SoftArray *p,int len) { int i; for(i=0;i<len;i++) //循环进行打印输出 { printf("%d\n",p->array[i]); } } //动态生成斐波那契数列 void create(int len) { int i; SoftArray * p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len); //声明结构体指针p,动态申请内存,大小为结构体大小+10个int型大小 //对不确定len值大小,使用了数组的方法。若不定义柔性数组,定义普通数组len需要确定的值!如10,11... for(i=0;i<len;i++) //循环进行数组赋值 { if( i <= 1 ) { p->array[i] = 1; }else if( i >= 2 ) { p->array[i] = p->array[i-1] + p->array[i-2]; }else { printf("DAMAGE: before Normal block or after Normal block"); return (-1); } } printfln(p,len); free(p); } //主函数 int main() { int i=0; int len; printf("请输入生成斐波那契数列的行数:");
scanf("%d",&len); //将一个不确定值传入了函数 create(len); return 0; }
二、动态数组
动态数组,即根据实时变化,可以扩大数组大小。而这个功能的实现需要用到指针和malloc和realloc函数。
int *a = (int*)malloc(10*sizeof(int));那么 a就相当于一个有10个元素的数组。当数据量超过10个放不下的时候,利用
a = (int*)realloc(a, 20*sizeof(int));//意思是把a的大小增加到20,而保持原来已有的数据不变。
上面的函数要包含:#include<stdlib.h> #include<malloc.h> 或#include<alloc.h>
举例说明:
#include<stdio.h> #include<stdlib.h> void DimensionalVector(){ int n, i; int *arr; //输入不定的值,体现了数组与指针的关系 scanf("%d",&n); arr = (int*)malloc(sizeof(int)*n); for (i = 0; i < n; i++) arr[i] = i; for (i = 0; i < n; i++) printf("%d\t",arr[i]); } int main(){ DimensionalVector(); return 0; }
体现了数组与指针的关系,可具体参考数组与指针的转换关系。
三、二者的区别
柔性数组是利用结构体,动态数组使用了指针与数组的关系;
前者在创建之后,利用p->array[]来访问每一个值,后者直接利用p[]来访问每一个值;
四、malloc和calloc,relloc
1、对于用malloc分配的内存区间,如果原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说, 在使用它之前必须先进行初始化(可用memset函数 对其初始化为0);
2、但调用calloc()函数分配到的空间在分配时就已经被初始化为0了;
3、rellocc函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即*ptr = NULL,则同malloc。当*ptr非空:若nuw_size < size,即缩小*ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;若nuw_size > size,即扩大*ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存,如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块nuw_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针。
malloc空间分配算法:可参考另一篇我的博文:https://www.cnblogs.com/huangfuyuan/p/9190371.html