首页 > 编程笔记 > C语言笔记(精华版)

C语言二维数组指针的定义和使用(附带示例)

C语言中的二维数组指针,实际上是指向二维数组中的某一行,而不是指向二维数组这个整体。借助二维数组指针,我们可以一行一行地遍历整个数组。
 

这个可以和一维数组指针类比。一维数组指针是指向数组中的某个元素,而不是指向一维数组这个整体。
 

在内存中,二维数组是以行优先的方式存储的,也就是说,一行接着一行地排列。例如,一个 3x4 的二维数组在内存中实际上是一个包含 12 个元素的连续内存块。
 

二维数组指针的定义语法如下:

数据类型 (*指针变量名)[列数];

在这个语法中,数据类型是数组元素的类型,指针变量名是我们要定义的指针变量,列数是二维数组的列数。括号是必需的,因为如果没有括号,这将变成一个指针数组(数组的每个元素都是指针类型),而不是一个指向数组的指针。


让我们通过一个具体的例子来理解二维数组指针的使用:

#include <stdio.h>

int main() {
    int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    int (*p)[4];
    p = arr;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", p[i][j]);
        }
        printf("\n");
    }

    return 0;
}

在这个例子中,我们定义了一个 3x4 的二维数组 arr,然后定义了一个指向含有 4 个整数的数组的指针 p。我们将 p 指向 arr,这是合法的,因为 arr 可以被视为一个包含 3 个元素的数组,每个元素都是一个包含 4 个整数的数组。
 

运行这段代码,我们会得到以下输出:

1 2 3 4 
5 6 7 8 
9 10 11 12 

这个输出证明我们成功地使用二维数组指针访问了二维数组的所有元素。需要注意的是,虽然我们使用了指针 p,但我们仍然可以使用熟悉的 p[i][j] 语法来访问数组元素,这与直接使用数组名 arr[i][j] 的效果是一样的。

另外,我们也可以借助*[ ]的组合来访问数组元素,例如:

printf("%d\n", (*p)[0]);  // 输出 arr[0][0],即 1
printf("%d\n", (*p)[1]);  // 输出 arr[0][1],即 2
printf("%d\n", (*(p+1))[0]);  // 输出 arr[1][0],即 5
printf("%d\n", (*(p+2))[3]);  // 输出 arr[2][3],即 12

理解 p+n 的含义非常重要。由于 p 是指向一个包含 4 个整数的数组的指针,p+1 会使指针向后移动 4 个整数的长度,也就是移动到下一行的开始位置;同理,p+2 会是指针向后移动 4*2 个整数的长度,也就是移动到后两行的开始位置。
 

二维数组指针的一个重要应用是在函数参数中。当我们需要将二维数组传递给函数时,可以使用二维数组指针作为参数类型。例如:

void printArray(int (*arr)[4], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int arr[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
    printArray(arr, 3);
    return 0;
}

在这个例子中,函数 printArray 接受一个二维数组指针和行数作为参数,这种方法允许我们传递不同行数的二维数组,只要每行都有 4 列。
 

二维数组指针还可以用于动态分配二维数组,这在处理大型数据或需要在运行时确定数组大小时特别有用。以下是一个动态分配 3x4 二维数组的例子:

int rows = 3, cols = 4;
int (*dynamicArr)[4] = malloc(rows * sizeof(*dynamicArr));

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        dynamicArr[i][j] = i * cols + j + 1;
    }
}

// 使用完毕后记得释放内存
free(dynamicArr);

在这个例子中,我们动态分配了一个可以容纳 3 个元素的数组,每个元素都是一个包含 4 个整数的数组。这种方法的优势在于我们可以在运行时决定行数,但列数必须在编译时确定。
 

理解二维数组指针的内存布局对于有效使用它们至关重要。每次我们增加指针(如 p+1),它都会移动到下一行的起始位置。这意味着 p、p+1、p+2 等分别指向二维数组的第一行、第二行、第三行的起始位置。

相关文章