5.1配列の定義&5.2配列の順序表示と実現


5.1配列の定義:
配列が定義されると、次元と次元境界は変更されません.したがって,構造の初期化と破棄に加えて,配列は要素へのアクセスと要素値の変更のみを行う.
5.2配列の順序表示と実現
次に、配列順序格納の表示を見てみましょう.
コードは次のとおりです.
#include 	//   va_start、va_arg、va_end
					//          
#define MAX_ARRAY_DIM 8//        8

typedef struct{
	ElemType* base;	//      , InitArray  
	int dim;	//    
	int* bounds;	//      , InitArray  
	int* constants;	//          , InitArray  
}Array;

まず分析します.
このva_start,va_arg,va_end関連コードに出会ってからにしましょう.
この*baseは配列要素のベースアドレスで、いわゆる要素のベースアドレス、私达は1次元の配列を知っていて、2次元の配列、3次元の配列はロジックの上で私达は彼をイメージ化することができて、例えば1次元の配列は線で、2次元は平面で、3次元は空間で、しかしメモリの中で、彼はやはり線形に配列して、だからそんなに1つの配列の要素のベースアドレスがあって、やっと要素の位置を確定することができます.
このdimは、さっき言った1次元、2次元、3次元などの配列の次元を指します.
この*boundsは、各次元が格納されているアドレスです.
この*constantsこれは配列イメージ関数定数ベースアドレスで、イメージ関数とは何かと聞かれるかもしれません.イメージ関数とは、配列の下付きスケールに基づいて格納位置をすばやく計算するためのもので、聞き取れないと言われています.例をあげましょう.各要素の占有量を1つのメモリセルとする.実はこれは:(b 2*…*bn)*j 1+(b 3*…*bn)*j 2+(b 4*…*bn)*j 3+…+[b(n-1)*bn]*j(n-2)+bn*j(n-1)+1*jn上式のバリエーション.constants[0]*j1+constants[1]*j2+...+constants[n-2]*j(n-1)+constants[n-1]*jn bounds[]に格納されている各次元の数
分かったでしょう.
次に、基本操作の関数プロトタイプの説明を示します.
まずInitArray関数を見てみましょう.
コードは次のとおりです.
Status InitArray(Array& A, int dim, ...)
{
	//   dim        ,        A,   OK
	if (dim<1 || dim>MAX_ARRAY_DIM)
		return ERROR;
	A.dim = dim;
	A.bounds = (int *)malloc(dim*sizeof(int));
	if (!A.bounds)
		exit(OVERFLOW);

	//       ,   A.bounds,   A     elemtotl
	int elemtotal = 1;	// elemtotal       ,   1(   )
	va_list ap;
	va_start(ap, dim);	//                 ,    ,           ,                        
	for (int i = 0; i < dim; i++)
	{
		A.bounds[i] = va_arg(ap, int);
		if (A.bounds[i] < 0)
			return UNDERFLOW;	//  math.h    4
		elemtotal *= A.bounds[i];
	}
	va_end(ap);
	A.base = (ElemType*)malloc(elemtotal*sizeof(ElemType));
	if (!A.base)
		exit(OVERFLOW);

	//        Ci,   A.constant[i-1],i=1,...,dim
	A.constants = (int*)malloc(dim*sizeof(int));
	if (!A.constants)
		exit(OVERFLOW);
	A.constants[dim - 1] = 1;	//L=1,              
	for (int i = dim - 2; i >= 0; --i)
		A.constants[i] = A.bounds[i + 1] * A.constants[i + 1];
	return Ok;
}

以下に分析します.
このMAX_ARRAY_DIMは、定義したばかりのマクロ、つまり最大8次元のみです.
ここのパラメータには「...」これは誰かが聞くかもしれません.ここで説明します.printfという、つまり可変パラメータはみんな知っています.では、いったい何個の可変パラメータがあるのかをどのように読み取るのか.それがva_start,va_list,va_end,va_Argの件ですが、以下va_について説明します.start,va_list,va_end,va_arg.
va_listは文字ポインタであり、現在のパラメータを指すポインタと理解され、パラメータはこのポインタで行わなければならない.パラメータテーブルを呼び出す前にva_を定義します.listタイプの変数(va_listタイプ変数がapとして定義されていると仮定).次にapを初期化し、va_を介して可変パラメータテーブルの最初のパラメータを指すようにします.startは、最初のパラメータがap自体であり、2番目のパラメータがパラメータテーブルの前に隣接する変数、すなわち「...」であることを実現する.前のパラメータ;次にパラメータを取得し、va_を呼び出します.arg、その最初のパラメータはapで、2番目のパラメータは取得するパラメータの指定タイプで、それからこの指定タイプの値を返して、apの位置を変参表の次の変数の位置に指します;すべてのパラメータを取得した後、このapポインタをオフにして、危険が発生しないようにする必要があります.va_を呼び出す方法です.end,彼は入力したパラメータapをNULLにし,パラメータテーブルを取得した後にポインタを閉じる習慣を身につけるべきである.はっきり言って、私たちのプログラムに丈夫さを持たせることです.通常va_startとva_endはペアで現れる.
ここではvaは使われていませんargは、次のプログラムで使用されます.
関数の説明が終わりました.次はこのプログラムの考え方を説明します.
このプログラムの構想はまず何次元のArrayを初期にして、この可変パラメータの中に入っているのはdimの数によって判断して、例えばdimは2次元で、それでは2次元で、それでは更に2つの可変パラメータが必要で、1つは1次元の要素の個数で、1つは2次元の要素の個数です.
ここでelemotal*=A.bounds[i]は、次元内のすべての要素を読み出します.
そしてA.baseは最初の要素のアドレスです.
A.baseのスペースを開いた後、イメージ関数を作ります.
次に、配列Aを破棄する
コードは次のとおりです.
Status DestroyArray(Array& A)
{
	//    A
	if (!A.base)
		return ERROR;
	free(A.base);
	A.base=NULL:
	if (!A.bounds)
		return ERROR;
	free(A.bounds);
	A.bounds = NULL;
	if (!A.constants)
		return ERROR;
	free(A.constants);
	A.constants = NULL;
	return Ok;
}

分析:
これは、そのポインタアドレスが空でない場合にfreeし、ポインタを安全な地帯、すなわちNULLに向けることです.
次に、Aにおける要素の相対位置を求める.
コードは次のとおりです.
Status Locate(Array A, va_list ap, int& off)
{
	// ap         ,       A     off
	int ind;
	off = 0;
	for (int i = 0; i < A.dim; i++)
	{
		ind = va_arg(ap, int);
		if (ind < 0 || ind >= A.bounds[i])
			return OVERFLOW;
		off += A.constants[i] * ind;
	}
	return Ok;
}

分析:
この関数は次の関数と結びつけて見ます.呼び出しva_argは、最初のパラメータがapであり、2番目のパラメータが取得するパラメータの指定タイプであり、この指定タイプの値を返し、apの位置をパラメータテーブルの次の変数の位置に指します.このapは次のValue関数の可変パラメータです.
次の2つの関数コードは次のとおりです.
Status Value(Array A, ElemType& e, ...)
{
	//A n   ,e     ,   n    。
	//       , e       A    ,   OK。
	va_list ap;
	int result;
	int off;
	va_start(ap, e);
	if ((result = Locate(A, ap, off)) <= 0)
		return result;
	e = *(A.base + off);
	return Ok;
}

Status Assign(Array& A, ElemType e, ...)
{
	//A n   ,e     ,   n    。
	//      ,  e         A   ,   OK
	va_list ap;
	va_start(ap, e);
	int off;
	int result;	//   Statues    int 
	if (result = Locate(A, ap, off) <= 0)
		return result;
	*(A.base + off) = e;
	return Ok;
}