数组的实现——数据结构
由于存储单元是一维的结构,而数组是个多维的结构,则用一组连续的存储单元存放数据元素就有次序约定的问题了。
假设现在有一个三维数组A[5][6][7],现在初始化其数据结构时,不难联想到,首先要说明存放的数据类型(也可以是数组元素的基址,但元素的类型是一定要说明的),其次,就是数组的维数,还有就是每一维的大小。现在继续考虑,假设现在这个数组已经被我们定义成了这个结构,当我们想要取出元素A[3][2][1],由于存储单元是连续的顺序存储结构,必须要算出其相对于A[0][0][0]的地址,不难算出其结果:A[3][2][1]=3*(6*7)+2*7+2(其各维的索引下标都是从0开始的)。我们可以总结对任意的n维数组,设每一维的大小为bi,其元素的存储位置如下:
Locate(j1,j2,....,jn)=Locate(0,0,....,0)+[(j1*bn*bn-1*....*b2)+(j2*bn*bn-1*....*b3)+....+(jn-1*bn)+(jn)]
于是为了对数组元素定位的方便,在其数据结构中添加一项数组映像函数,其实质就是计算每一个单独维其向下所含有的元素的个数(bn*bn-1*...*bi+1 :如本例中的A,其映像函数的值分别为7*6和7)。
综上其结构如下:
typedef struct {
ElemType *base; //数组元素的基址,
int dim; //数组的维度
int *bound; //数组维界的基址
int *constants; //数组映像函数常量的基址
}Array;
在开始数组的初始化工作之前,由于不知道输入的维数,以致在写初始化函数的时候,含有不确定个数的参数,所以有必要来了解一下va_list(以下来自百度百科)
VA_LIST 是在C语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>,用于获取不确定个数的参数
#include<stdarg.h>
#include<stdio.h>
void vltest(int i, float k, ...) //...代表可变参数
{
va_list vl; //定义va_list变量vl,该变量是指向参数的指针
va_start(vl, k); // 参数一:va_list变量vl;参数二:va_list变量vl中最后一个固定参数
int j = va_arg(vl, int); // 参数一:va_list变量vl;参数二:可变参数的类型,返回值j即可变参数
double m = va_arg(vl, double); // 同上
unsigned long n = va_arg(vl, unsigned long); // 同上
va_end(vl); // 结束可变参数的获取
printf("i = %d; k = %.1f; j = %d; m = %lf; n = %lu\r\n", i,k, j, m, n);
}
void main()
{
int i=1,j=8;
double m=3;
float k=2.0;
unsigned n=0;
vltest(i,k,j,m,n);
}
结果如图:

//数组的初始化
int Init_Array(Array &A,int dim,...)
{
//若输入的数组维度dim和各维的长度合法,则初始化数组,返回1
if(dim<1 || dim>MAX_ARRAY_DIM)
return 0;
A.dim=dim;
A.bound=(int *)malloc(dim * sizeof(int));
if(!A.bound)
exit(-2); //overflow
//各维的长度合法,则存入A.bound中,并求出A的元素总数
int elemTotal=1;
va_list ap;
va_start(ap,dim); //存放变长参数表信息的数组
int i;
for(i=0;i<dim;i++)
{
A.bound[i]=va_arg(ap,int);
if(A.bound[i]<0)
return -1;
elemTotal*=A.bound[i];
}
va_end(ap);
A.base=(ElemType *)malloc(elemTotal*sizeof(ElemType));
if(!A.base)
return -1;
//求映像函数的常数,同时存入A.constants中去
A.constants=(int *)malloc(dim*sizeof(int));
if(!A.constants)
return -1;
A.constants[dim-1]=1;
for(i=dim-2;i>=0;i--)
A.constants[i]=A.constants[i+1]*A.bound[i+1];
return 1;
}
数组的初始化完成之后,其他的工作就很简单了。
数组的赋值与取值案例如下:
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h> //标准头文件,提供宏va_start、va_arg和va_end,用于存储变长的参数表
#define ElemType int
#define MAX_ARRAY_DIM 8 //定义数组的最大维数为8
typedef struct {
ElemType *base; //数组元素的基址,由Init_Array函数分配
int dim; //数组的维度
int *bound; //数组维界的基址
int *constants; //数组映像函数常量的基址
}Array;
//数组的初始化
int Init_Array(Array &A,int dim,...)
{
//若输入的数组维度dim和各维的长度合法,则初始化数组,返回1
if(dim<1 || dim>MAX_ARRAY_DIM)
return 0;
A.dim=dim;
A.bound=(int *)malloc(dim * sizeof(int));
if(!A.bound)
exit(-2); //overflow
//各维的长度合法,则存入A.bound中,并求出A的元素总数
int elemTotal=1;
va_list ap;
va_start(ap,dim); //存放变长参数表信息的数组
int i;
for(i=0;i<dim;i++)
{
A.bound[i]=va_arg(ap,int);
if(A.bound[i]<0)
return -1;
elemTotal*=A.bound[i];
}
va_end(ap);
A.base=(ElemType *)malloc(elemTotal*sizeof(ElemType));
if(!A.base)
return -1;
//求映像函数的常数,同时存入A.constants中去
A.constants=(int *)malloc(dim*sizeof(int));
if(!A.constants)
return -1;
A.constants[dim-1]=1;
for(i=dim-2;i>=0;i--)
A.constants[i]=A.constants[i+1]*A.bound[i+1];
return 1;
}
int Locate(Array A,va_list ap,int *off)
{
//若ap指示的各下标值合法,则求出该元素在A中的而相对位置
*(off)=0;
int index;
int i;
for(i=0;i<A.dim;i++)
{
index=va_arg(ap,int);
if(index<0 || index>=A.bound[i])
return -1;
*(off)+=A.constants[i]*index;
}
return 1;
}
int Assign_value(Array &A,ElemType e,...)
{
//A是n维数组,e赋值元素,其后是n个下标值
va_list ap;
va_start(ap,e);
int off=0;
if(Locate(A,ap,&off)<0)
return -1;
*(A.base+off)=e;
return 1;
}
int Get_value(Array A,ElemType *e,...)
{
//A是n维数组,e是取值元素,其后是n个下标值
va_list ap;
va_start(ap,e);
int off=0;
if(Locate(A,ap,&off)<0)
return -1;
*e=*(A.base+off);
return 1;
}
void main()
{
Array A;
Init_Array(A,3,5,6,7);
int i,j,k,t=1;
for(i=0;i<5;i++)
for(j=0;j<6;j++)
for(k=0;k<7;k++)
Assign_value(A,t++,i,j,k);
int value;
Get_value(A,&value,3,2,1);
printf("数组A的A[3][2][1]的值为:%d\n",value);
}
截图如下:


浙公网安备 33010602011771号