/*郭睿玥第六次算法实验作业*/ /*实验原理 数组的顺序表示和实现 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 <stdio.h> #include <stdlib.h> #include <stdarg.h> //标准头文件,提供宏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 */