数组的实现——数据结构

  由于存储单元是一维的结构,而数组是个多维的结构,则用一组连续的存储单元存放数据元素就有次序约定的问题了。

  假设现在有一个三维数组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>,用于获取不确定个数的参数

用法
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
(2)然后用VA_START宏初始化刚定义的VA_LIST变量;
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
(4)最后用VA_END宏结束可变参数的获取。
宏:
  VA_START宏:获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):
                        #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
  VA_ARG宏:   获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):
                        #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
  VA_END宏: 清空va_list可变参数列表:
                        #define va_end(ap) ( ap = (va_list)0 )
测试如下:
#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);
}

截图如下:

 

 

        

posted @ 2017-06-04 21:31  晓乎  阅读(1257)  评论(0编辑  收藏  举报
总访问: counter for blog 次