550 likes | 736 Views
第 7 章. 数 组. 7.1 一维数组的定义和引用. 7.1.1 一维数组的定义 定义方式为: 类型说明符 数组名[ 常量表达式 ] ; 例如: int a[10]; 定义 a[10] 后, a 数组有 10个元素 ,分别是: a[0], a[1], a[2], a[3], … , a[8], a[9] 在常量表达式中,不能包含变量。即不允许对数组的大小作动态定义。 下面定义是错的: int n ; scanf( “ %d ” , &n); int a[n];.
E N D
第 7章 数 组
7.1 一维数组的定义和引用 7.1.1一维数组的定义 定义方式为: 类型说明符 数组名[ 常量表达式 ] ; 例如: int a[10]; 定义a[10]后,a数组有10个元素,分别是: a[0], a[1], a[2], a[3], … , a[8], a[9] 在常量表达式中,不能包含变量。即不允许对数组的大小作动态定义。下面定义是错的: int n ; scanf(“%d”, &n); int a[n];
说明:数组同变量一样,也必须先定义、后使用。说明:数组同变量一样,也必须先定义、后使用。 1维数组是只有1个下标的数组,定义形式如下: 数据类型 数组名[常量表达式1], 数组名2[常量表达式2]……; (1)“数据类型”是指数组元素的数据类型。 (2)数组名,与变量名一样,必须遵循标识符命名规则.。 (3)“常量表达式”必须用方括号括起来,指的是数组的元素个数(又称数组长度),它是一个整型值,其中可以包含常数和符号常量,但不能包含变量。 注意:C语言中不允许动态定义数组。
特别说明:在数组定义时,“常量表达式”外的方括号;以及元素引用时,“下标表达式”外的方括号,都是C语言语法规则所要求的,不是本书所约定的可选项的描述符号!特别说明:在数组定义时,“常量表达式”外的方括号;以及元素引用时,“下标表达式”外的方括号,都是C语言语法规则所要求的,不是本书所约定的可选项的描述符号! (4)数组元素的下标,是元素相对于数组起始地址的偏移量,所以从0开始顺序编号。 (5)数组名中存放的是一个地址常量,它代表整个数组的首地址。同一数组中的所有元素,按其下标的顺序占用一段连续的存储单元。
7.1.2一维数组元素的引用 数组必须先定义, 后使用。 只能逐个引用数组元素,不能一次引用整个数组。 数组元素的表示形式: 数组名[下标] 下标可以是整型常量,也可以是整型表达式。
例7.1 数组元素的引用。 main ( ) {int n, a[10]; for (n=0;n<=9;n++) a[n]=n ; for (n=9;n>=0;n--) printf(“%d”, a[n]) ; } 运行结果为: 9876543210
7.1.3 一维数组的初始化 (1)在定义数组时对数组元素赋初值。例如: int a[6]={1,3,5,7,9,11}; (2)可以只给一部分元素赋初值。例如: int a[6]={1,3,5}; a[0] ,a[1] ,a[2] 的值分别是1,3,5,其他元素值是0。 (3)若想使数组元素全为零。可以写成: int a[6]={0,0,0,0,0,0}; (4)对全部数组元素赋初值时,可以不指定数组长度。 int b[3]={4,6,8}; 可以写成 int b[ ]={4,6,8};
7.1.4 一维数组程序举例: 例7.2 用数组处理Fibonacci数列。 main ( ) {int n; int f[20]={1,1}; for (n=2;n<20;n++) f[n]=f[n-2]+f[n-1] ; for (n=0;n<=19;n++) {if(n%5==0) printf(“\n”) ; printf(“%12d”, f[n]) ; } }
冒泡法的基本思想:通过相邻两个数之间的比较和交换,使排序码(数值)较小的数逐渐从底部移向顶部,排序码较大的数逐渐从顶部移向底部。就像水底的气泡一样逐渐向上冒,故而得名。冒泡法的基本思想:通过相邻两个数之间的比较和交换,使排序码(数值)较小的数逐渐从底部移向顶部,排序码较大的数逐渐从顶部移向底部。就像水底的气泡一样逐渐向上冒,故而得名。 由A[n]~A[1]组成的n个数据,进行冒泡排序的过程可以描述为: (1)首先将相邻的A[n]与A[n-1]进行比较,如果A[n]的值小于A[n-1]的值,则交换两者的位置,使较小的上浮,较大的下沉;接着比较A[n-1]与A[n-2],同样使小的上浮,大的下沉。依此类推,直到比较完A[2]和A[1]后,A[1]为具有最小排序码(数值)的元素,称第一趟排序结束。 (2)然后在A[n]~A[2]区间内,进行第二趟排序,使剩余元素中排序码最小的元素上浮到A[2];重复进行n-1趟后,整个排序过程结束。
例7.3 用起泡法对10个数由小到大排序。 main () {int i,j,t,a[11]; printf(“input 10 number:\n”); for(i=1;i<=10;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]) {t=a[i];a[i]=a[i+1];a[i+1]=t;} printf(“排序后10个数:\n”); for(i=1;i<=10;i++)printf(“%d ”, a[i]) ; }
运行结果如下:input 10 numbers:1 0 4 8 12 65 –76 100 –45 123the sorted numbers:-76 -45 0 1 4 8 12 65 100 123 第一趟 0 1 4 8 12 -76 65 -45 100 123 第二趟 0 1 4 8 -76 12 -45 65 100 第三趟 0 1 4 -76 8 -45 12 65 第四趟 0 1 -76 4 -45 8 12 第五趟 0 -76 1 -45 4 8 第六趟 -76 0 -45 1 4 第七趟 -76 -45 0 1 |…… 每趟最大的数下沉,即红色的数
例 以下对一维数组a的正确说明是: (A)char a(10); (B)int a[ ]; (C)int k=5,a[k]; (D)char a[ ]={‘a’,’b’,’c’}; 答案:D
7.2 二维数组的定义和引用 7.2.1 二维数组的定义 定义的一般形式为: 类型说明符 数组名[常量表达式1] [常量表达式2] 例如:int a[3][3]; float b[2][3],num[3][5]; 可以把二维数组看作是一种特殊的一维数组:它的元素又是一个一维数组。例把a看作是一个一维数组它有三个元素:a[0]、a[1]、a[2],每个元素又是一个包含3个元素的一维数组。 a[0]……a[0][0] a[0][1] a[0][2] a[1]……a[1][0] a[1][1] a[1][2] a[2]……a[2][0] a[2][1] a[2][2] a
a[0][0] a[0][1] a[0][2]a[1][0] a[1][1] a[1][2]a[2][0] a[2][1] a[2][2]a[0][0] a[0][1] a[0][2]a[1][0] a[1][1] a[1][2]a[2][0] a[2][1] a[2][2] 二维数组在内存中是按行存放。即先放第一行的元素,再放第二行的元素,… 。例上面定义的数组b在内存中的排列顺序如下: b[0][0]、b[0][1]、b[0][2]、 b[1][0]、b[1][1]、b[1][2] C允许使用多维数组。例如int y[2][3][2];
7.2.2 二维数组的引用 二维数组的元素的表示形式: 数组名[下标][下标] 二维数组的元素可以出现在表达式中,也可以被赋值。例: int a[3][4],b[2][4]; a[2][1]=b[0][1]/2+a[0][1]; a[0][0]=9*8+7-6; 在使用数组元素时,应注意下标值不能超出已定义数组大小的范围。 例 a[3][4]=99;是错误的。因为最后一个元素是a[2][3].
7.2.3 二维数组初始化 可以用下面方法对二维数组初始化: (1)分行给二维数组赋初值。 int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; (2)只用一个花括号,按数组排列顺序对各元素赋初值。 int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12} ;作用与(1)相同。
2 0 • 3 0 0 • 2 0 • 0 0 0 0 1 0 0 0 3 (3)可以只对部分元素赋值。 例 int b[2][3]={{1,2},{3}}; b的数组元素为: 例 int b[2][3]={{1,2},{}}; b的数组元素为: 例 int b[2][3]={{0,1},{0,0,3}}; b的数组元素为:
(4)若对全部元素都赋初值,则定义数组时对第一维的长度可以不指定,但第二维的长度必须指定。系统会根据总个数,确定数组行数。(4)若对全部元素都赋初值,则定义数组时对第一维的长度可以不指定,但第二维的长度必须指定。系统会根据总个数,确定数组行数。 例如: int b[2][3]={1,2,3,4,5,6}; 等价于 int b[ ][3]={1,2,3,4,5,6}; 定义时也可以只对部分元素赋初值而省略第一维的长度,但应分行赋初值。 例:int a[ ][4]={{1,2,3},{},{6,7,8,9}}; 这样写法,能通知编译系统,数组有三行。
说明: 1.按行赋初值 数据类型 数组名[行常量表达式][列常量表达式]={{第0行初值表},{第1行初值表},……,{最后1行初值表}}; 赋值规则:将“第0行初值表”中的数据,依次赋给第0行中各元素;将“第1行初值表”中的数据,依次赋给第1行各元素;以此类推。 2.按2维数组在内存中的排列顺序给各元素赋初值 数据类型 数组名[行常量表达式][列常量表达式]={初值表}; 赋值规则:按2维数组在内存中的排列顺序,将初值表中的数据,依次赋给各元素。 如果对全部元素都赋初值,则“行数”可以省略。注意:只能省略“行数”。
例 若有说明语句:int a[2][4];则对a数组元素的正确引用是: (A) a[0][3] (B) a[0][4] (C) a[2][2] (D) a[2][2+1] 答案: A
例 若有说明语句:int y[][4]={0,0};,则以下叙述不正确的是: (A)数组y的每个元素都可得到初值0 (B)二维数组y 的行数为1 (C)该说明等价于int y[][4]={0}; (D)只有元素y[0][0]和y[0][1]可得到初值0,其余元素均得不到初值0 答案:D
例 若有说明语句 int a[][3]={1,2,3,4,5,6,7,8,} 则数组a的行数是: (A)3 (B)2 (C)无确定值 (D)1 答案: A
7.2.4 二维数组程序举例 例7.4将二维数组行和列元素互换,存到另一个二维数组中。例如: 1 4 b= 2 5 3 6 • 2 3 • 4 5 6 a= main( ) { int a[2][3]={ {1,2,3},{4,5,6} }; 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”,a[i][j]) ; printf(“\n”) ; } }
例7.5有一个3×4的矩阵, 求出值最大的元素的值,以及其所在的行号和列号。 main( ) {int i, j, max,row=0,colum=0; 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”, max, row, colum); }
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’; 上面的定义可改为:int c[10]; c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9]
7.3.2 字符数组的初始化 最容易理解的是逐个字符赋给数组中的各元素。如: int c[3]={‘y’,’o’,’u’}; 若花括号中提供的初值个数大于数组长度,作语法错误处理。若初值个数小于数组长度,只将这些字符赋给数组中前面的元素,其余元素自动定为空字符(‘\0’)。 如果初值个数与数组长度相同,定义时可以省略数组长度。如: char c[]={‘c’,’_’,’c’,’h’,’a’,’r’}; 数组c的长度自动定为6。 定义和初始化二维字符数组。如: char b[2][3]={{‘a’,’a’,’a’},{‘b’,’b’,’b’}};
7.3.3 字符数组的引用 例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”); }
例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”); } }
7.3.4 字符串和字符串结束标志 c语言将字符串作为字符数组处理。为测定字符串实际长度,规定’\0’为“字符串结束标志”。 遇到’\0’时,表示字符串结束,字符串的有效字符由它前面的字符组成。 系统对字符串常量也自动加一个’\0’作为结束符。例如“c program”在内存中占10个字节,最后一个字节放’\0’。 程序中往往依靠检测’\0’来判断字符串是否结束,而不是根据数组的长度来决定字符串长度。
说明:’\0’代表ASCII码为0的字符,它不是一个可以显示的字符,而是一个“空操作”,什么也不干,只是一个标志。说明:’\0’代表ASCII码为0的字符,它不是一个可以显示的字符,而是一个“空操作”,什么也不干,只是一个标志。 对于语句 printf(“How do you do?\n”); 由于在内存中系统自动在‘\n’的后面附加了一个’\0’作为字符串结束标志,执行时,输出一个检查一次,遇到’\0’就停止输出。
用字符串常量来使字符数组初始化: 例如 char c[ ]={“I_am_happy”}; 可省略花括号,直接写成: char c[ ]=“I am happy”; 注意:数组的长度是11,不是10,因为字符串常量的最后由系统加了一个‘\0’。 上面的初始化与下面的等价: char c[ ]={‘I’,’_’,’a’,’m’,’_’,’ h’,’a’, ’p’,’p’,’y’,’\0’}; 而不与下面的等价: char c[ ]={‘I’,’_’, ’a’,’m’,’_’,’ h’,’a’, ’p’,’p’,’y’};
字符数组并不要求它的最后一个字符为‘\0’,下面定义是合法的: 字符数组并不要求它的最后一个字符为‘\0’,下面定义是合法的: char c[5]={‘c’,’h’,’i’,’n’,’a’}; 但只要用字符串常量,就会自动加一个‘\0’。 因此,为了使处理方法一致,便于测定字符串的实际长度,以及在程序中作相应的处理,人们在字符数组中也常常人为地加一个‘\0’。如: char c[6]={‘c’,’h’,’i’,’n’,’a’,’\0’}; 或 char c[ ]={‘c’,’h’,’i’,’n’,’a’,’\0’}; 或 char c[ ]=“china”; /* 直观 ,方便*/ 或 char c[ ]={ “china” };
例 若有以下说明语句,则正确的叙述是 char x[ ]=“12345”; char y[ ]={‘1’,’2’,’3’,’4’,’5’}; (A)x数组与y数组的长度相同 (B)x数组长度大于y数组长度 (C)x数组长度小于y数组长度 (D)x数组等价于y数组 答案:B
7.3.5 字符数组的输入输出 两种方法: 1、逐个字符输入输出。用格式符‘%c’输入输出一个字符。 2、将整个字符串一次输入或输出。用‘%s’格式。例如: char c[ ]={“china”}; printf(“%s”,c); 在内存中数组C的状态: 遇到’\0’就停止输出。
注意: (1)输出字符不包括’\0’。 (2)用‘\s’格式符输出字符串时,printf函数中的输出项是字符数组名,而不是数组元素名。 (3)如果数组长度大于字符串实际长度,也只输出到遇’\0’结束。 (4)如果字符数组中包含一个以上的’\0’, 则遇第一个’\0’时输出就结束。
可以用scanf函数输入一个字符串。如 scanf(“%s”,c); c是字符数组名,从键盘输入的字符串应短于字符数组c的长度。 如果利用一个scanf函数输入多个字符串,则以空格分隔,如: char s1[5],s2[5],s3[5]; scanf(“%s%s%s”,s1,s2,s3); 输入数据:How are you? 数组S1、S2、S3的状态为:
如果改为 char s [13]; scanf(“%s”,s); 也输入 How are you? 只将“How”’加上‘\0’送到s数组中。 注意:C语言规定数组名代表该数组的起始地址。下列写法错误: scanf(“%s”,&s); 用printf(“%s”,c)输出时,是按数组名,找到该数组的起始地址,然后逐个输出其中的字符,遇‘\0’为止。
字符数组的逐个字符操作与 字符数组的整体操作区别。 1.字符数组的定义 一维字符数组,用于存储和处理1个字符串,其定义格式与1维数值数组一样。 二维字符数组,用于同时存储和处理多个字符串,其定义格式与2维数值数组一样。 2.字符数组的初始化 字符数组的初始化,可以通过为每个数组元素指定初值字符来实现。 3.字符数组的引用 字符数组的逐个字符引用,与引用数值数组元素类似。
A)字符数组的输入 除了可以通过初始化使字符数组各元素得到初值外,也可以使用getchar()或scanf()函数输入字符。 例如: char str[10]; …… for(i=0; i<10; i++) { scanf("%c", &str[i]); fflush(stdin); /*清除键盘输入缓冲区*/ } ……
B)字符数组的输出 字符数组的输出,可以用putchar()或printf()函数。 例如: char str[10]="c language"; …… for(i=0; i<10; i++) printf("%c", str[i]); printf("\n"); …… 注意:逐个字符输入、输出时,要指出元素的下标,而且使用“%c”格式符。另外,从键盘上输入字符时,无需输入字符的定界符──单引号;输出时,系统也不输出字符的定界符。
1.字符串及其结束标志 所谓字符串,是指若干有效字符的序列。C 语言中的字符串,可以包括字母、数字、专 用字符、转义字符等。 C语言规定:以‘\0’作为字符串结束标志. (‘\0’代表ASCII码为0的字符,表示一个“空 操作”,只起一个标志作用)。因此可以对 字符数组采用另一种方式进行操作了──字符 数组的整体操作。
2.字符数组的整体初始化 字符串设置了结束标志以后,对字符数组的初始化,就可以用字符串常量来初始化字符数组。 3.字符数组的整体引用 (1)字符串的输入 除了可以通过初始化使字符数组各元素得到初值外,也可以使用scanf()函数输入字符串。 (2)字符串的输出 printf()函数,不仅可以逐个输出字符数组元素,还可以 整体输出存放在字符数组中的字符串。 注意:由于系统在存储字符串常量时,会在串尾自动加 上1个结束标志,所以无需人为地再加1个。 另外,由于结束标志也要在字符数组中占用一个元素的 存储空间,因此在说明字符数组长度时,至少为字符串 所需长度加1。
例 下面程序段的运行结果正确的是: char x[5]={‘a’,’b’,’\0’,’c’,’\0’}; printf(“%s”,x); (A)’a’’b’ (B)ab (C)ab c (D)abc
7.3.6 字符串处理函数 1. puts(字符数组) 将一个字符串输出到终端。输出的字符串中可以包含转义字符。如: char str[ ]= “China\nBeijing”; puts(str); 输出为: China Beijing 输出时将‘\0’转换成’\n’,即输出完字符串后换行。
2. gets(字符数组) 从终端输入一个字符串到字符数组,并得到一个函数值。该函数值是字符数组的起始地址。 函数调用如:gets(str); 3. strcat(字符数组1,字符数组2) 连接两个字符数组中的字符串,字符串2接到字符串1的后面,结果放在字符数组1中。函数调用后,得到一个函数值:字符数组1的地址。 说明: (1)字符数组1的长度要能容纳新字符串。 (2) 连接后取消字符串1后的‘\0’,只在新串的最后保留一个‘\0’。
4. strcpy(字符数组1,字符串2) 将字符串2拷贝到字符数组1中去。 说明: (1)字符数组1的长度不应小于字符串2的长度。 (2)“字符数组1”必须写成数组名形式,“字符串2”可以是字符数组名或字符串常量。 (3) ‘\0’也一起拷贝到字符数组1中。 (4)不能用赋值语句将一个字符串常量或字符数组直接赋给一个字符数组。而只能用strcpy函数处理。 (5)可用strcpy函数将字符串2的前几个字符拷贝到字符数组1中。 如: strcpy(str1,sr2,2);的作用是将str2中前两个字符复制到str1中去,然后再加一个‘\0’。
5. strcmp(字符串1,字符串2) 作用是按ASCII码值比较两个字符串,自左至右逐个字符相比,直到出现不同字符或遇到‘\0’为止。 (1)若字符串1=字符串2,函数值为0。 (2)若字符串1>字符串2,函数值为正整数。 (3)若字符串1<字符串2,函数值为负整数。 注意:两个字符串比较,不能用下面形式: if(str1==str2)printf(“yes”); 而只能用下面形式: if(strcmp(str1,str2)==0)printf(“yes”);
6. strlen(字符数组) 测字符串长度函数,函数值是字符串实际长度,不包括‘\0’在内。 如:char str[10]=“china”; printf(“%d”,strlen(str)); 输出结果是5,不是6,不是10。 也可测字符串常量长度: strlen(“china”) 7. strlwr(字符串) 将字符串中大写字母转换成小写字母。 8. strupr(字符串) 将字符串中小写字母转换成大写字母。
例 判断字符串str1是否大于字符串str2,应当使用: (A)if(str1>str2) (B)if(strcmp(str1,str2)) (C)if(strcmp(str2,str1)>0) (D)if(strcmp(str1,str2)>0)
例 若有语句:char s1[10],s2[10]={“books”},则能将字符串books赋给数组s1的正确语句是: (A)s1={“books”}; (B)strcpy(s1,s2); (C)s1=s2; (D)strcpy(s2,s1);