560 likes | 737 Views
第七章 数组. 前面所用到的数据均为基本类型 ( 整、实、字符 ) ,为了丰富数据类型 ,须提供强有力的数据表达方式。 C 语言提供了一种构造类型数据 ––– 由基本类型按某一规则组合在一起。. 其中数组:同一种 ( 基本 ) 类型按一定顺序组合在一起的数据类型。. §7.1 一维数组. 7.1.1 一维数组的定义. 形式 : 类型说明符 数组名 [ 常量表达式 ];. 例 : int a [20]; float x [100];. 1. 数组名的确定方法同变量名。. 2. C 语言用方括号 [ ] 表示数组元素个数。.
E N D
第七章 数组 前面所用到的数据均为基本类型(整、实、字符),为了丰富数据类型 ,须提供强有力的数据表达方式。C语言提供了一种构造类型数据–––由基本类型按某一规则组合在一起。 其中数组:同一种(基本)类型按一定顺序组合在一起的数据类型。
§7.1一维数组 7.1.1 一维数组的定义 形式: 类型说明符 数组名[常量表达式]; 例: int a [20]; float x [100]; 1. 数组名的确定方法同变量名。 2. C语言用方括号[ ]表示数组元素个数。
3. 常量表达式为常量和符号常量。不允许有变量,其表达式的值代表了元素的个数。 例: int a[20]; 表示有20个元素 且元素从0开始编排:a[0],a[1],…,a [19]
4. 可在定义时对静态数组和外部存储(全局)数组赋初值, 方法如下: 对全部元素赋初值 static int a[10]={10, 11, 12, 13, 14, 15, 16, 17, 18, 19,} 静态 对部分元素赋初值 static int a[10]={0,1,2,3,4}; 如此,只有前5个元素初值确定,后5个元素由系统设置。
如对数组元素赋同一初值,必须一一写出: static int a[10]={0,0,0,0,0,0,0,0,0,0}; 不可写成: static int a[{10*0}]; × 若赋全部元素的初值,可省略常量表达式 …a [ ]={0,1,2,3}; 表示a[4],即只有4个元素。
7.1.2 一维数组的引用 1. 须象使用变量那样,先定义,后使用 2. 引用方式: 数组名[下标] 其中的下标为整型表达式,但不得越界。 数组引用代表了一个元素,等价一个同类型的变量。 例: a [0]5+a[1] 6 为正确的算术表达式 3. 一般地,一维数组各元素分配在连续的内存单元之中。
例7.1:给 a[0] ~ a[9] 赋值 0 ~9,然后按逆序输出。 main( ) { int i,a[10]; for (i=0;i<=9;i++) a[i]=i; for (i=9;i>=0;i--) printf(“%4d”,a[i]); printf(“\n”); }
7.1.3 一维数组的应用 例7.2:求Fibonacci 数列。 定义数组,并赋初值 static int f [20]={1,1}; 用循环for实现: for (i=2; i<20; i++) f [i]=f [i –2]+f [i –1]; 注意:下标界限问题:i =2且i<20
1 8 89 987 1 13 144 1597 2 21 133 1584 3 34 377 4181 5 55 610 6765 程序如下: main() { int i; static 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] ) } } 运行结果如下:
打印: 每5个数换一行。 for (i=0; i<20; i++) { if (i%5= =0) printf(" \n "); printf (" %12d ", f [i]); }
例2:排序问题–––计算机处理数据的一个重要问题例2:排序问题–––计算机处理数据的一个重要问题 排序算法较多,一种最简单的算法–––选择排序法用得较多。基本思路: 设有n个数,需将它们从小到大顺序排列。则: 1. 从n个元素中,通过比较,找出最小元素,放在第一个位置上。 2. 在剩下的n –1个元素中,找出第二小的元素并把它放在第二个位置上。 3. 对上述过程重复,直至剩下一个元素。
例如: 8, 4, 20, 100, 28, 1, 第1次: 4, 8, 20, 100, 28, 1 1, 8, 20, 100, 28, 4 两次交换 第2次: 1, 4, 20, 100, 28, 8 –––一次交换 第3次: 1, 4, 8, 100, 28, 20 –––一次交换 第4次: 1, 4, 8, 28, 100, 20, 1, 4, 8, 20, 100, 28 两次交换 第5次: 1, 4, 8, 20, 28, 100 –––一次交换
初始化 输入n个元素a数组 i1 B ji+1 A No a[i]>a[j] Yes 交换a[i] a[j] 从以上例子可以看到: 用到两种循环,第一种循环––找第i小的元素,第二种循––对其后的元素的一一比较。 流程图:
jj+1 内循环 No A j>n Yes ii+1 外循环 No B i> n–1 Yes 打印结果 结束
程序: main() { int a [11]; int i, j, t; printf (" please input 10 numbers:\n "); for (i=1; i<=10; i++) scanf("%d", &a[i]); printf(" \n "); for (i=1; i<=9; i++) for (j=i+1; j<=10; j++) if (a[i]>a[j]) { t=a[i]; a[i]=a[j]; a[j]=t;} printf (" the sorted numbers: \n "); for (i=1; i<=10; i++) printf(" %d ", a[i]); printf(" \n " ); } 思考:此算法还可改进!
程序: main() { int a [11]; int i, j, t,minj; printf (" please input 10 numbers:\n "); for (i=1; i<=10; i++) scanf("%d", &a[i]); printf(" \n "); for(i=1;i<=9;i++) {minj=i; for(j=i+1;j<=10;j++) if(a[j]<a[minj]) minj=j;if(minj!=i) {t=a[i];a[i]=a[minj];a[minj]=t;} }printf (" the sorted numbers: \n "); for (i=1; i<=10; i++) printf(" %d ", a[i]); printf(" \n " ); }
(1)若a0>a1,则a0、a1交换;(使a1为a0,a1的大者)(2)若a1>a2,则a1、a2交换;(使a2为a1,a2的大者)…(i) 若ai-1>ai,则ai-1、ai交换;(使ai为ai-1,ai的大者)按照这种方法运算下去,数组中的最大元一定可以移动到最后一个下标位置! 另一种排序法:冒泡排序法(教材例7.3) 相邻元素比较大小,发生交换,使最大值(最小值)“浮出”到数组尽头:
冒泡排序举例: 初始序列为49,38,65,97,76,13,27,49’由小到大排序 第1趟冒泡:38 49 65 76 13 27 49’ [97] 第2趟冒泡:38 49 65 13 27 49’ [76 97] 第3趟冒泡:38 49 13 27 49’ [65 76 97] 第4趟冒泡:38 13 27 49 [49’ 65 76 97] 第5趟冒泡:13 27 38 [49 49’ 65 76 97] 第6趟冒泡:13 27 [38 49 49’ 65 76 97] 排序结果为:13 27 38 49 49’ 65 76 97
冒泡排序算法: N元数组a[0]~a[N-1]由小到大排序:第1步:找到a[0]~a[N-1]中的最大元浮动到a[N-1];第2步:找到a[0]~a[N-2]中的最大元浮动到a[N-2];第3步:找到a[0]~a[N-3]中的最大元浮动到a[N-3];…第i步:找到a[0]~a[N-i]中的最大元浮动到a[N-i];…第N-1步:找到a[0]~a[1]中的最大元浮动到a[1]。算法停止.
#include “stdio.h”#define N 10 void main(){int a[N],i,j,t;printf(“Input %d int numbers:\n”,N); for(i=0;i<N;i++) scanf(“%d”,a+i);for(i=1;i<N;i++) for(j=0;j<N-i;j++) if(a[j]>a[j+1]) { t=a[j];a[j]=a[j+1];a[j+1]=t; }printf(“Reslut:”);for(i=0;i<N;i++) printf(“%6d”,a[i]);printf(“\n”);} 此处, a+i等价于&a[i]
顺序查找(一种查找方法) main() {int i, a[10],x; for (i=0;i<=9;i++) scanf(“%d”,&a[i]); scanf(“%d”,&x); for (i=0;i<=9;i++) if (a[i]==x) break; if (i<=9) printf (“%d is a [%d] ”,x,i); else printf (“not find %d” ,x); } 例:键盘输入10个数存于数组a[10]中,再输入一数x,查找x在a[10]中的位置。 程序如右:
折半查找(也称为对分查找) 算法: 设a[0]~a[N-1]已升序,待查找元素为x令起点下标 h=0; 终点下标 r=N-1;中点下标 m=(h+r)/2; @当h<=r时执行以下步骤: 若x==a[m]则表明查找成功,a[m]为所找元素;x<a[m],显然x在a[h]~a[m-1]之间,则h不变;r=m-1;m=(h+r)/2;转@ x>a[m],显然x在a[m+1]~a[r]之间,则 r不变;h=m+1;m=(h+r)/2;转@ 若h>r,则表明查找失败. 该算法仅适用于在已排序的数组中快速查找所需要的元素,具有效率高的突出优点。可以证明,当数组长度为n个元素时,该算法的平均比较次数不会超过log2n+1。
/*升序数组a[N]中查找x,找到返回有效下标0~N-1, 查找失败返回-1*/main() {int a[10]={1,2,3,4,5,6,7,8,9,10}; int x,h,r,m;scanf(“%d”,&x);h=0;r=9;m=(h+r)/2; while(h<=r&&x!=a[m]) if(x<a[m]) {r=m-1;m=(h+r)/2;} else { h=m+1;m=(h+r)/2; }if(h>r) printf (“not find %d” ,x); else printf (“%d is a [%d] ”, x,i); }
§7.2 二维数组 7.2.1 二维数组的定义 形式 类型说明符 数组名[常量表达式] [常量表达式] 例: int a[4] [10]; float x[8] [20]; 1. 不可将定义写为int a[4,10]。
2. 可将二维数组的元素看成为若干个特殊的一维数组。 如:int b[3] [4]; 则: 有三个特殊的一维数组b[0],b[1], b[2],每一个又有四个元素: b[0]: b[0][0], b[0][1], b[0][2], b[0][3], b[1]: b[1][0], b[1][1], b[1][2], b[1][3], b[2]: b[2][0], b[2][1], b[2][2], b[2][3],
3. 二维数组的存放方式为: 按行存放。由此可推广 至三维、n维数组的定义和存放。 即: 最右边的下标变化最快。 4. 初始化: 按行给二维数组赋初值: static int a[3][4]={{1,2,3,4}, {5,6,7,8,}, {9,10,11,12,}}; 可以去掉其中的{ }。
则相当于 1 2 0 0 3 0 0 0 8 0 0 0 可以对部分元素赋初值,但需表达清楚。如: static int a[3][4]={{1,2},{3},{8}}。 可通过赋初值决定数组大小。如为二维,则只可省略第一维的大小. static int a[ ][4]={1,2,3,…,12};
7.2.2 二维数组元素的引用 形式: 数组名[下标][下标] 其中的下标为整型表达式,但不得越界。 与一维数组元素一样,二维数组元素相当于同类型的简单变量。
1 4 2 5 3 6 1 2 3 4 5 6 a= b= 7.2.3 程序举例 例1将一个二维数组行和列元素互换,存到另一个二维数组中。例如: 程序如下:
main() { static int a[2] [3]={{1, 2,3},{4, 5,6}}; static int b[3] [2], i, j; 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"); 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 array b: 1 4 2 5 3 6 数组元素数据的输入必须以循环方式进行或者定义时置初值。
max= a[0][0] for i=0 to 2 for j=0 to 3 a[i][j]>max 真 假 max= a[i][j] row=i colum=j 输出:max和row,colum 二维数组一般用二重循环 例2. 有一个3×4的矩阵,要求编程序求出其中值最大的那个元素的值,以及所在的行号和列号。 先用N-S流程图表示算法,见图7.6
据此写出以下程序: main() { int i,j, row=0, colum=0, max; static 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;} printf( "max=%d,row=%d, colum=%d\n ", max, row, colum); } 输出结果为: max=10, row=2, colum=1
§7.3 字符数组 用来存放字符数据。字符串–––用字符数组存放。 7.3.1字符数组的定义 char c[10]; 大小 数组名 类型名 1. 初始化: 直接给出字符串中的各字符 static char a[4]={' G ', ' o ', ' o ', ' d '}; 若字符多于元素个数,则语法错。
可以去掉定义时的大小设置,而通过自动赋值决定 长度(大小)可以去掉定义时的大小设置,而通过自动赋值决定 长度(大小) static char x[ ]={' I ', ' ', ' a ', ' m ', ' ', 'a', ' ', ' s ', ' t ', ' u ', ' d ', ' e ', ' n ', ' t '}; 前面说过,字符串常量用“ ” 表示,且由‘ \0’结尾. static char x[ ]={"I am a student. "}; 则长度为15+1=16, 其中x[15]存放‘\0’,其中 { }亦可省略。 2. 字符数组的引用 每一个字符数组元素相当于一个字符变量。
7.3.2 字符数组的输入输出 格式符: %c –––逐个输入/输出字符。 %s ––– 整个串一次输入/输出。 1. 输出 (用%s) 用%s输出时,不输出‘\0’。 在printf中须直接写数组名. static char c[ ]={"I am a student"}; printf("%s", c);
若数组长度大于字符串长度,则遇到‘ \0’ 即停止输出 static char c[10]=" china"; printf(" %s", c); 输出时遇到第一个‘ \0’即结束。
2. 输入(用%s) 输入字符串时,系统自动加上‘ \0’ 输入多个字符串,可用空格隔开。 Static char str1[5], str2[5], str3[5]; scanf(" %s%s%s", str1, str2,str3); 则:输入 How are you? str1: H o w \0 str2: a r e \0 str3: y o u \0
str: H o w \0 …… 只能输入不包括空格、\t和\n的字符串 若: static char str[13]; scanf("%s", str); 输入: How are you 则只会将How输入,且存为 scanf中须用地址量,数组名表示地址量。
视C的版本而定 7.3.3 字符串处理函数 在使用1、2字符串函数时要包含头文件“stdio.h”。 在使用3-6字符串函数时要包含头文件“string.h”。 1. puts(字符数组名) 输出一个字符串 • 例:static char str[ ]={" China\nBeijing"}; • puts(str); • 输出:China Beijing • 字符串中可包含转义字符 • \0自动转换为\n
2. gets(字符数组名) 功能:输入一个字符串到字符数组 • 例:static char c[6]; • gets(c); • 输入:China↙ • 数组c在内存中实际存放情况为: 串长=5 C H I N A \0 c[0] c[1] c[2] c[3] c[4] c[5]
x y ... z \0 a b c d e f g \0 3. strcat(字符数组名1,字符数组名2) 功能:连接两个字符数组中的字符串,串2接在串1的后面 str2 • 例:char str1[30]=“xyxyz”;char str2[]=“abcdefg”; printf(“%s”,strcat(str1,str2)); • 输出: xyxyzabcdefg • 字符数组1要足够长。 • 根据字符串1中 \0 的位置进行字符串连接。 • 关键:要用str2的第1个字符覆盖str1的串结束标记\0。 ... ... ... a b c d e f g \0 str1
a b ... ... ... f g \0 4. strcpy(字符数组名1,字符串2) 功能:将字符串2复制到字符数组1中去 • 例:char str1[10] ;char str2[10]=“abcdefg”;strcpy(str1,str2); printf(“%s”,str1); • 输出: abcdefg 没有必要复制整个数组,根据字符串中 \0 的位置,只对\0前面的字符进行复制。 字符串2可以是字符串常量 例: strcpy(str1, "China"); str1 ... ... ... str2 a b ... ... ... f g \0
5. strcmp (字符串1,字符串2) 功能:比较字符串1和字符串2 确定字符串大小的基本规则:按照串中对应位置字符的ASCII码值的大小确定大小。 例如:”abc” < ”b”因为字符 a < b ”abc” > ”abadef”因为字符 c > a 例:strcmp(str1,str2); strcmp(“China”,”Korea”); strcmp(str1,”beijing”);
结果由函数值带回: 字符串1=字符串2,函数值为0;字符串1>字符串2,函数值为正;字符串1<字符串2,函数值为负; 例:当str1=str2时,打印输出“yes” if(str1==str2) printf(“yes”); × if(strcmp(str1,str2)==0) printf(“yes”); √
6. strlen(字符数组名) 功能:测试字符串长度 例:char str [10] =“China”;printf(“%d”,strlen(str)); 输出结果: 5
7.3.4 字符串数组举例 例:输入一行字符,统计其中有多少个单词,单词之间用空格分隔开。 程序如下:
# include "stdio.h" main ( ) {char string[81]; int i, num=0, word=0; char c; gets (string); for (i=0; (c=string[i])!= '\0 '; i++) if ( c= = ' ')word=0; else if (word = =0) {word=1; num++;} printf("There are %d words in the line \n ", num); }
运行情况如下: I am a boy. There are 4 words in the line
length=0 length=1 length=2 a b c d e f g \0 串长 例:求字符串长度 • 根据字符串中 \0 的位置来计算字符串长度。 • 若:数组中第i 个元素为\0,则,串长=i。 • #include <stdio.h> • main ( ) • { intlength; • char line[100]; • gets(line); • length=0; • while( line[length] != ’\0’) • length++; • printf (”String length=%d”, length); • } length=7