本篇内容介绍了“C语言二维数组是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
二维数组的定义
同一维数组一样,既支持 C89 标准的二维静态数组,又支持 C99 标准的二维动态数组或变长数组。某些 C 编译器还没更新到支持 C99 标准的语法,故可能在一些编译器中变长数组会报错。如无特殊说明,教程中所指二维数组,均默认为静态数组。
静态二维数组定义的一般格式为:
类型 数组名[第一维大小][第二维大小];
其中,第一、二维的大小一般均为常量表达式。
例如:
int a[4][5];
定义了一个 4 行 5 列的 int 型二维数组 a。
float sc[3][4];
定义了一个 3 行 4 列的 float 型二维数组 sc。
如下二维数组的定义形式均是错误的。
int a[][3];//错误。编译器无法确定所需空间int a[2][];//错误。缺少列下标,编译器无法确定所需空间
动态数组例子如下(仅做了解)。
int n=2;int a[n][3];//动态数组,正确的C99语法。但在某些编译器中可能报错int a[2][n];//动态数组,正确的C99语法
定义时未初始化的数组,其数据元素的值一般为无意义的随机值,如:
int a[2][3];//该数组的6个元素均为随机值
可以把二维数组看成一个特殊的一维数组,它的每个元素又是一个一维数组。例如,定义一个表示 3 个学生 4 门课程成绩的二维数组:
int sc[3][4];
定义了一个 3 行 4 列的二维数组 sc,该二维数组可表示 3 个对象(学生),从这个角度看,该二维数组可以看成含 3 个对象(学生)的一维数组,3 个对象(元素)分别为:sc[0]、sc[1]、sc[2],其中 sc 为该一维数组名。
每个对象(元素)sc[i] 又是一个包含 4 个属性(4 门成绩)的一维数组,4 个属性分别 为:sc[i][0](语文)、sc[i][1](数学)、sc[i][2](外语)、sc[i][3](C 语言)。每一行表示一个学生,每一列表示一门课程,形成如下所示的行列矩阵形式。
语文 数学 外语 c语言
sc[0](第一个学生)-----sc[0][0] sc[0][1] sc[0][2] sc[0][3]
sc[1](第二个学生)-----sc[1][0] sc[1][l] sc[1][2] sc[1][3]
sc[2](第三个学生)-----sc[2][0] sc[2][1] sc[2][2] sc[2][3]
二维数组名 sc 是首对象(第一个学生)sc[0] 的地址,即 sc=&sc[0]。二维数组名加 1 表示跳过一个对象,即 sc+1 为第二个对象(学生)sc[1] 的地址,sc+2 为第三个对象(学生)sc[2] 的地址。
从行列式角度分析,二维数组名即首行的地址,C 语言中的地址一般均是空间首地址。故二维数组名是首行首地址,该数组名加 1 表示跳过一整行,到达第二行的首地址,以此类推。
【例 1】以下二维数组 sc 用于保存 3 个学生的 4 门课程(语数外及 C 语言)成绩。根据程序的运行结果,分析二维数组名的含义。
#includeint main (void){ int sc[3][4]; printf("sc=%p\n",sc); printf ("&sc[0]=%p\n",&sc[0]); printf("sc+1=%p\n",sc+1); printf("sc+2=%p\n",sc+2); return 0;}
程序某次运行的结果:
sc=0060FEE0
&sc[0]=0060FEE0
sc+1=0060FEF0
sc+2=0060FF00
程序分析:
1) 本例中定义的二维数组为 3 行 4 列,含 3 个学生对象,对应 3 行,每个学生对象包括 4 个属性,对应 4 列。
2) 二维数组名 sc 相当于首对象即第一个学生 sc[0] 的地址,即 sc==&sc[0]。输出地址一般使用格式控制符 %p 或 %x 或 %08x。由某次运行结果可知,sc 和 &sc[0] 的值均为十六进制数 0060FEE0。
由此可得:二维数组名为首对象或首行的地址。
3) 二维数组名加 1 表示跳过一个对象(一行)的空间,为下一个对象(下一行)的地址。即跳过一个对象所有属性(一行中所有列元素)对应的空间,到达下一个对象(下一行)的起始位置。
而本例中一个对象有 4 个属性,每个属性均为整型变量,在 VC++6.0 中占 4 字节,故一个对象(一行)共占 4X4=16 个字节。故 sc、sc+1、sc+2 均相差 16 个字节,转换为十六进制为 0x10。如运行结果所示。
4) 程序每次运行为某变量空间分配的起始地址可能有差别。
二维数组的引用
二维数组的引用格式为:
数组名[行下标][列下标];
注意引用数组元素时不能加类型,行下标、列下标均从 0 开始。且行下标和列下标的形式可以为常量、变量或表达式。
若 M 和 N 均为已定义的正整数:
int i,j; //i和j分别表示行下标和列下标.int a[M][N]; //定义了一个M行N列的二维整型数组a
行下标i的范围为 0〜M-1。
列下标j的范围为 0〜N-1。
称第几个时,习惯上是从第 1 个开始,第 2 个,第 3 个,…,而不从第 0 个开始。但是二维数组的行下标及列下标均是从 0 开始的,为统一起见,本书中对数组元素的引用,采用行列序号来描述,如 a[i][j] 为 i 行 j 列元素,而不说成第 i 行第 j 列元素。例如:
int a[3][4];a[0][0]; //为0行0列元素a[2][1]; //为2行1列元素a[1][1+2]; //为1行3列元素
例如:
int n=4, i, j ;int a[3][4]; //定义了一个3行4列的二维数组a
对该数组的引用形式为 a[i][j],其中,行下标 i 的范围为 0〜2,列下标 j 的范围为 0〜3。以下对该二维数组的引用均是正确的。
a[2][n-1]=a[0][1+1] +a[2][2-1]; //a[0][2]、a[2][1]相加后赋给a[2][3]a[3-1][n-1];//引用2行3列元素
以下对该二维数组的引用形式是错误的。
a[-2][1]; //行下标-2越界,应为0〜2a[3][2]; //行下标3越界,应为0〜2a[2][n]; //列下标n=4越界,应为0〜3a[2,3]; //引用形式错误,应为a[2][3]a[2][]; //缺少列下标int a[1][n-2]; //引用不能加类型,若为定义,第二维含有变量n,错误
【例 2】定义一个 2 行 3 列的二维数组,从键盘上输入 6 个数值,依次给该二维数组的每个元素赋值,按每行三个元素输出该二维数组及所有元素的和。
程序分析:
例题涉及对二维数组的赋值,一般使用双重循环,外层循环控制行下标,内层循环控制列下标。二维数组的每个元素 a[i][j] 像普通变量一样使用,使用 scanf 函数输入时,一定要加 &。输入时,可以输入完 6 个数据后按一次回车键。
本题要求每输出一行后换行,即输出完一行中的所有列数据(内层循环结束)后换行。
实现代码:
#includeint main (void){ int a[2][3]; //先定义,后赋值 int i,j,s=0; printf("Input 6 integers:"); for(i=0;i<2;i++) { for (j=0; j<3; j++) { scanf ("%d",&a[i][j]); //勿忘 & s+=a[i][j] ; //与上一条语句不能颠倒 } } for(i=0;i<2;i++) { for (j=0; j<3; j++) printf("%d\t",a[i][j]); //使用\t 的作用 printf ("\n"); //注意该输出换行符的位置 } printf("s=%d\n", s); return 0;} 运行结果为: Input 6 integers:1 2 3 4 5 6 1 2 3 4 5 6 s=21 二维数组的初始化
二维数组可以先定义,后赋值,在显式赋值之前,二维数组的各数据元素是随机值。也可以在定义二维数组的同时,采用初始化列表的形式对其元素赋初值,称为二维数组的初始化。
二维数组的初始化方式通常有以下几种。
1) 分行给出初始化数据,且每行的初始化数据个数等于列数。例如:
int a[2][3]={{1,2,3},{4,5,6}};
该初始化列表给出了两行数据,每一行数据用一对大括号 {} 括起来,一行中的数据及行与行之间均用逗号隔开。这是一种较常用的二维数组的初始化方式。
该初始化语句相当于如下 6 条赋值语句。
a[0][0]=1; a[0][1]=2; a[0][2]=3;a[1][0]=4; a[1][1]=5; a[1][2]=6;
由于初始化列表中明确给出了两行数据,故定义该数组时,其第一维的大小可省略,编译器能间接算出该数组的行数为 2,故依然可以确定其空间大小,因此,在对二维数组进行初始化时,其第一维的大小可以省略,即写成如下形式:
int a[][3]={{l,2,3},{4,5,6}};
注意:第二维的大小一定不能省略!如下初始化均是错误的。
int a[2][] = {{l,2,3},{4,5,6}}; //错误。不能省略第二维大小int a[][] = {{l,2,3}, {4,5,6}}; //错误。不能省略第二维大小int a[][3]; //错误。没有提供初始化列表时,两维的大小都必须显式给出int a[2][3] = {{l,2,3},{4,5,6},{7,8,9}}; //错误。初始行数多于数组行数
如果把上面一条初始化语句改为省略第一维的大小,便是正确的,即:
int a[][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; //正确。间接得知该数组为三行
2) 分行给出初始化数据,但每行的初始化数据个数少于列数。例如:
int a[2][3]={{l,2},{4}};
该初始化列表给出了两行数据,第一行给出两个数据,少一个,对 int 型默认为补 0;第二行仅给出一个数据,少两个,补两个 0。所以上述初始化语句相当于:
int a[2][3]={{1,2,0},{4,0,0}};
同理:
int a[][3]={{0},{0}};
相当于:
int a[][3] = {{0,0,0},{0,0,0}}; //2行3列
3) 初始化数据没有分行,容易产生混乱,不推荐这种方式。
如果初始化数据的个数是列数的整数倍,即:
int a[2][3]={l,2,3,4,5,6};
初始化数据以列数三个为一组,共分为两组,且每组数据个数恰好等于列数 3,故第一组赋值给第 1 行,第二组赋值给第 2 行。初始化后,数组中各元素为:
1 2 3
4 5 6
例如:
int a[2][3]={1,2,3,4};
由于该二维数组列数为 3,初始化数据以三个为一组,共分为两组,但第二组仅一个数据,少于列数 3,对 int 型数组用 0 补齐。故第一组数据 1,2,3 赋值给第一行,第二组补齐为三个数据 4,0,0 后,赋值给第二行。相当于 int a[][3]={1,2,3,4,0,0}; 初始化后, 数组中各元素为:
1 2 3
4 0 0
int a[][3] = {1,2,3,4,5,6,7,8}; //正确,可间接得知该数组为三行,不推荐
第三行不够三个数据,用 0 补齐。故该语句相当于:
int 3[][3] = {1,2,3,4,5,6,7,8,0};
初始化后,数组中各元素为:
1 2 3
4 5 6
7 8 0
如果第一维大小没有省略,则初始化数据的个数一定不能超过数组元素的总个数,否则报错。例如:
int a[2][3] = {1,2,3,4,5,6,7,8};//错误。初始数据个数8多于数组总个数6
二维数组的存储
二维数组在逻辑(表现形式)上可理解为矩阵形式(分行分列),但其物理存储形式却是连续的,即存完第一行,在其后面接着存储第二行,第三行,…,如无特殊说明,本书中涉及对二维数组的表述一般指的是其逻辑形式即矩阵形式。
二维教组的应用举例
【例 3】一个班级有 N 名学生,每个学生有 4 门课程(语文、数学、外语、C 语言),计算每个学生的平均分。编写程序实现该功能需求。
问题分析:该问题可把每个学生当成一个对象,而每个对象(学生)有 5 个属性:4 门课程成绩及平均分。故该问题可使用二维数组来处理数据,该二维数组含有 N 个对象,故第一维的大小为 N,每个对象有 5 个属性,故第二维的大小为 5。为便于验证,本例中学生个数 N 设为 3 个。
实现代码:
#include#define N 3int main (void){ float a[N][5],sum; //sum用来累加每个学生4门课的总成绩 int i, j ; printf ("输入%d个学生信息(语、数、外、C语言成绩):\n",N); for(i=0;i
运行结果为:
输入3个学生信息(语、数、外、C语言成绩):
NO1:82 91 88 93
NO2:83 84 80 91
NO3:73 79 86 81
学号 语文 数学 外语 C语言 平均成绩
NO1: 82.0 91.0 88.0 93.0 88.5
NO2: 83.0 84.0 80.0 91.0 84.5
NO3: 73.0 79.0 86.0 81.0 79.8
“C语言二维数组是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。