一、问题引入
我们定义数组时,数组的方括号内填写的是一个常量表达式。可是,在很多情况下,数组的大小是不确定的,比如储存学生信息的数组,我们往往需要对学生的信息进行增、删、查、改,那么数组的大小就要随着对学生信息的操作而改变。这里就需要引入动态数组的概念。
二、动态数组
大多数情况下,我们无法预知数组的长度,所以,我们希望数组的长度能够随数据的增加自动增长。一种常用的数组增长策略是:当程序检测到数组已经装满时,数组长度自动增长为原来的两倍。为了实现这个功能,我们需要引入malloc 与 realloc 函数。
三、malloc 与 realloc 函数
1、void *malloc(size_t size);
malloc函数用于向内存申请size个字节大小的空间,若申请成功,则返回这段内存空间的首地址。若申请失败,则返回NULL。
2、void *realloc(void *ptr, size_t new_size);
realloc函数用于增长或缩短之前申请的内存空间。函数的第一个参数是之前申请的内存空间的首地址,第二个参数是将之前申请的内存空间增长或缩短为new_size个字节大小的内存空间,返回值是新的内存空间的首地址。
四、具体案例
为方便大家理解,我们引入一个具体案例:利用动态数组实现学生信息的增、删、查、改。
一、定义相关结构体
首先,定义学生信息结构体。
typedef struct{
int id; // 学号
char name[20]; // 姓名
int gender; // 性别
int mark; // 成绩
}student;
然后,定义一个嵌套结构。
typedef struct {
student* pData;
int size;
int capacity;
}vector
pData 用于记录数组的首元素指针。 size 为数组中盛放的数据的长度。 capacity 为整个数组拥有的元素个数,即数组的容量。
二、定义vectorInit函数初始化vector结构体
为了方便测试,我们将数组初始大小设置为1,可以用一个define宏定义。
#define VECTOR_INIT_CAPACITY 1
然后,再定义一个vectorInit函数初始化vector结构体, 初始情况下,使用 malloc 函数申请一个元素类 型为 struct student 的数组,数组的元素数量为 VECTOR_INIT_CAPACITY 。保存这个数组的首元素指针 到 pData 中。此时,数组拥有的元素个数为 VECTOR_INIT_CAPACITY ,盛放的数据长度为0。
void vectorInit(vector* pVec)
{
pVec->pData = (student*)malloc(sizeof(student)*VECTOR_INIT_CAPACITY);
//相当于student a->pData[sizeof(student)*VECTOR_INIT_CAPACITY]
pVec->size = 0;
pVec->capacity = VECTOR_INIT_CAPACITY;
}
三、增
利用bool型函数增加学生信息,如果增加成功,返回true,否则返回false。
代码和注释如下。
bool vectorAppend(vector* pVec,student data)
{
if (pVec->size >= pVec->capacity)//判断数组是否装满
{
//将数组增长为原来的两倍
student* newData = (student*)realloc(pVec->pData, pVec->capacity * sizeof(student) * 2);
if (newData == NULL)//如果增长失败,则返回false
{
return false;
}
pVec->pData = newData;
pVec->capacity = 2 * pVec->capacity;
}
pVec->pData[pVec->size] = data;
pVec->size++;
return true;
}
四、删
从数组中删除元素的方法:从被删除元素的下标开始,将后续元素依次赋值给前驱元素。
void vectorRemove(vector* pVec, int index)
{
for (int i = index; i < pVec->size - 1; i++)
pVec->pData[i] = pVec->pData[i + 1];//将后续元素依次赋值给前驱元素
pVec->size -= 1;//数组盛放元素减1
}
五、查
查找元素很简单,只要输出结构体数组中index下标所对应的元素数据即可。
student vectorGet(vector* pVec, int index)
{
return pVec->pData[index];
}
六、改
clear 方法用于将所有数组中盛放的数据清空,并将数组的容量缩短为初始容量。再调用”增“函数重置学生信息即可。
void vectorClear(vector* pVec)
{
if (pVec->pData != NULL)
free(pVec->pData);//释放内存空间
pVec->pData = (student*)malloc(sizeof(student) * VECTOR_INIT_CAPACITY);
pVec->size = 0;
pVec->capacity = VECTOR_INIT_CAPACITY;
}