1第6章数组2第6章数组►6.1一维数组的定义和引用►6.2多维数组的定义和引用►6.3数组与函数►6.4字符串►6.5数组应用程序举例36.1一维数组的定义和引用►C语言的数组类型,用来表示一组数据的集合。►使用数组,可以方便地定义一个名字(数组名)来表示大批数据(数组元素),并且能够通过循环批处理大量数据。46.1.1一维数组的定义►1.一维数组的定义►一维数组的定义形式为:intA[10];intB[10],C[15];//多个数组定义intE[10],m,n,F[15];//数组和变量混合在一起定义元素类型数组名[常量表达式],......;56.1.1一维数组的定义►(1)一维数组是由元素类型、数组名和长度组成的构造类型。元素类型指明了存放在数组中的元素的类型,可以是内置数据类型或自定义类型。例如:intA[10],B[20];//元素是整型doubleF1[8],F2[10];//元素是双精度浮点型charS1[80],S2[80];//元素是字符型66.1.1一维数组的定义►(2)数组名必须符合C语言标识符规则。►(3)常量表达式的值必须为整型且大于等于1,表示数组中元素的个数,称为数组长度。例如“intA[10]”表示数组有10个元素。►(4)数组一经定义,数组长度就始终不变。如果希望数组能存储更多的数据,只能修改定义重新编译。76.1.1一维数组的定义►2.一维数组的内存形式►一维数组是指定类型元素的指定数目的数据集合,它的每个元素数据类型都相同,因而元素的内存形式也是相同的。C语言规定数组元素是连续存放的,即在内存中一个元素紧跟着一个元素线性排列,所以一维数组的内存形式就是多个元素内存形式连续排列的结果。如图所示。86.1.2一维数组的初始化►一维数组的初始化►可以在一维数组对象定义时对它进行初始化,初始化的语法形式如下:intA[5]={1,2,3,4,5},B[3]={7,8,9};//一维数组初始化元素类型数组名[常量表达式]={初值列表},......;96.1.2一维数组的初始化►(1)初值列表的大括号“{}”是必需的,初值按一维数组内存形式中的元素排列顺序一一对应初始化。例如:intA[5]={1,8,9,-3,-5};106.1.2一维数组的初始化►(2)初值列表提供的元素个数不能超过数组长度,但可以小于数组长度。如果初值个数小于数组长度,则只初始化前面的数组元素,剩余元素初始化为0。例如:intA[5]={1,8,9};116.1.2一维数组的初始化►(3)在提供了初值列表的前提下,数组定义时可以不用指定数组长度,编译器会根据初值个数自动确定数组的长度。例如:intA[]={1,8,9};126.1.2一维数组的初始化►下面的表达式能够计算出数组A的长度:sizeofA/sizeof(int)//数组内存长度/元素内存长度=数组长度136.1.2一维数组的初始化►(4)数组初始化的规则与对象初始化规则相同。►若数组未进行初始化,那么在函数体外定义的静态数组对象,其元素均初始化为0;►在函数体内定义的动态数组对象,其元素没有初始化,为一个随机值。146.1.3一维数组的引用►一维数组的引用►数组对象必须先定义后使用,且只能逐个引用数组元素的值而不能一次引用整个数组全部元素的值。►数组元素引用是通过下标得到的,一般形式为:数组名[下标表达式]156.1.3一维数组的引用表6-1下标引用运算符运算符功能目结合性用法[]下标引用单目自左向右object[expr]下标引用运算符在所有运算符中优先级较高,其作用是引用数组对象中的指定元素,运算结果为左值(即元素本身),因此可以对运算结果做赋值、自增自减、取地址等运算。intA[5]={1,2,3,4,5},x;x=A[2];//x=3A[1]=10;//给A[1]元素赋值,则数组A变为{1,10,3,4,5}A[2]++;//A[2]元素自增运算,则数组A变为{1,10,4,4,5}166.1.3一维数组的引用►(1)object必须是数组名,expr为下标表达式,表示数组元素的索引。►下标表达式可以是常量、变量及其表达式,但必须是无符号整型数据,不允许为负。►数组元素下标总是从0开始,与其内存形式对应。►约定数组最前面的元素称为第0个元素,其余依次为第1个元素,第2个元素,......。176.1.3一维数组的引用►(2)下标值不能超过数组长度,否则导致数组下标越界的严重错误。例如:intA[5]={1,2,3,4,5};A[5]=10;//错误,没有A[5]元素186.1.3一维数组的引用注意:数组下标越界会使数据存取超过程序合法的内存空间,这样就可能会改写其他函数栈空间的数据,进而产生很严重的异常错误,甚至引起程序崩溃。C语言编译器不会检查数组是否越界,需要程序员自己小心控制。196.1.3一维数组的引用►(3)整个数组不允许进行赋值运算、算术运算等操作,只有元素才可以,例如:intA[10],B[10],C[10];A=B;//错误A=B+C;//错误A[0]=B[0];//正确,数组元素赋值A[2]=B[2]+C[2];//正确,数组元素赋值206.1.3一维数组的引用►从数组的内存形式来看,数组元素的下标是有序递增的,这个特点使得可以利用循环来批量处理数组元素。►(1)遍历数组元素►利用循环逐个引用数组元素。►(2)数组元素复制►利用循环通过元素逐个赋值,可以达到两个数组“赋值”的效果。216.1.3一维数组的引用例6.11#includestdio.h2intmain()3{4inti,A[100];//定义100个整型5for(i=0;i100;i++)6scanf(%d,&A[i]);7for(i=100-1;i=0;i--)8printf(%d,A[i]);9return0;10}226.1.3一维数组的引用例6.21#includestdio.h2intmain()3{4intA[5]={1,2,3,4,5},B[5],i;5for(i=0;i5;i++)6B[i]=A[i];//元素一一复制7return0;8}236.2多维数组的定义和引用►1.多维数组的定义►C语言允许定义多维数组,其中二维数组的定义形式为:元素类型数组名[常量表达式1][常量表达式2],......;元素类型数组名[常量表达式1][常量表达式2]…[常量表达式n],......;intA[3][4];//定义二维数组intB[3][4][5];//定义三维数组intC[3][4][5][6];//定义四维数组246.2.1多维数组的定义►本质上,C语言的多维数组都是一维数组,这是由内存形式的线性排列决定的。因此,不能按几何中的概念来理解多维,多维数组不过是借用“维”的数学说法表示连续内存单元。►多维定义实际上是反复递归一维定义:即N维数组是一个集合,包含多个元素,每一个元素又是一个N-1维数组。256.2.1多维数组的定义►intA[3][4];►①若A是二维数组,则A[0]、A[1]、A[2]是它的元素,是一维数组。►②若A[0]是一维数组,则A[0][0]、A[0][1]、A[0][2]、A[0][3]是它的元素。►③A[0]的下一个是A[1],A[1]的下一个是A[2],其余依次类推。►④A[0][0]的下一个A[0][1],A[0][3]的下一个是A[1][0],其余依次类推。266.2.1多维数组的定义图6.2二维数组的内存结构2.多维数组的内存形式C语言在编译时会将任何多维数组的引用转化为一维数组的形式。276.2.2多维数组的初始化►多维数组的初始化►可以在多维数组对象定义时对它进行初始化,这里以二维数组来说明,初始化有两种形式。►①初值按多维形式给出:元素类型数组名[常量表达式1][常量表达式2]={{初值列表1},{初值列表2},...};286.2.2多维数组的初始化►多维数组的初始化►②初值按一维形式给出:元素类型数组名[常量表达式1][常量表达式2]={初值列表};①intA[2][3]={{1,2,3},{4,5,6}};//初值按二维形式②intA[2][3]={1,2,3,4,5,6};//初值按一维形式296.2.2多维数组的初始化►(1)可以用一维初值形式来对二维数组初始化,►本质上是因为二维数组的内存形式就是一维数组的内存形式。不过一维形式的初值写法不如二维形式清晰,元素对应关系不容易直接看出。306.2.2多维数组的初始化►(2)初值列表提供的元素个数不能超过数组长度,但可以小于数组长度。如果初值个数小于数组长度,则只初始化前面的数组元素;剩余元素初始化为0。这个规则两种初始化形式都适用,例如://只对每行的前若干个元素赋初值intA[3][4]={{1},{1,2},{1,2,3}};316.2.2多维数组的初始化//只对前若干行的前若干个元素赋初值intA[3][4]={{1},{2}};326.2.2多维数组的初始化//一维形式部分元素赋初值intA[3][4]={1,2,3,4,5};336.2.2多维数组的初始化►(3)在提供了初值列表的前提下,多维数组定义时可以不用指定第1维的数组长度,但其余维的长度必须指定,编译器会根据列出的元素个数自动确定第1维的长度。例如:intA[][2][3]={1,2,3,4,5,6,7,8,9,10,11,12};//正确intB[2][][3]={1,2,3,4,5,6,7,8,9,10,11,12};//错误,只能省略第1维intC[2][2][]={1,2,3,4,5,6,7,8,9,10,11,12};//错误,只能省略第1维346.2.2多维数组的初始化为什么其余维的长度必须要指定呢?因为编译器需要确认多维数组的结构是唯一的例如二维数组总共有12个元素,那么就会有2×6、3×4、4×3、6×2等不同形式的结构,指定了第2维为4,编译器就能确定二维数组是3×4。356.2.2多维数组的初始化►(4)如果多维数组未进行初始化,那么在函数体外定义的静态数组对象,其元素均初始化为0;在函数体内定义的动态数组对象,其元素没有初始化,为一个随机值。366.2.3多维数组的引用►多维数组的引用►多维数组元素的引用与一维类似,也只能逐个引用数组元素的值而不能一次引用整个数组对象全部元素的值,引用的一般形式为:数组名[下标表达式1][下标表达式2]…[下标表达式n]376.2.3多维数组的引用►下标表达式用来索引元素在数组中的位置,可以是常量、变量及其表达式,但必须是无符号整型数据,不允许为负。►每个维的下标总是从0开始,与其内存形式对应,而且相互独立。►相互独立是指多维数组中的多个下标表达式相互是不关联的,各自索引在本维上的元素。386.2.3多维数组的引用intA[3][4]={1,2,3},x;x=A[0][1];//x=2A[2][2]=50;//则数组A变为396.2.3多维数组的引用例6.31#includestdio.h2intmain()3{4intA[3][4],i,j;5for(i=0;i3;i++)6for(j=0;j4;j++)7scanf(%d,&A[i][j]);8for(i=0;i3;i++){9for(j=0;j4;j++)//内循环输出一行10printf(%d,A[i][j]);11printf(\n);//每输出一行换行12}13return0;14}406.2.3多维数组的引用►之所以要用到双重循环,原因是A[i][j]的下标i和j各自都要在本维上遍历,彼此不关联,需要逐一枚举,从而能够遍历所有的二维数组元素。416.2.3多维数组的引用►【例6.4】求矩阵的转置矩阵:426.2.3多维数组的引用例6.41#includestdio.h2intmain()3{4intA[2][3]={{1,2,3},{4,5,6}},AT[3][2],i,j;5for(i=0;i2;i++)//求矩阵A的转置6