1 / 80

7.1  一维数组的定义和引用 7.2  二维数组的定义和引用 7.3  字符数组 习题

第 7 章 数 组. 7.1  一维数组的定义和引用 7.2  二维数组的定义和引用 7.3  字符数组 习题. 迄今为止,我们使用的都是属于基本类型 ( 整型、字符型、实型 ) 的数据, c 语言还提供了构造类型的数据,它们有:数组类型、结构体类型、共用体类型。构造类型数据是由基本类型数据按一定规则组成的,因此有的书称它们为 “ 导出类型 ” 。 本章只介绍数组。数组是有序数据的集合。数组中的每一个元素都属于同一个数据类型。用一个统一的数组名和下标来唯一地确定数组中的元素。有关数组的概念和其他高级语言中介绍的是相同的,不再赘述。本章只介绍 c 语言中如何定义和使用数组。.

deliz
Download Presentation

7.1  一维数组的定义和引用 7.2  二维数组的定义和引用 7.3  字符数组 习题

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第7章 数 组 7.1 一维数组的定义和引用 7.2 二维数组的定义和引用 7.3 字符数组 习题

  2. 迄今为止,我们使用的都是属于基本类型(整型、字符型、实型)的数据,c语言还提供了构造类型的数据,它们有:数组类型、结构体类型、共用体类型。构造类型数据是由基本类型数据按一定规则组成的,因此有的书称它们为“导出类型”。迄今为止,我们使用的都是属于基本类型(整型、字符型、实型)的数据,c语言还提供了构造类型的数据,它们有:数组类型、结构体类型、共用体类型。构造类型数据是由基本类型数据按一定规则组成的,因此有的书称它们为“导出类型”。 本章只介绍数组。数组是有序数据的集合。数组中的每一个元素都属于同一个数据类型。用一个统一的数组名和下标来唯一地确定数组中的元素。有关数组的概念和其他高级语言中介绍的是相同的,不再赘述。本章只介绍c语言中如何定义和使用数组。

  3. 7.1 一维数组的定义和引用 7.1.1 一维数组的定义 一维数组的定义方式为类型说明符 数组名[常量表达式]; 例如: int a[10]; 它表示数组名为a,此数组有10个元素。 说明: (1) 数组名定名规则和变量名相同,遵循标识符定名规则。 (2) 数组名后是用方括弧括起来的常量表达式,不能用圆括弧,下面用法不对:int a(10);

  4. (3) 常量表达式表示元素的个数,即数组长度。例如,在a[10]中,10表示a数组有10个元素,下标从0开始,这10个元素是,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]。注意不能使用数组元素a[10]。 (4) 常量表达式中可以包括常量和符号常量,不能包含变量。也就是说,c不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值。例如,下面这样定义数组是不行的: int n; scanf("%d",&n); int a[n];

  5. 7.1.2 一维数组元素的引用 数组必须先定义,然后使用。c语言规定只能逐个引用数组元素而不能一次引用整个数组。 数组元素的表示形式为数组名[下标] 下标可以是整型常量或整型表达式。例如: a[0]=a[5]+a[7]-a[2*3] 例7.1数组元素的引用。 main() { int i,a[10]; for (i=0; i<=9;i++)

  6. a[i]=i; for(i=9;i>=0; i--) printf("%d ",a[i]); } 运行结果如下: 9 8 7 6 5 4 3 2 1 0 程序使a[0]到a[9]的值为0~9,然后按逆序输出。

  7. 7.1.3 一维数组的初始化 对数组元素的初始化可以用以下方法实现: (1) 在定义数组时对数组元素赋以初值。例如: int a[10]={0,1,2,3,4,5,6,7,8,9}; 将数组元素的初值依次放在一对花括弧内。经过上面的定义和初始化之后,a[0]=0,a[1]=1,a[2]=2,a[3]=3,a[4]=4,a[5]=5,a[6]=6,a[7]=7,a[8]=8,a[9]=9。 (2) 可以只给一部分元素赋值。例如: int a[10]={0,1,2,3,4}; 定义a数组有10个元素,但花括弧内只提供5个初值,这表示只给前面5个元素赋初值,后5个元素值为0。

  8. (3) 如果想使一个数组中全部元素值为0,可以写成 int a[10]={0,0,0,0,0,0,0,0,0,0};  不能写成 int a[10]={0*10}; 这是与FORTRAN语言不同的,不能给数组整体赋初值。 (4) 在对全部数组元素赋初值时,可以不指定数组长度。例如: int a[5]={1,2,3,4,5};  可以写成 int a[]={1,2,3,4,5} 在第二种写法中,花括弧中有5个数,系统就会据此自动定义a数组的长度为5。

  9. 但若被定义的数组长度与提供初值的个数不相同,则数组长度不能省略。例如,想定义数组长度为10,就不能省略数组长度的定义,而必须写成但若被定义的数组长度与提供初值的个数不相同,则数组长度不能省略。例如,想定义数组长度为10,就不能省略数组长度的定义,而必须写成 int a[10]={1,2,3,4,5}; 只初始化前5个元素,后5个元素为0。 7.1.4 一维数组程序举例 例7.2用数组来处理求fibonacci数列问题。 程序如下: main()

  10. { int i; int f[20]={1,1}; for(i=2;i<20;i++) f[i]=f[i-2]+f[i-1]; for(i=0;i<20;i++) { if(i%5==0) printf("\n"); printf("%12d",f[i]); } }

  11. 运行结果如下: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 if语句用来控制换行,每行输出5个数据。 例7.3用起泡法对10个数排序(由小到大)。 起泡法的思路是:将相邻两个数比较,将小的调到前头。见图7.1。

  12. 图7.1 图7.2

  13. 若有6个数。第一次将8和9对调,第二次将第2和第3个数(9和5)对调……如此共进行5次,得到854209的顺序,可以看到:最大的数9已“沉底”,成为最下面一个数,而小的数“上升”。最小的数0已向上“浮起”一个位置。经第一趟(共5次)后,已得到最大的数。然后进行第二趟比较,对余下的前面5个数按上法进行比较,见图7.2。经过4次比较,得到次大的数8。如此进行下去。可以推知,对6个数要比较5趟,才能使6个数按大小顺序排列。在第一趟中要进行两个数之间的比较共5次,在第二趟中比4次……第5趟比1次。如果有n个数,则要进行n-1趟比较。在第1趟比较中要进行n-1次两两比较,在第j趟比较中要进行n-j次两两比较。据此画出流程图(见图7.3)。根据流程图写出程序(今设n=10),定义数组长度为11,本例中对a[0]不用,只用a[1]到a[10],以符合人们的习惯。若有6个数。第一次将8和9对调,第二次将第2和第3个数(9和5)对调……如此共进行5次,得到854209的顺序,可以看到:最大的数9已“沉底”,成为最下面一个数,而小的数“上升”。最小的数0已向上“浮起”一个位置。经第一趟(共5次)后,已得到最大的数。然后进行第二趟比较,对余下的前面5个数按上法进行比较,见图7.2。经过4次比较,得到次大的数8。如此进行下去。可以推知,对6个数要比较5趟,才能使6个数按大小顺序排列。在第一趟中要进行两个数之间的比较共5次,在第二趟中比4次……第5趟比1次。如果有n个数,则要进行n-1趟比较。在第1趟比较中要进行n-1次两两比较,在第j趟比较中要进行n-j次两两比较。据此画出流程图(见图7.3)。根据流程图写出程序(今设n=10),定义数组长度为11,本例中对a[0]不用,只用a[1]到a[10],以符合人们的习惯。

  14. 图7.3

  15. main() { int a[11]; int i,j,t; printf("input 10 numbers :\n"); for (i=1;i<11;i++) scanf("%d",&a\[i\]); printf("\n"); for(j=1;j<=9;j++) for(i=1;i<=10-j;i++) if (a[i]>a[i+1])

  16. {t=a\[i\];a\[i\]=a\[i+1];a[i+1]=t;} printf("the sorted numbers :\n"); for(i=1;i<11;i++) printf("%d ",a[i]); } 运行情况如下: input 10 numbers: 1 0 4 8 12 65 -76 100 -45 123 the sorted numbers: -76 -45 0 1 4 8 12 65 100 123

  17. 7.2二维数组的定义和引用 7.2.1 二维数组的定义 二维数组定义的一般形式为类型说明符 数组名[常量表达式][常量表达式]。 例如:float a[3][4],b[5][10]; 定义a为3×4(3行4列)的数组,b为5×10(5行10列)的数组。注意不能写成 float a[3,4],b[5,10]; c语言对二维数组采用这样的定义方式,使我们可以把二维数组看作是一种特殊的一维数组:它的元素又是一个一维数组。例如,可以把a看作是一个一维数组,它有3个元素:a[0]、a[1]、

  18. a[2],每个元素又是一个包含4个元素的一维数组。见图7.4。可以把a[0]、a[1]、a[2]看作是3个一维数组的名字。上面定义的二维数组可以理解为定义了3个一维数组,即相当于 float a[0][4],a[1][4],a[2][4] 图7.5 图7.4

  19. 此处把a[0],a[1],a[2]看作一维数组名。c语言的这种处理方法在数组初始化和用指针表示时显得很方便,这在以后会体会到。此处把a[0],a[1],a[2]看作一维数组名。c语言的这种处理方法在数组初始化和用指针表示时显得很方便,这在以后会体会到。 c语言中,二维数组中元素排列的顺序是:按行存放,即在内存中先顺序存放第一行的元素,再存放第二行的元素。图7.5表示对a[3][4]数组存放的顺序。 c允许使用多维数组。有了二维数组的基础,再掌握多维数组是不困难的。例如,定义三维数组的方法是 float a[2][3][4];

  20. 多维数组元素在内存中的排列顺序:第一维的下标变化最慢,最右边的下标变化最快。例如,上述三维数组的元素排列顺序为多维数组元素在内存中的排列顺序:第一维的下标变化最慢,最右边的下标变化最快。例如,上述三维数组的元素排列顺序为 a[0][0][0]→a[0][0][1]→a[0][0][2]→a[0][0][3]→a[0][1][0]→a[0][1][1]→a[0][1][2]→a[0][1][3]→a[0][2][0]→a[0][2][1]→a[0][2][2]→a[0][2][3]→a[1][0][0]→a[1][0][1]→a[1][0][2]→a[1][0][3]→a[1][1][0]→a[1][1][1]→a[1][1][2]→a[1][1][3]→a[1][2][0]→a[1][2][1]→a[1][2][2]→a[1][2][3]

  21. 7.2.2 二维数组的引用 二维数组的元素的表示形式为 数组名[下标][下标] 如a[2][3]。下标可以是整型表达式,如a[2-1][2*2-1]。不要写成a[2,3],a[2-1,2*2-1]形式。 数组元素可以出现在表达式中,也可以被赋值,例如: b[1][2]=a[2][3]/2 在使用数组元素时,应该注意下标值应在已定义的数组大小的范围内。常出现的错误是

  22. int a[3][4]; … a[3][4]=3; 定义a为3×4的数组,它可用的行下标值最大为2,列下标值最大为3。用a[3][4]超过了数组的范围。 请读者严格区分在定义数组时用的a[3][4]和引用元素时的a[3][4]的区别。前者a[3][4]用来定义数组的维数和各维的大小,后者a[3][4]中的3和4是下标值,a[3][4]代表某一个元素。

  23. 7.2.3 二维数组的初始化 可以用下面的方法对二维数组初始化: (1) 分行给二维数组赋初值。如 int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 这种赋初值方法比较直观,把第1个花括弧内的数据给第1行的元素,第2个花括弧内的数据赋给第2行的元素……即按行赋初值。 (2) 可以将所有数据写在一个花括弧内,按数组排列的顺序对各元素赋初值。如:int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};效果与前相同。但以第1种方法为好,一行对一行,界限清楚。

  24.  用第2种方法如果数据多,写成一大片,容易遗漏,也不易检查。 用第2种方法如果数据多,写成一大片,容易遗漏,也不易检查。 (3) 可以对部分元素赋初值。 int a[3][4]={{1},{5},{9}}; 它的作用是只对各行第1列的元素赋初值,其余元素值自动为0。赋初值后数组各元素为 1 0 0 0 5 0 0 0 9 0 0 0 也可以对各行中的某一元素赋初值: int a[3][4]={{1},{0,6},{0,0,11}};

  25. 初始化后的数组元素如下: 1 0 0 0 0 6 0 0 0 0 11 0 这种方法对非0元素少时比较方便,不必将所有的0都写出来,只需输入少量数据。也可以只对某几行元素赋初值: int a[3][4]={{1},{5,6}}; 数组元素为 1 0 0 0 5 6 0 0 0 0 0 0

  26. 第3行不赋初值。也可以对第2行不赋初值: int a[3][4]={{1},{},{9}}; (4) 如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。如: int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 与下面的定义等价: int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 系统会根据数据总个数分配存储空间,一共12个数据,每行4列,当然可确定为3行。

  27. 在定义时也可以只对部分元素赋初值而省略第一维的长度,但应分行赋初值。如:int a[][4]={{0,0,3},{},{0,10}}; 这样的写法,能通知编译系统;数组共有3行。数组各元素为 0 0 3 0 0 0 0 0 0 10 0 0 从本节的介绍中可以看到:c语言在定义数组和表示数组元素时采用a[][]这种两个方括弧的方式,对数组初始化时十分有用,它使概念清楚,使用方便,不易出错。

  28. 7.2.4 二维数组程序举例 例7.4将一个二维数组行和列元素互换,存到另一个二维数组中。例如: a=1 2 3 b=1 4 4 5 6 2 5 3 6 程序如下: main() { int a[2][3]={{1,2,3},{4,5,6}}; int b[3][2],i,j;

  29. printf("array a:\n"); for (i=0;i<=1;i++) { for (j=0;j<=2;j++) { printf("%5d",a[i][j]); b[j][i]=a[i][j]; } printf("\n"); } printf("array b:\n");

  30. for (i=0;i<=2,i++) { for(j=0;j<=1;j++) printf("%5d",b[i][j]); printf("\n"); } } 运行结果如下: array a: 1 2 3 4 5 6

  31. array b: 1 4 2 5 3 6 例7.5有一个3×4的矩阵,要求编程序求出其中值最大的那个元素的值,以及其所在的行号和列号。先用N-S流程图表示算法,见图7.6。 据此写出以下程序: 图7.6

  32. main() {int i,j,row=0,colum=0,max; int a[3][4]={{1,2,3,4},{9,8,7,6},{-10,10,-5,2}}; max=a[0][0]; for (i=0;i<=2;i++) for (j=0;j<=3;j++) if (a[i][j]>max) {max=a[i][j]; row=i; colum=j; }

  33. printf("max=%d,row=%d,colum=%d\n",max,row,colum);printf("max=%d,row=%d,colum=%d\n",max,row,colum); } 输出结果为: max=10,row=2,colum=1 由于数值型数组的概念和应用与其他高级语言差不多,读者比较熟悉,因此不再赘述。

  34. 7.3 字符数组 用来存放字符数据的数组是字符数组。字符数组中的一个元素存放一个字符。 7.3.1 字符数组的定义 定义方法与前面介绍的类似。例如: char c[10]; c[0]='I';c[1]=' ';c[2]='a';c[3]='m';c[4]=' ';c[5]='h';c[6]='a';c[7]=’p';c[8]=’p';c[9]='y'; 定义c为字符数组,包含10个元素。在赋值以后数组的状态如图7.7所示。

  35. 图7.7 也可以用整型数值来存放字符型数据,因此上面第一行也可以改用: int c[10];/*合法,但浪费存储空间*/

  36. 7.3.2 字符数组的初始化 对字符数组初始化,最容易理解的方式是逐个字符赋给数组中各元素。如:char c[10]={'I',' ','a','m',' ','h','a','P','P','y'};把10个字符分别赋给c[0]到c[9]10个元素。 如果花括弧中提供的初值个数(即字符个数)大于数组长度,则按语法错误处理。如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素,其余的元素自动定为空字符(即'\0')。如: char c[10]={'c',' ','P','r','o','g','r','a','m'}; 数组状态如图7.8所示。

  37. 图7.8 如果提供的初值个数与预定的数组长度相同,在定义时可以省略数组长度,系统会自动根据初值个数确定数组长度。如: char c[]={'I',' ','a','m',' ','h','a','p','p','y'};

  38. 数组c的长度自动定为10。用这种方式可以不必人工去数字符的个数,尤其在赋初值的字符个数较多时,比较方便。数组c的长度自动定为10。用这种方式可以不必人工去数字符的个数,尤其在赋初值的字符个数较多时,比较方便。 也可以定义和初始化一个二维字符数组,如: char diamond[5][5]={{' ',' ','*'},{' ','*',' ','*'}, {'*',' ',' ',' ','*'},{' ','*',' ','*'},{' ',' ','*'}}; 用它代表一个钻石形的平面图形,见图7.9。完整的程序见例7.7。 图7.9

  39. 例7.6输出一个字符串。 main() {char c[10]={'I',' ','a','m',' ','a',' ','b','o','y'}; int i; for(i=0;i<10;i++) printf("%c",c[i]); printf("\n"); } 运行结果: I am a boy

  40. 例7.7输出一个钻石图形。main() {char diamond[][5]={{'','','*'},{'','*','','*'},{'*','','','','*'},{'','*','','*'},{'','','*'}}; int i,j; for (i=0;i<5;i++) {for (j=0;j<5;j++) printf("%c",diamond[i][j]); printf("\n"); } } 运行结果为:

  41. 7.3.4 字符串和字符串结束标志 在c语言中,将字符串作为字符数组来存放。例7.6就是用一个一维的字符数组存放一个字符串“I am a boy”中的字符。这个字符串的实际长度与数组长度相等。有时,人们关心的是有效字符串的长度而不是字符数组的长度。例如,定义一个字符数组长度为100,而实际有效字符只有40个。为了测定字符串的实际长度,c语言规定了一个“字符串结束标志”,以字符‘\0’代表。如果有一个字符串,其中第10个字符为‘\0’,则此字符串的有效字符为9个。也就是说,在遇到字符‘\0’时,表示字符串结束,由它前面的字符组成字符串。

  42. 系统对字符串常量也自动加一个‘\0’作为结束符。例如“c Program”共有9个字符,但在内存中占10个字节,最后一个字节‘\0’是由系统自动加上的。字符串作为一维数组存放在内存中。 有了结束标志‘\0’后,字符数组的长度就显得不那么重要了。在程序中往往依靠检测‘\0’的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串长度。当然,在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串实际长度。如果在一个字符数组中先后存放多个不同长度的字符串,则应使数组长度大于最长的字符串的长度。

  43. 说明:‘\0’代表ASCII码为0的字符,从ASCII码表中可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。说明:‘\0’代表ASCII码为0的字符,从ASCII码表中可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。 我们以前曾用过以下的语句: printf("How do you do?\n"); 即输出一个字符串。在执行此语句时系统怎么知道应该输出到哪里为止呢?实际上,在内存中存放时,系统自动在最后一个字符‘\n’的后面加了一个‘\0’作为字符串结束标志,在执行printf函数时,每输出一个字符检查一次,看下一个字符是否‘\0’。遇‘\0’就停止输出。

  44. 对c语言处理字符串的方法有以上的了解后,我们再对字符数组初始化的方法补充一种方法,可以用字符串常量来使字符数组初始化。例如char c[]={"I am happy"};也可以省略花括弧,直接写成 char c[]="I am happy"; 不是用单个字符作为初值,而是用一个字符串(注意字符串的两端是用双引号而不是单引号括起来的)作为初值。显然,这种方法直观、方便、符合人们的习惯。数组c的长度不是10,而是11,这点务请注意。因为字符串常量的最后由系统加上一个‘\0’。因此,上面的初始化与下面的初始化等价。

  45. char c[] ={'I',' ','a','m',' ','h','a','p','p','y','\0'}; 而不与下面的等价: char c\[]={'I',' ','a','m',' ','h','a','p','p','y'}; 前者的长度为11,后者的长度为10。如果有char c[10]={"china"}; 数组c的前5个元素为'c','h','i','n','a',第6个元素为‘\0’,后4个元素为空字符。见图7.10。

  46. 图7.10 需要说明的是:字符数组并不要求它的最后一个字符为‘\0’,甚至可以不包含‘\0’。像以下这样写完全是合法的: char c[5]={'c','h','i','n','a'}; 是否需要加‘\0’,完全根据需要决定。但是由于系统对字符串常量自动加一个‘\0’。 因此,人们为了使处理方法一致,便于测定字符串的实际长度,以及在程序中作相应的处理,在字符数组也常常人为地加上一个‘\0’。如: char c[6]={'c','h','i','n','a','\0'};

  47. 7.3.5 字符数组的输入输出 字符数组的输入输出可以有两种方法: (1) 逐个字符输入输出。用格式符“%c”输入或输出一个字符,如例7.6。 (2) 将整个字符串一次输入或输出。用“%S”格式符,意思是输出字符串(String)。例如: char c[]={"china"}; printf("%S",c); 在内存中数组c的状态如图7.11所示。输出时,遇结束符‘\0’就停止输出。输出结果为: china china\0

  48. 图7.11 请注意: (1) 输出字符不包括结束符‘\0’。 (2) 用“%S”格式符输出字符串时,printf函数中的输出项是字符数组名,而不是数组元素名。写成下面这样是不对的: printf("%S",c[0]); (3) 如果数组长度大于字符串实际长度,也只输出到遇‘\0’结束。如char c[10]={"china"}; printf("%S",c);

  49. 也只输出“china”5个字符,而不是输出10个字符。这就是用字符串结束标志的好处。也只输出“china”5个字符,而不是输出10个字符。这就是用字符串结束标志的好处。 (4) 如果一个字符数组中包含一个以上‘\0’,则遇第一个‘\0’时输出就结束。 可以用scanf函数输入一个字符串。例如 scanf("%S",c); scanf函数中的输入项c是字符数组名,它应该在先前已被定义。从键盘输入的字符串应短于已定义的字符数组的长度。例如,已定义 char c[6];

  50. 从键盘输入: china 系统自动在后面加一个‘\0’结束符。如果利用一个scanf函数输入多个字符串,则以空格分隔。例如: char strl[5],Str2[5],Str3[5]; scanf("%S%S%S",Str1,Str2,Str3); 输入数据: How are you?  输入后Str1、Str2、Str3数组状态见图7.12。数组中未被赋值的元素的值是不可预料的。

More Related