第 11 节:数组(二)

187 阅读4分钟

数组(二)

本节内容要点:

  • 二维数组
  • 编写处理数组的函数

10.3 二维数组

1.二维数组的定义和初始化

二维数组可以看作是数组的数组,它在编程中常用于表示表格数据、矩阵等。在大多数编程语言中,二维数组可以通过指定两个维度的大小来定义和初始化。

二维数组的定义:

   定义类型:类型名 数组名[ 行表达式 ][ 列表达式];
int a[3][4];

表示定义了一个 3×4,即 34 列总共有 12 个元素的数组 a。这 12 个元素的名字依次是:

a[0][0]、a[0][1]、a[0][2]、a[0][3];
a[1][0]、a[1][1]、a[1][2]、a[1][3];
a[2][0]、a[2][1]、a[2][2]、a[2][3]。

与一维数组一样,行序号和列序号的下标都是从 0 开始的

  • 元素 a[i][j] 表示第i+1行、第 j+1列的元素。

  • 数组 int a[m][n] 最大范围处的元素是 a[m–1][n–1]

    所以在引用数组元素时应该注意,下标值应在定义的数组大小的范围内。

行与列用常量表达式。

// 定义一个3行4列的二维数组
int array[3][4];

// 初始化二维数组
int array[3][4] = {
  {1234},
  {5678},
  {9101112}
};
2.二维数组在内存中的存储

二维数组在内存中的存储是连续的,尽管它在逻辑上看起来是由多个一维数组组成的。这种存储方式称为行优先存储(row-major order) ,意味着内存中先存储第一行的所有元素,然后是第二行的所有元素,依此类推,直到最后一行。

行优先存储(Row-Major Order)

在行优先存储中,二维数组的元素按照行的顺序依次存储。例如,一个3行4列的二维数组在内存中的存储方式如下:

1 | 2 | 3 | 4 |  // 第一行5 | 6 | 7 | 8 |  // 第二行9 | 101112|  // 第三行

每个元素占用的内存大小取决于数组的数据类型。例如,如果数组是整型(int),在32位系统中,每个元素可能占用4个字节。

内存地址计算

由于二维数组在内存中是连续存储的,我们可以通过计算来直接访问特定元素的内存地址。对于一个声明为int array[rows][cols]的二维数组,元素array[i][j]的内存地址可以通过下面的公式计算:

address(array[i][j]) = base_address(array) + (i * cols + j) * size_of(int)

-base_address(array)是数组在内存中的起始地址。

-size_of(int) 是单个整型元素占用的字节数。

性能考虑

由于二维数组的存储方式,访问数组中的元素时,内存访问模式是优化的,因为它遵循了CPU缓存的行缓存机制。当按顺序访问数组元素时(如遍历每一行),CPU可以有效地利用缓存,提高访问速度。

总结

二维数组在内存中的存储方式对于理解数组操作的效率至关重要。了解行优先存储的概念有助于编写更高效的代码,特别是在处理大型数据集时。此外,这种存储方式也影响了数组操作的算法设计,例如,某些算法可能需要考虑内存访问模式以减少缓存未命中和提高性能。

3.二维数组的使用

C语言中的二维数组定义及实例

#include <stdio.h>

// 定义一个3行4列的二维数组
int array[3][4] = {
  {1234},
  {5678},
  {9101112}
};

int main() {
  printf("The element at [1][2]: %d\n"array[1][2]); // 输出:7
  return 0;
}

运行结果:

The element at [1][2]: 7

遍历数组

// C语言遍历二维数组示例
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        printf("Element at [%d][%d]: %d\n", i, j, array[i][j]);
    }
}

运行结果(部分展示):

Element at [0][0]: 1
Element at [0][1]: 2
...
Element at [2][3]: 12

10.4 数组与函数

传递数组给函数
#include <stdio.h>

void print2DArray(int arr[3][4]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("Element at [%d][%d]: %d\n", i, j, arr[i][j]);
        }
    }
}

void arrayFun() {
    int arr[3][4] = {
        {1234},
        {5678},
        {9101112}
    };

    print2DArray(arr);
}

int main() {
    arrayFun();
}

该段代码会输出与上述遍历二维数组相同的运行结果。

Element at [0][0]: 1
Element at [0][1]: 2
Element at [0][2]: 3
Element at [0][3]: 4
Element at [1][0]: 5
Element at [1][1]: 6
Element at [1][2]: 7
Element at [1][3]: 8
Element at [2][0]: 9
Element at [2][1]: 10
Element at [2][2]: 11
Element at [2][3]: 12

函数修改数组 尽管此处未给出具体示例,但在C/C++中,若要让函数修改传入的二维数组,可以将参数声明为指向数组的指针(如 void modify2DArray(int (*arr)[4], int rows)),这样函数内部就可以直接修改原始数组的内容。