数组指针、指针数组、二维数组

数组指针、指针数组、二维数组

蛋总常说“凡事必有初”,写下这篇博客的初衷在于:
今天尝试用指针的方式访问一个大二维数组,而又不想用一维数组人工计算偏移量,于是有了指针数组与数组指针的探索。结论是数组指针。

二维数组

我们在开辟一个二位数组的时候似乎很简单。
比如要开辟一个第一二维度分别是5和8的int数组,可以定义为 int a[5][8]。遍历这个数组的方式可以写为:

int a[5][8];
for (int i=0; i<5; i++) {
    for (int j=0; j<8; j++) {
        // visit a[i][j]
    }
}

注意,这个二维数组的第二维是固定的,第一维通常也是固定的,例外情况是 C99 支持的 VLA,可以在函数内声明第一维不定长的数组,如:

int main() {
    int x = 5;
    int a[x][8];
    return a[2][0];
}

但是通常我们为了兼容性考虑,不会使用VLA,因为C++不支持VLA。而且VLA只能在函数内声明,无法声明为全局变量,比如以下写法就无法通过编译:

int x = 5;
int a[x][8];
int main() {
    return a[2][0];
}

数组指针

数组指针本质还是一个指针,和多维数组搭配使用很方便。
比如对于上面的二维数组a,可以声明一个对应类型的数组指针 b 为 int (*b)[8], 这里b就是一个数组指针,指向包含8个int元素的一维数组,p++ 会一次跨越8个int元素的步长。若要借助b来访问a的数据,操作如下:

int a[5][8];
int (*b)[8];
b = a;
for (int i=0; i<5; i++) {
    for (int j=0; j<8; j++) {
        // visit b[i][j]
    }
}

上面这种方式看起来似乎没有必要,那么当我们需要开辟一个第一维不定长的数组,尤其是全局数组的时候,数组指针就很有必要了。还记得之前说过的 VLA 的局限吗?

// ...
int (*b)[8];
int main() {
    int w = 5;
    b = (int(*)[8])malloc(sizeof(int) * 8 * w);
    for (int i=0; i<5; i++) {
        for (int j=0; j<8; j++) {
            // visit b[i][j]
        }
    }
}

另外一种使用场景则是在函数传参的时候,使用 int (*p)[8] 作为形参和使用 int p[][8] 作为形参是等价的,做的都是数组指针的工作:

void foo(int p[][8]) {
    // visit p[i][j]
}
void bar(int (*p)[8]) {
    // visit p[i][j]
}
int main() {
    int a[5][8];
    foo(a);
    bar(a);
}

指针数组

指针数组顾名思义是一个元素类型为指针的数组,本质是个数组。
指针数组也可以和多维数组搭配使用,通常用于底层维度不确定的情况。当然用于底层维度确定的情况也可以,但是没必要,还是上面的例子:

int a[5][8];
int* b[5];
for (int i=0; i<5; i++) {
    b[i] = a[i];
}
for (int i=0; i<5; i++) {
    for (int j=0; j<8; j++) {
        // visit b[i][j]
    }
}

或者更干脆,当高维长度不知道的时候,我们需要写成如下形式:

int** b;
int main() {
    int w = 5;
    b = (int**)malloc(sizeof(int*) * w);
    for (int i=0; i<w; i++) {
        b[i] = (int*)malloc(sizeof(int) * 8);
    }
    for (int i=0; i<w; i++) {
        for (int j=0; j<8; j++) {
            // visit b[i][j]
        }
    }
}

可以看到,同样是访问数组a,借助数组指针只需要一个指针的空间开销,而借助指针数组则需要5个指针开销。 int (*p)[8] vs. int* p[5] 前者完胜后者。

posted @ 2022-03-09 16:06  与MPI做斗争  阅读(84)  评论(0编辑  收藏  举报