多维数组与指针

来源:互联网 发布:奇葩说人工智能哪一期 编辑:程序博客网 时间:2024/06/10 03:52

有关的声明语句及效果

几个例子:

char *a[]; // error: unknown size of a.
char *a1[10]; // type of a1 is "int*[10]", size of a1 is 40.
char (*a2)[]; // type of a2 is "int[0]*", size of a2 is 4.
char (*a3)[10]; // type of a3 is "int[10]*", size of a3 is 4.

数组退化为指针

When an identifier of an array type appears in an expression other than sizeof, address-of (&), or initialization of a reference, it is converted to a pointer to the first array element.

用 new 运算符创建多维数组

When new is used to allocate a multidimensional array of objects, it yields a pointer to the first element of the array, and the resultant type preserves the size of all but the leftmost array dimension. For example:
new float[10][25][10]
yields type float (*)[25][10](pzy:应该也就是 float[25][10]*).

为什么多维数组的非最左维的长度非常重要(因此必须是常量表达式)?

因为它们是指针的数据类型的一部分。比如 int[3]* 和 int[7]* 不属同一类型,这些长度决定了指针的“步距”。假设一个函数接受二维整形数组,可以给它 int[3]* ,但不能给它 int[]* ——指向未知长度的数组的指针是没有意义的,编译器不知道指针加1要偏移多少。

下面的函数接收了 int(*)[] 参数,因为没有指定第二维数组的长度,语句 1 和 2 会导致错误。但是,如果没有这两句,函数是可以被编译的,也就是说 int(*)[] 仍然是个正确的类型(不合理罢了)。

void f(int (*a)[], int rows, int cols)
{
int n = 0;
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < cols; ++c)
{
a[r][c] = n++; // 语句1, CERROR: int(*)[]:unknown size.
cout << a[r][c] << " "; // 语句2, CERROR: int(*)[]:unknown size.
}
cout << endl;
}
}

对于上面的函数,它应该把参数 a 声明为 int(*)[COLS],其中 COLS 为常数表达式。如果不能在编译时确定 COLS,函数 f 的参数列表就应该是类似这个样子了:(int **a, int rows, int cols) 或 (int *a, int rows, int cols),前者使用数组的数组,后者使用一维数组。

示例代码

演示了几种使用动态二维数组的方式。

#1 使用“多级”数组,它可以做成钜齿数组。

#1-2 既可看成 #1 的变形,也可看成 #3 的扩展。作为 #1 的变形,它能保证各子数组是连续的,但无法做成钜齿数组。作为 #3 的扩展,它相当于引入了一组书签——如果把目标数组看作一本书(每一页代表一个数组元素)的话。

#2 无视多维数组的概念, 用一维数组以行为主序连续存放子数组,通过下标算术访问元素:

*((array-name) + (subscript1* max2 * max3...maxn)
+ subscript2 * max3...maxn)
. . . + subscriptn))

#3 真正的二维数组(为什么有人说C++里没有真正的多维数组?)。arr4是指向数组的指针,它的步距是一个数组。值得注意的是多维数组的释放方式,就是简单的 delete[]。

总结起来,真多维数组的使用是最简便的,但是它有一个严重的限制是,它的高维子数组要求常量尺寸。

// want int[NCOLS,NROWS].
const int NCOLS = 7;
int NROWS = 3;

// #1: array of array.

// allocate.
int **arr1 = new int*[NROWS]; // memory for int*.
for (int r = 0; r < NROWS; ++r)
arr1[r] = new int[NCOLS]; // memory for int.

// access:arr1[r][c].

// destroy:upwards.
for (int r = 0; r < NROWS; ++r)
delete []arr1[r]; // memory for int.
delete []arr1; // memory for int*.
arr1 = NULL;

// #1-2: keep array's contents contiguous.

// allocate.
int **arr2 = new int*[NROWS]; // memory for int*.
arr2[0] = new int[NROWS * NCOLS]; // memory for int.
for (int r = 1; r < NROWS; ++r)
arr2[r] = arr2[r - 1] + NCOLS;

// access: arr2[r][c].

// destroy:upwards.

delete []arr2[0]; // memory for int.
delete []arr2; // memory for int*.
arr2 = NULL;

// #2: singly dimensioned array,
// access by subscript calculations.

// allocate.
int *arr3 = new int[NROWS * NCOLS]; // arr3 == arr2[0].

// access: arr3[c + r * NCOLS].

// destroy.
delete []arr3; // memory for int.
arr3 = NULL;

// #3: pointer to array.

// allocate.
int (*arr4)[NCOLS] = new int[NROWS][NCOLS];
// NCOLS must be constant expression.
// Type of arr4 is int[NCOLS]* - a pointer.

// access: arr4[r][c];

// destroy:upwards.
delete []arr4; // memory for int*.
arr4 = NULL;

原创粉丝点击