/*郭睿玥第六次算法实验作业*/
/*实验原理
数组的顺序表示和实现
1.存在的主序问题
由于我们的内存是一维的线性结构,而数组是个多维的结构,则用一组连续存储单元存放
数组元素时就有个次序约定问题。因为我们是用C语言实现,所以我们默认都是使用行主序
(BASIC、COBOL、 PASCAL和C语言)(FORTRAN 语言使用列主序)。
2.存储位置计算
对于数组,一旦规定了它的维数和各维的长度,便可为它分配存储空间。反之,只要给出一
组下标就可求出相应数组元素的存储位置。下面以行序为主序的存储结构进行说明。
假设每个数据元素占L个存储单元,则二维数组A任一元素a(i, j)的存储位置可由下式确定:
LOC(i, j) = LOC(0, 0)+(b2*i+j) *L
其中LOC(0, 0)是元素a(0, 0)的存储位置,即二维数组A的起始存储位置,也称为基地址。
现将二维数组推广到一般情况,得到n维数组的数据元素存储位置的计算公式
*/
/*实验环境
CodeBlocks*/
/*实验目的
理解数组的逻辑结构和顺序存储方式
掌握数组的建立和使用的特点
*/
/*实验内容
创建x维数组
为x维数组各个元素赋值
打印x维数组各个元素的值
*/
#include
#include
#include //标准头文件,提供宏va_start、va_arg和va_end用于存取变长参数表
#define MAX_ARRAY_DIM 8 //假设数组维数最大值为8
typedef struct
{
int *base; //数组元素基址
int dim; //数组维数
int *bound; //数组维界基址,即用于存储每一维的长度
int *constants;//数组映像函数的各个常量系数
}Array;
//初始化数组,初始化维度,每一维的长度,和给数组分配内存
void InitArray(Array *A, int dim, ...)//初始化数组,其中由于数组维数不固定故使用...
{
if (dim < 1 || dim > MAX_ARRAY_DIM)//如果维数超界则结束
return;//返回
A->dim = dim; //初始化数组的维数
A->bound = (int*)malloc(dim * sizeof(int));//申请空间
int elemtotal = 1;//elemtotal用于计数
va_list ap;//用于参数个数不定的变量ap
va_start(ap, dim);//引用函数,获取可变参数dim的第一个参数的地址
for (int i = 0; i < dim; ++i) //存放数组每一维的长度
{
A->bound[i] = va_arg(ap, int);//获取可变参数的当前参数,返回指定类型并将指针指向下一参数
elemtotal *= A->bound[i]; //统计数组的元素个数
}
va_end(ap);//清空可变参数
A->base = (int*)malloc(sizeof(int) * elemtotal);//申请首地址空间
A->constants = (int*)malloc(dim * sizeof(int));//申请为每一维度的空间
A->constants[dim - 1] = 1; //最后的一维是一维数组,其参数固定为1
for (int i = dim - 2; i >= 0; --i)
{
A->constants[i] = A->bound[i + 1] * A->constants[i + 1];//除了最后一维之外每一位的空间都是上一位空间*这一维度的长度
}
}
//释放数组动态分配的内存空间,以免发生内存泄露
void DestroyArray(Array *A)//销毁数组
{
if (!A->base)//如果base不占空间
return;//返回
free(A->base);//清空
A->base = NULL;//首元素是空
if (!A->bound)//如果bound不占空间
{
return;//返回
}
free(A->bound);//清空申请的空间
A->bound = NULL;//置空
if (!A->constants)//如果constants不占空间
{
return;//返回
}
free(A->constants);//清空申请的空间
A->constants = NULL;//置空
}
//ap参数中存放着要存取的元素的下标,off为数组映像函数的常量参数
int Locate(Array *A, va_list ap, int *off)//布尔型函数,定位坐标为(x,y,z,...)的元素在数组中的下标
{
*off = 0;
for (int i = 0; i < A->dim; ++i)//根据维度循环
{
int ind = va_arg(ap, int); //依次取出每一维的下标
if (ind < 0 || ind > A->bound[i])//如果要定位的元素在某一维的坐标值不在范围
return 0;//返回错误
(*off) += A->constants[i] * ind;//计算待存取的元素和数组基址的距离,即数组下标
}
return 1;//返回
}
//A是n维数组,e是元素变量,随后是n个下标值
//若下标不越界,则将e赋值为所指定的A的元素
void Value(Array *A, int *e, ...)//取值函数,由于维数不确定故,参数数量不确定
{
va_list ap;//用于参数个数不定的变量ap
va_start(ap, e);//引用函数,获取可变参数dim的第一个参数的地址
int off;
if (!Locate(A, ap, &off))//如果位置为ap的元素不在指定的三维空间以内则返回
{
return;//返回
}
*e = *(A->base + off);//获取下标为off的元素的值
}
//A是n维数组,e是元素变量,随后是n个下标值
//若下标不越界,则将e赋给指定的A的元素
void Assign(Array *A, int e, ...)//赋值函数
{
va_list ap;//用于参数个数不定的变量ap
va_start(ap, e);//引用函数,获取可变参数dim的第一个参数的地址
int off;
if (!Locate(A, ap, &off))//如果位置为ap的元素不在指定的三维空间以内则返回
{
return;//返回
}
*(A->base + off) = e;//将e赋值为所指定的A的元素
}
int main(void)
{
Array arr;//建立一个数组
InitArray(&arr, 3, 3, 6, 8);//初始化数组,这个数组是三维的,每维度的长分别为3,6,8,即这个数组一共有144个元素
for (int i = 0; i < 3; ++i)//每一层循环
{
for (int j = 0; j < 6; ++j)//每一列循环
{
for (int k = 0; k < 8; ++k)//每一行循环
{
Assign(&arr, i + j + k, i, j, k);//为当前元素赋值这个元素位于数组的第i*48+j*8+k个元素
}
}
}
for (int i = 0; i < 3; ++i)//每一层循环
{
for (int j = 0; j < 6; ++j)//每一列循环
{
for (int k = 0; k < 8; ++k)//每一行循环
{
int tmp = 1;
Value(&arr, &tmp, i, j, k);//根据在每维度的位置坐标(k,j,i)获取这个元素的值
printf("%5d", tmp);//输出这个值
}
printf("\n");//换行
}
printf("\n");//换行
}
printf("\n");//换行
return 0;//结束
}
/*实验结果如下
0 1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10 11
5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10 11
5 6 7 8 9 10 11 12
6 7 8 9 10 11 12 13
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10 11
5 6 7 8 9 10 11 12
6 7 8 9 10 11 12 13
7 8 9 10 11 12 13 14
*/