下面一组函数是DDLA的基本函数:
void* new_a( size_t, size_t, ... );
void* new0_a( size_t, size_t, ... );
void* resize_a( void*, size_t, ... );
size_t sizeof_a( void* );
size_t dimen_a( void* );
size_t* dimenlen_a( void*, size_t* );
size_t elmntsize_a( void* );
bool process_a( void*, void (*)(void*, size_t* ) );
void delete_a( void* );
void delete_all();
new_a和new0_a用于创建数组,new0_a同时将数组各元素初始化为0。返回值为中间地址缓冲区的首地址,第一个参数为元素大小,单位字节,第二个参数为维度,可变参数为各维的长度,例如:
int **p = ( int** )new_a( sizeof( int ), 2, 7, 8 );
创建一个二维、各维长度分别为7和8的动态数组,接受返回值的指针的*声明符的个数必须与数组的维度相等。
当元素大小、维度或各维长度小于1、动态内存分配失败时,函数返回NULL。
resize_a用于动态改变数组的维度和长度,变形的过程中元素大小不变,当新数组比原数组大时,多出的部分内容不确定;新数组比原数组小时,多出的部分被截断,共有的部分内容不变。resize_a第一个参数为DDLA, 第二个参数为新数组的维度,可变参数为各维的长度。
当元素大小、维度或各维长度小于1、动态内存分配失败时,函数返回NULL。
当一个动态数组创建后,各维的首地址就是中间数组的地址,例如对于:
int **p = ( int** )new_a( sizeof( int ), 2, 7, 8 );
p[0]这个数组的地址就是p[0]的值,与传统的动态数组一样,不可以用&p[0]代替p[0],因为&p[0]的值是保存p[0]的值的那个内存单元的地址,而不是象c/c++的传统数组定义那样地址值与p[0]相同,在这里&p[0]与p[0]是不一样的,这是所有动态数组的共性。
只能对数组元素取地址,例如&p[0][0]。
elmntsize_a、dimen_a、dimenlen_a分别返回DDLA的元素大小、维度和各维长度,其中需要为dimenlen_a准备一个size_t类型的缓冲区,dimenlen_a将各维长度保存在这里,dimenlen_a第二个参数传递缓冲区的首地址,函数返回值也返回这个首地址。
如果三个函数的第一个实参不是DDLA,则返回0,dimenlen_a返回NULL。
sizeof_a是专为实现类似sizeof运算符的功能设计的,它可以计算出各维中间数组的长度,单位为字节,但不能用它计算元素的大小,获得元素大小可用elmntsize_a函数。示例如下:
对于上述定义的p动态二维数组,则sizeof_a( p )为7 x 8 x sizeof( int ),sizeof_a( p[0] )为8 x sizeof( int ),但不能使用sizeof_a( p[0][0] )。当p不是DDLA时,sizeof_a返回0。
无论DDLA处于什么地方,即使在被调函数内部,仍可以通过sizeof_a得出DDLA的大小。
process_a函数可以使用回调函数对整个或部分数组的元素进行操作,回调函数类型为 void (void*, size_t* ),两个参数的内容由process_a传递,第一个参数的实参为DDLA, 第二个参数为保存当前元素各维下标的size_t类型数组的首地址,从这里可以获知当前处理元素为哪一个元素,数组长度与维度相同。在回调函数内部可以使用DDLA各函数,但process_a本身除外,否则会出现无限调用嵌套的情况。
delete_a和delete_all用于释放不再使用的DDLA,以获得更多的剩余内存空间,delete_a释放单个DDLA,delete_all一次释放所有DDLA,如果参数不是DDLA或者为空,两函数将啥也不做。
前面介绍过的new_a等函数,都使用可变参数,但是有时候,输入的维度为变量,由于维度未知,就不能使用可变参数了,同时也不能使用确定类型的指针接受new_a返回的地址,也无法使用下标访问数组的元素,这时候可以使用new_pa函数创建这样的数组,new_pa第三个参数定义为一个指向由用户提供的size_t类型一维数组的指针,该数组保存各维长度,new_pa从此处读取各维长度,第一个元素为第一维长度,其余类推,该数组长度与维度相等。
接受new_pa数组的指针可定义为void*类型。
与之对应,resize_pa与new_pa一样,用于处理维度为变量的情况,用一个size_t类型数组指示各维长度。
创建这种数组的示例如下:
void *p;
size_t *buffer;
int m;
scanf( “%d”, &m );
buffer = ( size_t* )malloc( m * sizeof( size_t ) );
................. /*填充buffer缓冲,产生各维长度*/
p = new_pa( sizeof( int ), m, buffer );
这种方法创建的p无法直接通过下标运算符访问其元素,这时候可以通过另一组函数操作p,它们是:
assign_pa assign_va
value_pa value_va
address_pa address_va
sizeof_pa sizeof_va
pa版本的函数象new_pa一样,使用一个缓冲区存放各维长度,va是这些函数的可变参数版本。
assign_pa对某元素赋值,value_pa则相反,是取值,address_pa返回某元素或中间数组的地址,当第二个参数为0时,address_pa还可以返回元素存储区的首地址,这个地址才是真正的保存元素内容的区域的首地址,p的值是中间地址缓冲区的首地址,如果觉得这些函数使用比较麻烦,可以通过address获得的元素存储区首地址直接操作元素的值,这也是连续存储区带来的好处。sizeof_pa返回数组及各中间数组的大小,sizeof_pa还可以返回元素的大小。