动态数组,是相对于静态数组而言。静态数组的长度是预先定义好的,在整个程序中,一旦给定大小后就无法改变。而动态数组则不然,它可以随程序需要而重新指定大小。动态数组的内存空间是从堆(heap)上分配(即动态分配)的。是通过执行代码而为其分配存储空间。当程序执行到这些语句时,才为其分配。程序员自己负责释放内存。
为什么要使用动态数组?
在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题,用静态数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数结合指针可以按需要动态地分配内存空间,来构建动态数组,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。
动态数组与静态数组的对比
对于静态数组,其创建非常方便,使用完也无需释放,要引用也简单,但是创建后无法改变其大小是其致命弱点!
对于动态数组,其创建麻烦,使用完必须由程序员自己释放,否则严重会引起内存泄露。但其使用非常灵活,能根据程序需要动态分配大小。
本章中对于动态数组的遍历使用到了迭代器操作,迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。
本章中对于动态数组的遍历使用到了迭代器操作,迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。
迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和C/C++“操作array元素”时的指针接口一致。不同之处在于,迭代器是个所谓的复杂的指针,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器型别都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义于内部。因此各种迭代器的接口相同,型号却不同。这直接导出了泛型程序设计的概念:所有操作行为都使用相同接口,虽然它们的型别不同。
功能
迭代器使开发人员能够在类或结构中支持foreach迭代,而不必整个实现IEnumerable或者IEnumerator接口。只需提供一个迭代器,即可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable接口或者IEnumerator接口的Current,MoveNext和Dispose方法。
特点
特点
1.迭代器是可以返回相同类型值的有序序列的一段代码;
2.迭代器可用作方法、运算符或get访问器的代码体;
3.迭代器代码使用yieldreturn语句依次返回每个元素,yield break将终止迭代;
4.可以在类中实现多个迭代器,每个迭代器都必须像任何类成员一样有惟一的名称,并且可以在foreach语句中被客户端,代码调用如下所示:foreach(int x in SimpleClass.Iterator2){};
5.迭代器的返回类型必须为IEnumerable和IEnumerator中的任意一种;
6.迭代器是产生值的有序序列的一个语句块,不同于有一个 或多个yield语句存在的常规语句块;
7.迭代器不是一种成员,它只是实现函数成员的方式,理解这一点是很重要的,一个通过迭代器实现的成员,可以被其他可能或不可能通过迭代器实现的成员覆盖和重载;
8.迭代器块在C#语法中不是独特的元素,它们在几个方面受到限制,并且主要作用在函数成员声明的语义上,它们在语法上只是语句块而已;
9.yield关键字用于指定返回的值。到达yieldreturn语句时,会保存当前位置。下次调用迭代器时将从此位置重新开始执行。 迭代器对集合类特别有用,它提供一种简单的方法来迭代不常用的数据结构(如二进制树)。
简介
迭代器是一种检查容器内元素并遍历元素的数据类型。
对于迭代器iterator.h头文件的实现如下:
foreach 和 reverse_foreach分别为为正向和反向遍历.
本章中对于dynamic_array.h 的实现如下:
dynamic_array.c对于接口的实现如下:
在dynamic_array.h 中结构体对于插入和删除进行了封装.
工具文件tools.h和tools.c的实现如下:
tools.h
tools.c
测试程序如下:
其实验结果和内存检测如下图所示:
对于迭代器iterator.h头文件的实现如下:
1 #ifndef _ITERATOR_H_
2 #define _ITERATOR_H_
3
4 typedef struct Iterator{
5 void *ptr; //指定的容器中元素的地址
6 int index; //迭代器当前容器中的下标
7 int size; //迭代器所指向容器的有效元素的个数
8 }Iterator;
9
10 //正向迭代
11 //iter是迭代器的存储实体
12 //container是容器的地址
13
14 #define FOREACH(iter,container)\
15 for(container ->iter_head(&iter,container);\
16 (iter).ptr;\
17 container ->iter_next(&iter,container))
18
19 #define foreach FOREACH
20
21 //反向迭代
22 #define REVERSE_FOREACH(iter,container)\
23 for(container ->iter_tail(&iter,container);\
24 (iter).ptr;\
25 container ->iter_prev(&iter,container))
26
27 #define reverse_foreach REVERSE_FOREACH
28
29 #endif
~
foreach 和 reverse_foreach分别为为正向和反向遍历.
本章中对于dynamic_array.h 的实现如下:
#ifndef _DYNAMIC_ARRAY_H_
#define _DYNAMIC_ARRAY_H_
#include "tools.h"
#include "iterator.h"
#define BASE_SIZE (32)
typedef struct Array Array;
//动态数组的结构体
struct Array{
void **data; //动态数组的存储实体
int capacity; //动态数组申请的总量
int count; //动态数组当前有效元素的个数
//1.释放函数指针
void (*free)(const void *ptr);
//2.匹配函数指针
Boolean (*match)(const void *value1,const void *value2);
//3.拷贝函数指针
void *(*copy)(const void *src_value,void *dest_value);
//插入删除操作
//1.头插
Boolean (*push_front)(Array *array,void *value);
//2.尾插
Boolean (*push_back)(Array *array,void *value);
//3.头删
Boolean (*pop_front)(Array *array);
//4.尾删
Boolean (*pop_back)(Array *array);
//迭代器操作
//1.指向动态数组的头部
void *(*iter_head)(Iterator *iter,Array *array);
//2.指向下一个元素的位置
void *(*iter_next)(Iterator *iter,Array *array);
//3.指向动态数组的尾部
void *(*iter_tail)(Iterator *iter,Array *array);
//4.指向动态数组的上一个元素
void *(*iter_prev)(Iterator *iter,Array *array);
};
//定义动态数组的接口
Array *init_array(int init_size); //动态数组的初始化
void destroy_array(Array **array); //动态数组的销毁
void array_clean(Array *array); //动态数组的清零
//插入到指定下标的前边
Boolean array_prev_insert(Array *array,int index,void *value);
//插入到指定下标的后边
Boolean array_next_insert(Array *array,int index,void *value);
void *get_array_index(Array *array,int index); //得到指定下标的元素
int get_array_count(Array *array); //得到动态数组的个数
Boolean get_array_front(Array *array ,void **value); //得到头部元素
Boolean get_array_tail(Array *array,void **value); //得到尾部元素
Boolean delete_index_value(Array *array,int index); //删除指定下标元素
Boolean delete_range_value(Array *array,int left,int right); //删除指定范围的下标元素
int find_value(Array *array,void *value); //查找指定元素的下标
#endif
dynamic_array.c对于接口的实现如下:
#include <stdio.h>
#include <stdlib.h>
#include "dynamic_array.h"
//动态数组的增长
static void array_grow(Array *array,int size);
//调整大小
static int adjust_size(int size);
//动态数组为满
static Boolean is_array_full(Array *array);
static void array_grow(Array *array,int size)
{
//两种情况
//1.初始化状态
//2.数组空间不够进行扩展
//10 -> 32
//31 -> 32
//32 -> 32
//33 -> 64
int adjust = 0;
if(array ->capacity < size){
//对申请的大小做向上取整(32整数倍)
//
// 35 % 32 = 3
// 32 - 3 = 29
// 35 + 29 = 64
//
adjust = adjust_size(size);
array ->capacity = adjust;
if(array ->data){
array ->data = (void **)Realloc(array ->data,
sizeof(void *) * adjust);
}else{
array ->data = (void **)Malloc(sizeof(void *) * adjust);
}
}
}
static int adjust_size(int size)
{
//对申请的大小做向上取整(32整数倍)
//
// 35 % 32 = 3
// 32 - 3 = 29
// 35 + 29 = 64
//
return size + (BASE_SIZE - (size % BASE_SIZE));
}
static Boolean is_array_full(Array *array)
{
return array ->capacity <= array ->count;
}
//1.头插
Boolean (array_push_front)(Array *array,void *value)
{
array_prev_insert(array,0,value);
}
//2.尾插
Boolean (array_push_back)(Array *array,void *value)
{
if(array == NULL || value == NULL){
return FALSE;
}
if(is_array_full(array)){
array_grow(array,array ->capacity + BASE_SIZE);
}
array ->data[array ->count] = value;
array ->count++;
return TRUE;
}
//3.头删
Boolean (array_pop_front)(Array *array)
{
void *delete = NULL;
int i = 0;
int move_count = 0;
if(array == NULL || array ->count == 0){
return FALSE;
}
//删除操作
array ->count--;
delete = array ->data[0];
if(array ->free){
array ->free(delete);
}
for(i = 0,move_count = array ->count;i < move_count; ++i){
array ->data[i] = array ->data[i + 1];
}
array ->data[i] = NULL;
return TRUE;
}
//4.尾删
Boolean (array_pop_back)(Array *array)
{
void *delete = NULL;
if(array == NULL || array ->count == 0){
return FALSE;
}
array ->count--;
delete = array ->data[array ->count];
if(array ->free){
array ->free(delete);
}
array ->data[array ->count] = NULL;
return TRUE;
}
//迭代器操作
//1.指向动态数组的头部
void *(array_iter_head)(Iterator *iter,Array *array)
{
if(iter == NULL || array == NULL){
return NULL;
}
iter ->index = 0;
iter ->size = array ->count;
if(array ->data == NULL || array ->count == 0){
iter ->ptr = NULL;
}else{
iter ->ptr = array ->data[0];
}
return iter ->ptr;
}
//2.指向下一个元素的位置
void *(array_iter_next)(Iterator *iter,Array *array)
{
if(iter == NULL || array == NULL){
return NULL;
}
iter ->index++;
if(iter ->index >= iter ->size){
iter ->ptr = NULL;
}else{
iter ->ptr = array ->data[iter ->index];
}
return iter ->ptr;
}
//3.指向动态数组的尾部
void *(array_iter_tail)(Iterator *iter,Array *array)
{
if(iter == NULL || array == NULL){
return NULL;
}
iter ->index = array ->count - 1;
iter ->size = array ->count;
if(array ->data == NULL || array ->count == 0){
iter ->ptr = NULL;
}else{
iter ->ptr = array ->data[iter ->index];
}
return iter ->ptr;
}
//4.指向动态数组的上一个元素
void *(array_iter_prev)(Iterator *iter,Array *array)
{
if(iter == NULL || array == NULL){
return NULL;
}
iter ->index--;
if(iter ->index < 0){
iter ->ptr = NULL;
}else{
iter ->ptr = array ->data[iter ->index];
}
return iter ->ptr;
}
Array *init_array(int init_size) //动态数组的初始化
{
Array *array = (Array *)Malloc(sizeof(Array));
//初始化赋值
array ->free = NULL;
array ->match = NULL;
array ->copy = NULL;
//头删、尾删、头插、尾插
array ->push_front = array_push_front;
array ->push_back = array_push_back;
array ->pop_front = array_pop_front;
array ->pop_back = array_pop_back;
//迭代器操作
//指向头部、指向下一个、指向尾部、指向是上一个
array ->iter_head = array_iter_head;
array ->iter_tail = array_iter_tail;
array ->iter_next = array_iter_next;
array ->iter_prev = array_iter_prev;
array ->count = 0;
array ->capacity = 0;
array ->data = NULL;
if(init_size > 0){
array_grow(array,init_size);
}
return array;
}
void destroy_array(Array **array) //动态数组的销毁
{
if(array == NULL || *array == NULL){
return ;
}
//销毁步骤
//1.先销毁数组元素所指向的空间(如果需要销毁的话)
//2.销毁array ->data
//3.销毁array控制信息
array_clean(*array);
free((*array) ->data);
free(*array);
*array = NULL;
}
void array_clean(Array *array) //动态数组的清零
{
delete_range_value(array,0,array->count - 1);
}
//插入到指定下标的前边
Boolean array_prev_insert(Array *array,int index,void *value)
{
int i = 0;
if(array == NULL || value == NULL
|| index < 0 || index >= array ->count){
return FALSE;
}
if(is_array_full(array)){
array_grow(array, array->capacity + BASE_SIZE);
}
for(i = array ->count;i > index;--i){
array ->data[i] = array ->data[i - 1];
}
array ->data[i] = value;
array ->count++;
return TRUE;
}
//插入到指定下标的后边
Boolean array_next_insert(Array *array,int index,void *value)
{
int i = 0;
if(array == NULL || value == NULL
|| index < 0 || index >= array ->count){
return FALSE;
}
if(is_array_full(array)){
array_grow(array, array->capacity + BASE_SIZE);
}
for(i = array ->count;i > index + 1;--i){
array ->data[i] = array ->data[i - 1];
}
array ->data[i] = value;
array ->count++;
return TRUE;
}
void *get_array_index(Array *array,int index) //得到指定下标的元素
{
if(array == NULL || index < 0 || index >= array ->count){
return NULL;
}
return array ->data[index];
}
int get_array_count(Array *array) //得到动态数组的个数
{
if(array == NULL){
return -1;
}
return array ->count;
}
Boolean get_array_front(Array *array ,void **value) //得到头部元素
{
if(array == NULL || array ->count == 0){
return FALSE;
}
if(value){
*value = array ->data[0];
return TRUE;
}
return FALSE;
}
Boolean get_array_tail(Array *array,void **value) //得到尾部元素
{
if(array == NULL || array ->count == 0){
return FALSE;
}
if(value){
*value = array ->data[array ->count - 1];
return TRUE;
}
return FALSE;
}
Boolean delete_index_value(Array *array,int index) //删除指定下标元素
{
delete_range_value(array,index,index);
}
Boolean delete_range_value(Array *array,int left,int right) //删除指定范围的下标元素
{
int i = 0;
int j = 0;
int move_count = 0;
if(array == NULL || left < 0 || right >= array ->count
|| left > right || array ->count == 0){
return FALSE;
}
//先处理删除操作
for(i = left;i < right;++i){
if(array ->free){
array ->free(array ->data[i]);
}
array ->data[i] = NULL;
}
//在处理移动操作
move_count = array ->count;
for(i = left,j = right + 1;j < move_count;++i,++j){
array ->data[i] = array ->data[j];
array ->data[j] = NULL;
}
array ->count -= (right - left) - 1;
return TRUE;
}
int find_value(Array *array,void *value) //查找指定元素的下标
{
Iterator iter = {0};
if(array == NULL || value == NULL){
return -1;
}
if(array ->match){
foreach(iter,array){
if(array ->match(iter.ptr,value)){
return iter.index;
}
}
}else{
foreach(iter,array){
if(iter.ptr == value){
return iter.index;
}
}
}
return -1;
}
在dynamic_array.h 中结构体对于插入和删除进行了封装.
工具文件tools.h和tools.c的实现如下:
tools.h
1 #ifndef _TOOLS_H_
2 #define _TOOLS_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 //定义布尔类型
7 #define TRUE (1)
8 #define FALSE (0)
9
10
11 typedef unsigned char Boolean;
12
13 //定义接口
14 void *Malloc(size_t size);
15 void *Realloc(void * ptr,size_t size);
16 void print_int(void *value);
17 #endif
tools.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "tools.h"
4
5 void *Malloc(size_t size)
6 {
7 void *result = malloc(size);
8 if(result == NULL){
9 fprintf(stderr,"the memory is full!\n");
10 exit(1);
11 }
12 return result;
13 }
14
15 void *Realloc(void * ptr,size_t size)
16 {
17 void *result = realloc(ptr,size);
18 if(result == NULL){
19 fprintf(stderr,"the memory is full!\n");
20 exit(1);
21 }
22 return result;
23 }
24 void print_int(void *value)
25 {
26 int *p = (int *)value;
27 printf("%5d",*p);
28 }
测试程序如下:
#include <stdio.h>
#include <stdlib.h>
#include "dynamic_array.h"
#include "tools.h"
#include "iterator.h"
int main(int argc,char **argv)
{
Array *array = NULL;
Iterator iter = {0};
int arr[] = {3,2,5,8,4,7,6,9};
int arr_length = sizeof(arr) / sizeof(arr[0]);
int i = 0;
array = init_array(5); //初始化动态数组
for(i = 0;i < arr_length;++i){
array ->push_back(array,&arr[i]);
}
//打印动态数组元素
foreach(iter,array){
print_int(iter.ptr);
}
printf("\n");
//头部删除
for(i = 0;i < 3;++i){
array ->pop_front(array);
}
//打印动态数组元素
foreach(iter,array){
print_int(iter.ptr);
}
printf("\n");
destroy_array(&array);
return 0;
}
其实验结果和内存检测如下图所示: