在C99标准之前,C语言在创建数组的时候,数组的大小只能使用常量,常量表达式来,或者在初始化数组时,省略数组的大小,这就是所谓的定长数组
#include
int main()
{
int arr1[10];
int arr2[10 + 5];
int arr3[] = {1,2,3,4,5,6,7,8,9,10};
return 0;
}
有定长数组这样的语法限制,让我们创建数组不够灵活,有时数组大小给大了浪费空间,有时数组大小给小了不够用,所以在C99标准之后,有个一个变⻓数组(variable-length array,简称 VLA)的概念,允许我们在创建数组的时候使用变量
int n = a + b;
int arr[n];
在上述示例中,arr 就是变长数组,因为它的长度取决于变量n的值,编译器没法事先确定,只有运行时才能知道变量n是多少
变长数组特点:
- 变长数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化
- 变⻓数组的意思是数组的⼤⼩是可以使⽤变量来指定的,在程序运⾏的时候,根据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的⼤⼩⼀旦确定就不能再变化了。
在VS2022中是不支持变长数组的,没法测试,在gcc编译器上可以测试
#include
int main()
{
int n = 0;
scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
int arr[n];
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
那么有没有一种数组,在确定确定数组的大小,还可以根据需要扩大数组
在C99 中,结构体中的最后⼀个元素允许是未知⼤⼩的数组,这就叫做『柔性数组』成员。
例如:
struct S
{
int i;
char c;
int arr[];
};
在上述示例中,arr就是变长数组
变长数组的特点:
- 在结构体中
- 最后一个成员
- 未知大小的数组
这样的数组就是柔性数组
struct S
{
int i;
char c;
int arr[];
};
#include
int main()
{
printf("%zd\n", sizeof(struct S));
return 0;
}
代码运行结果:>8
根据结构体对齐规则,int 4个字节,char 1个字节,总共5个字节,不为最大对齐数4的倍数,对齐至8字节
在存在柔性数组的结构体中,计算结构体的大小时,不会计算柔性数组的大小
柔性数组是通过 malloc realloc的方式来实现数组大小的扩大的
代码一:
#include
#include
#include
struct S
{
int i;
char c;
int arr[];
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int)); //通过结构体指针来访问结构体,开辟一个结构体大小 + 想要开辟数组大小的空间
if (p == NULL) //判断开辟是否成功
{
perror("malloc fail");
return 1;
}
//使用柔性数组
int i = 0;
for (i = 0; i < 10; i++)
{
p->arr[i] = i;
}
struct S* tmp = (struct S*)realloc(p, sizeof(struct S) + 15 * sizeof(int)); //调整数组大小
if (tmp != NULL) //判断是否调整成功
{
p = tmp;
}
else
{
perror("realoc fail");
return 1;
}
//使用
for (i = 10; i < 15; i++)
{
p->arr[i] = i;
}
//打印
for (i = 0; i < 15; i++)
{
printf("%d ", p->arr[i]);
}
//释放
free(p);
p = NULL;
return 0;
}
看不懂的可以去看看动态内存管理malloc calloc realloc free这篇博客
代码二:
#include
#include
#include
struct S
{
int i;
char c;
int *arr;
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S)); //开辟一块空间给结构体
if (p == NULL) //判断开辟是否成功
{
perror("malloc fail");
return 1;
}
p->arr = (int*)malloc(10 * sizeof(int)); //开辟数组
if (p->arr == NULL) //判断开辟是否成功
{
perror("malloc fail");
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
p->arr[i] = i;
}
int* tmp = (int*)realloc(p->arr,15 * sizeof(int)); //调整结构体大小
if (tmp != NULL) //判断
{
p->arr = tmp;
}
else
{
perror("realoc fail");
return 1;
}
//使用
for (i = 10; i < 15; i++)
{
p->arr[i] = i;
}
//打印
for (i = 0; i < 15; i++)
{
printf("%d ", p->arr[i]);
}
//释放
free(p->arr);
p->arr = NULL;
free(p);
p = NULL;
return 0;
}
代码一和代码二可以使用了柔性数组,但是代码一有两个好处:
2.这样有利于访问速度
代码一中是一块连续的内存,连续的内存有益于提⾼访问速度,也有益于减少内存碎⽚。(只是相较于代码二速度会快一点,其实,我个⼈觉得也没多⾼了,反正你跑不了要⽤做偏移量的加法来寻址)