做一些算法题的时候你是否有过这样的苦恼:
数组要是能用变量来定义数组大小那该多好啊~
数组定义小了,要改成动态的岂不是要一部分换血,好麻烦~
数组定义大了,好浪费空间...
哈哈哈,不用苦恼
你幻想的这种动态柔软的数组确实有啊~
在C99标准中
出现了这样一个名词——柔性数组
它是什么呢?
结构体中最后一个元素允许是未知大小的数组,这就叫【柔性数组】
接下来给出你们好奇的语法结构:
typedef struct st_type
{
int i;
int a[0];//柔性数组成员 写0表示并不知道这个数组有多大
}type_a;
有些小伙伴可能就照着如上代码试了,却报错
不如试试下面这个~ (并不是所以编译器都支持如上写法)
typedef struct st_type
{
int i;
int a[];//柔性数组成员
}type_a
有同学可能会问了:
博主,柔性数组怎么用呀?
柔性是怎么体现的啊?
首先你因该要了解她的特点嘛~所谓 知己知彼 百战百胜
- 结构体的柔性数组成员前至少有一个其他成员
- sizeof这种类型并不会返回柔性数组的大小
- 如果用到malloc对其进行动态内存开辟,分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
这第一条好理解,这第二条什么意思呢?
看代码:
#include<stdio.h>
typedef struct student
{
int n;
int arr[];
}student;
int main()
{
printf("sizeof = %d",sizeof(student));
return 0;
}
运行结果:
也就是计算类型大小的时候抛开柔性数组不看
按结构体对齐原则,计算其他成员即可~
欸嘿,那第三个呢?
这柔性数组是如何体现的呢?
实际上,也告诉我们,在创建结构体的时候不能直接创建,如下:
#include<stdio.h>
typedef struct student
{
int n;
int arr[];
}student;
int main()
{
student stu;
return 0;
}
那怎么办呢?
对于包含柔性数组真正的创建方式如下:
假设我希望创建的柔性数组的成员先是10个整形大小
#include<stdio.h>
typedef struct student
{
int n;
int arr[];
}student;
int main()
{
student* ps = (student*)malloc(sizeof(student) + 40);
return 0;
}
有了如上代码,再加上下图,让你对柔性数组的了解更近一层~
此时,若是我有想法:
操作一下柔性数组 (如下)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct student
{
int n;
int arr[];
}student;
int main()
{
student* ps = (student*)malloc(sizeof(student) + 40);
if (ps == NULL)
{
perror(ps);
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
//访问
for (i = 0; i < 10; i++)
{
printf("%d ", ps->arr[i]);
}
return 0;
}
哎呀,博主,你这还是只讲了使用与访问呀,那柔性体现在何处呢?
不急不急,慢下来,一步一步走,更扎实~
这就谈及到开头讨论到的问题啦,怎么解决呢?
不卖关子了 当你的数组感觉设计小了,我想让他能不能在大一点?
当然可以
这空间都是malloc出来的,用realloc即可
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct student
{
int n;
int arr[];
}student;
int main()
{
student* ps = (student*)malloc(sizeof(student) + 40);
if (ps == NULL)
{
perror(ps);
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
//访问
for (i = 0; i < 10; i++)
{
printf("%d ", ps->arr[i]);
}
student* ptr = (student*)realloc(ps,sizeof(student) + 80);
if (ptr == NULL)
{
perror(ptr);
return 1;
}
//处理
return 0;
}
在倘若,这空间利用完了,不想要了
那咱就释放:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct student
{
int n;
int arr[];
}student;
int main()
{
student* ps = (student*)malloc(sizeof(student) + 40);
if (ps == NULL)
{
perror(ps);
return 1;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
//访问
for (i = 0; i < 10; i++)
{
printf("%d ", ps->arr[i]);
}
student* ptr = (student*)realloc(ps,sizeof(student) + 80);
if (ptr != NULL)
{
ps = ptr;
}
//处理
//释放
fclose(ps);
ps = NULL;
return 0;
}
有同学又问了:
那为啥不直接让结构体的成员为int*?然后动态开辟一块空间给int*?
那咱就来分析一下以下代码在空间中是什么样的?
struct student
{
int i;
int* arr;
};
当我有这样一个结构,那么你因该期望有如下下结果
既然刚刚柔性数组都是用malloc在堆上开辟的
不妨控制变量,让这个结构也在堆上开辟看看到底柔性数组好在哪?
代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct student
{
int i;
int* arr;
};
int main()
{
struct student* ps = (struct student*)malloc(sizeof(struct student));
if (ps == NULL)
{
perror("ps");
return 1;
}
ps->i = 100;
ps->arr = (int*)malloc(40);
if (ps->arr == NULL)
{
perror("arr");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d", ps->arr[i]);
}
//释放 注意,要先释放数组
free(ps->arr);
ps->arr = NULL;
free(ps);
ps = NULL;
return 0;
}
倘若你还想扩容,如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct student
{
int i;
int* arr;
};
int main()
{
struct student* ps = (struct student*)malloc(sizeof(struct student));
if (ps == NULL)
{
perror("ps");
return 1;
}
ps->i = 100;
ps->arr = (int*)malloc(40);
if (ps->arr == NULL)
{
perror("arr");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d", ps->arr[i]);
}
//扩容
int* ptr = (int*)realloc(ps->arr, 80);
if (ptr == NULL)
{
perror("ptr");
return 1;
}
//相应使用...
//释放 注意,要先释放数组
free(ps->arr);
ps->arr = NULL;
free(ps);
ps = NULL;
return 0;
}
那么现在回顾一下之前的问题:
柔性数组和这个比起来到底有什么好呢?
首先
想象一下
- malloc的次数越多,free的次数就要多,容易出错造成内存泄漏
- 其次,多次进行malloc就会留下更多的内存碎片,导致内存利用率不高
所以好处便是
- 第一个好处是:方便内存释放
- 第二个好处是:这样有利于访问速度.