### C语言中的数组与指针
#### 二维数组与指针概述
在C语言中,二维数组是一种非常实用的数据结构,它可以被形象地理解为一个表格。与一维数组不同,二维数组允许我们在行和列两个维度上组织数据。本文将详细介绍二维数组的基本概念、定义方式、内存布局以及如何通过指针访问二维数组中的元素。
#### 二维数组的定义
二维数组可以通过以下方式定义:
```c
类型标识符 数组名[整型常量表达式1][整型常量表达式2];
```
其中,“类型标识符”是指数组中元素的数据类型,如`int`、`float`等;“数组名”是定义的数组名称;而“整型常量表达式1”和“整型常量表达式2”分别代表数组的行数和列数,它们必须是整型的常量表达式。
例如:
```c
inta[2][3];//定义了一个2行3列的整型二维数组,数组名为a。
```
这里定义了一个名为`a`的二维数组,它包含两行三列的整数。
#### 二维数组的内存布局
在内存中,二维数组实际上是一维连续存储的。例如,对于上述定义的`int a[2][3]`,它的内存布局如下所示:
- `a[0][0]`
- `a[0][1]`
- `a[0][2]`
- `a[1][0]`
- `a[1][1]`
- `a[1][2]`
可以看到,虽然在逻辑上我们将数组理解为二维结构,但在物理上它是按照行优先的原则进行连续存储的。
#### 访问二维数组的元素
可以通过下标来访问二维数组中的元素。例如,`a[i][j]`表示数组`a`中第`i`行第`j`列的元素。这里的`i`和`j`均是从0开始的整数。
示例代码如下:
```c
a[1][2] = 2; // 将a数组第二行第三列的值设为2
x = a[1][2] * 10; // 将a数组第二行第三列的值乘以10赋值给x
```
#### 二维数组的初始化
二维数组可以在定义时进行初始化。初始化的方式有多种:
1. **逐行初始化**:每一行分别用大括号包围。
```c
int a[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
```
2. **省略行数**:如果知道列数,可以省略行数。
```c
int a[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
```
3. **不分行**:类似于一维数组的初始化方式。
```c
int a[4][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
```
4. **初始化数据不足**:系统会用0自动填充剩余部分。
```c
int a[4][3] = {{1, 2}, {4, 5}, {7, 8, 9}, {10, 11, 12}};
```
5. **最简单的初始化**:
```c
int a[4][3] = {0};
```
#### 指针与二维数组
在C语言中,数组名本质上是一个指向数组第一个元素的指针。因此,我们可以利用指针来操作和访问二维数组。
- **行指针**:`a`本身可以被视为一个指向含有3个整型元素的数组的指针。
- 示例代码:
```c
int (*p)[3] = a; // 定义一个指向含有3个整型元素数组的指针
p[i]; // 等同于 a[i]
p[i][j]; // 等同于 a[i][j]
```
- **列指针**:`a[i]`可以被视为指向第`i`行第一个元素的指针。
- 示例代码:
```c
int *p = a[0]; // 定义一个指向整型元素的指针
*(p + 1); // 获取第0行第1号元素的内容
*(p + 5); // 获取第1行第2号元素的内容
```
#### 习题解析
假设有一个二维数组`inta[m][n];`,根据之前的内容,我们可以解答以下问题:
- `a`保存数组的首地址,即`&a[0][0]`。
- `a+1`跳过`n*sizeof(int)`个字节。
- `a[i]`保存着第`i`行的地址,即`&a[i][0]`。
- `a[i]+1`跳过`sizeof(int)`个字节。
通过以上内容的学习,我们不仅掌握了二维数组的基本定义和使用方法,还了解了如何利用指针来高效地访问和操作数组中的元素。这对于编写更复杂的数据处理程序至关重要。