C动态数组-(非容器类)

本文详细介绍了动态数组的两种形式——连续动态数组与离散动态数组,并对比了两者的优缺点。重点讲解了连续动态数组的实现方式及其优势,包括直接寻址、长度与维度的灵活调整等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 根据数据存储区的空间连续性,可以将动态数组分成两大类,一类是具有连续存储空间的动态数组,另一类是非连续存储空间的动态数组。笔者分别将它们称为连续动态数组和离散动态数组。

 

离散动态数组是最简单的动态数组,因为无须考虑数据在哪里存储,只需要动态分配就行了,同时中间地址不需要或只需要简单计算就可以得出。例如一个二维离散动态数组可以这样构造:

 

int **p = ( int** )malloc( m * sizeof( int* ) );

for( i = 0; i < m; ++i )

       p[i] = ( int* )malloc( n * sizeof( int ) );

 

上述代码中,p指向中间地址缓冲区,保存第一维各元素的首地址,p[i]指向数据存储区,这个存储区是不连续的。释放空间时需要这样进行:

 

for( i = 0; i < m; ++i )

       free( p[i] );

free( p );

 

离散动态数组是先构造好中间地址缓冲区,再构造数据存储区,这是造成数据空间不连续的原因,虽然构造过程简单,但非连续性带来很多缺点。一是不利于数组内部的直接寻址,例如通过数据区首地址计算元素地址;二是当需要对数组长度进行改变时,过程复杂;三是空间的释放需要对中间地址缓冲区重新遍历。但其实,完全可以先构造数据存储区,再构造中间地址缓冲区,这种方法使连续数据存储空间有了可能,而且,连续动态数组不会带来离散动态数组那些缺点。下面是构造连续动态数组的示例:

 

int *p = ( int* )malloc( m * n * sizeof( int ) );

int **q = ( int** )malloc( m * sizeof( int* ) );

for( i = 0; i < m; ++i )

       q[i] = p + i * n;

 

首先p分配m*n个int数据的存储区,再由q根据这段空间构造中间地址。现在,不仅可以通过q[m][n]使用这个数组,还可以直接通过p和下标运算符访问数组的元素。释放空间的时候直接释放p和q就行了,需要改变数组长度的话,只须重新分配p指向的空间,再重新构造一下中间地址缓冲区,例如将上述m*n个int元素的数组改为k*j个int元素,可以这样做:

 

int *p = ( int* )realloc( p, k * j * sizeof( int ) );

int **q = ( int** )realloc( q, k * sizeof( int* ) );

for( i = 0; i < k; ++i )

       q[i] = p + i * j;

 

而离散动态数组就必须先动态分配好k*j个int的新空间,然后把旧数据都复制过去,再释放旧空间,整个过程比连续空间麻烦得多。

 

连续动态数组不仅可以使用堆中的空间,还可以在栈段和数据段中构造,只要在栈或数据段的数组对象中重新构造中间地址即可,例如:

 

double a[100];

double **p = ( double** )malloc( 5 * sizeof( double* ) );

for( i = 0; i < 5; ++i )

       p[i] = a + i * 20;

 

这样就把一维double数组a的空间重新在逻辑上改造成了一个二维数组p[5][20],注意重新构造的动态数组的长度不能超出a的空间,否则结果是不确定的,是危险的。

 

上述例子在一个一维数组上构造了一个二维数组,维度发生了变化,这说明连续动态数组不仅可以方便地改变长度,还可以方便地改变维度。当目标维度可变时,中间地址的构造需要使用递归算法。笔者的博客中就提供了一个维度可变的数组ADT的例子。

 

要注意的是,动态数组的中间地址不具数组类型。例如上述动态数组q[m][n]的第一维q[m]类型依然是int*,而一个数组对象int a[m][n]的第一维a[m]的类型是数组类型int[n]。

 

综合来看,由于连续动态数组的优点比离散动态数组多得多,在编程实践中应优先使用连续动态数组。

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/supermegaboy/archive/2009/11/23/4854899.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值