《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
1、二维数组的下标
其实二维数组访问也是使用下标的形式的,二维数组是有行和列的,只要锁定了行和列就能唯⼀锁定数组中的⼀个元素。
二维数组的行是从 0 开始的,列也是从 0 开始的,如下所示:
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
图中最右侧绿色的数字表示行号,第⼀行蓝色的数字表示列号,都是从 0 开始的。
比如:
第 0 行,第 2 列,a[0][2] = 3;
第 2 行,第 4 列,a[2][4] = 7;
第 2 行,第 0 列,a[2][0] = 3;
2、访问二维数组元素
二维数组中的元素是通过使用下标(即数组的行索引和列索引)来访问的。例如:
int val = a[2][3];
让我们来看看下面的程序,我们将使用嵌套循环来处理二维数组:
#include <stdio.h>
int main()
{
/* 一个带有 5 行 2 列的数组 */
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};int i, j;
/* 输出数组中每个元素的值 */
for ( i = 0; i < 5; i++ )
{
for ( j = 0; j < 2; j++ )
printf("a[%d][%d] = %d\n", i,j, a[i][j] );}
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
a[0][0] = 0
a[0][1] = 0
a[1][0] = 1
a[1][1] = 2
a[2][0] = 2
a[2][1] = 4
a[3][0] = 3
a[3][1] = 6
a[4][0] = 4
a[4][1] = 8
3、二维数组的输入
举例:
#include <stdio.h>
int main()
{
int arr[2][3] = {0};
int i = 0;//遍历行
//输入
for(i=0; i<2; i++) //产⽣行号
{
int j = 0;
for(j=0; j<3; j++) //产⽣列号
{
scanf("%d", &arr[i][j]); //输入数据
}
}
//输出
for(i=0; i<2; i++) //产⽣行号
{
int j = 0;
for(j=0; j<3; j++) //产⽣列号
{
printf("%d ", arr[i][j]); //输出数据
}
printf("\n");
}
return 0;
}
输入和输出的结果:
1 1 1 2 2 2
1 1 1
2 2 2
扩展 1 – 二维数组存放字符串
二维数组存放字符串,读取时当一维数组使用。
举例:
#include<stdio.h>
int main()
{
int i;
char names[6][50] = {"马超", "关平", "赵云", "张飞", "关羽", "刘备"};
for (i=0; i<6; i++) {
printf("悍将名称:%s\n", names[i]);
}
return 0;
}
运行结果:
悍将名称:马超
悍将名称:关平
悍将名称:赵云
悍将名称:张飞
悍将名称:关羽
悍将名称:刘备
扩展 2 – 二维数组名的步长
二维数组在逻辑上是方阵,由行和列组成。
但是二维数组在物理上是线性的,按行来依次进行存放,内存是连续的。
举例:
#include <stdio.h>
int main()
{
int age[6][4];
for (int i = 0; i < sizeof(age)/sizeof(age[0]) ; i++)
{
printf("age + %d address is %p\n",i, age + i);
}
for (int i = 0; i < sizeof(age) / sizeof(age[0]); i++)
{
for (int j = 0; j < sizeof(age[0]) / sizeof(int); j++)
{
printf("age[%d][0] + %d address is %p\n", i, j, &age[i][0]+j);
}
}
return 0;
}
运行结果:
age + 0 address is 0x7fffd98b9400
age + 1 address is 0x7fffd98b9410
age + 2 address is 0x7fffd98b9420
age + 3 address is 0x7fffd98b9430
age + 4 address is 0x7fffd98b9440
age + 5 address is 0x7fffd98b9450
age[0][0] + 0 address is 0x7fffd98b9400
age[0][0] + 1 address is 0x7fffd98b9404
age[0][0] + 2 address is 0x7fffd98b9408
age[0][0] + 3 address is 0x7fffd98b940c
age[1][0] + 0 address is 0x7fffd98b9410
age[1][0] + 1 address is 0x7fffd98b9414
age[1][0] + 2 address is 0x7fffd98b9418
age[1][0] + 3 address is 0x7fffd98b941c
age[2][0] + 0 address is 0x7fffd98b9420
age[2][0] + 1 address is 0x7fffd98b9424
age[2][0] + 2 address is 0x7fffd98b9428
age[2][0] + 3 address is 0x7fffd98b942c
age[3][0] + 0 address is 0x7fffd98b9430
age[3][0] + 1 address is 0x7fffd98b9434
age[3][0] + 2 address is 0x7fffd98b9438
age[3][0] + 3 address is 0x7fffd98b943c
age[4][0] + 0 address is 0x7fffd98b9440
age[4][0] + 1 address is 0x7fffd98b9444
age[4][0] + 2 address is 0x7fffd98b9448
age[4][0] + 3 address is 0x7fffd98b944c
age[5][0] + 0 address is 0x7fffd98b9450
age[5][0] + 1 address is 0x7fffd98b9454
age[5][0] + 2 address is 0x7fffd98b9458
age[5][0] + 3 address is 0x7fffd98b945c
详细说明:
二维数组名的步长是一行的长度,比如一下例子中:
age + 1 address is 00EFFC04
age + 2 address is 00EFFC14
因为每一行有四个元素,每个 int 类型的元素占四个字节,一行有 16 个字节,所以数组名 age 加 1 后地址增加了 16 个字节说明数组名的步长位一行的长度。
具体到每一个元素加 1 的时候,地址增加的是一个元素所占字节的大小,因此元素的步长即为元素本身的大小,例如:
age[2][0] + 0 address is 00EFFC14
age[2][0] + 1 address is 00EFFC18
扩展 3 – 二维数组当作参数
将二维数组当作参数的时候
:必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小
,这是由编译器原理限制的。
事实上,编译器是这样处理数组的:
设有数组 int a[m][n],如果要访问 a[i][j]的值,编译器的寻址方式
为:
&a[i][j] = &a[0][0] + i*sizeof(int)*n + j*sizeof(int);
// 注意 n 为第二维的维数
因此,可以省略第一维的维数,不能省略其他维的维数。
在定义二维数组的时候对其进行初始化,也可以省略第一维,编译器会根据你的初始化语句自动决定第一维度。
举例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char a[3][3];
memset(a, 0, sizeof(a));
printf("%lu\n", sizeof(a));
for(int i=0; i<3; i++)
{
for(int j=0; j<10; j++)
printf("%d ", a[i][j]);
}
return 0;
}
运行结果:
9
0 0 0 0 0 0 0 0 0
扩展 4 – C99 标准的变长数组
在 C99 标准之前
,C 语⾔在创建数组的时候,数组大小的指定只能使用常量、常量表达式。
比如我们学过的代码:
int arr1[10];
int arr2[3+5];
C99 标准中
存在变长数组,允许我们可以使用变量指定数组大小。
请看下⾯的代码:
int n = a+b;
int arr[n];
数组 arr 就是变长数组,因为它的长度取决于变量 n 的值,编译器没法事先确定,只有运行时才能知道 n 是多少。
变长数组的根本特征:
就是数组长度只有运行时才能确定,所以变长数组不能初始化。它的好处是不必在开发时,随意为数组指定⼀个估计的长度,程序可以在运行时为数组分配精确的长度。
《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
每日一更!
公众号、优快云等博客:小菜狗编程笔记
谢谢点赞关注哈!目前在飞书持续优化更新~
日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!