430 likes | 574 Views
第七章 数组. 主要内容: 7.1 一维数组的定义和引用 7.2 二维数组的定义和引用 7.3 字符数组 要求: 1 ,掌握一维与二维数组的定义与使用方法 2 ,起泡排序算法 3 ,字符数组的定义与使用 4 ,使用字符数组进行串处理的方法。. 数组是用于存储多个相同类型数据的变量的集合. 7.1 一维数组的定义和引用 一维数组的定义方式: 类型说明符 数组名 [ 常量表达式 ] ; 如: int a[10],b[20];. 说明 :( 1 )数组名,与变量名一样,必须遵循标识符命名规则。
E N D
第七章 数组 主要内容:7.1 一维数组的定义和引用 7.2 二维数组的定义和引用 7.3 字符数组 要求:1,掌握一维与二维数组的定义与使用方法 2,起泡排序算法 3,字符数组的定义与使用 4,使用字符数组进行串处理的方法。
数组是用于存储多个相同类型数据的变量的集合数组是用于存储多个相同类型数据的变量的集合 7.1 一维数组的定义和引用 一维数组的定义方式: 类型说明符 数组名[常量表达式]; 如:int a[10],b[20];
说明:(1)数组名,与变量名一样,必须遵循标识符命名规则。说明:(1)数组名,与变量名一样,必须遵循标识符命名规则。 (2)“常量表达式”必须用方括号括起来,不能是圆括号。如下面是不正确的数组定义: int a(10) (3)常量表达式的值为数组的元素个数(又称数组长度),数组元素的下标是元素相对于数组起始地址的偏移量,所以从0开始顺序编号。 (4)常量表达式是一个整型值,其中可以包含常数和符号常量,但不能包含变量。C语言中不允许动态定义数组。
例如,如下定义数组是不行的: int n=10; main() {int a[n];} 特别说明:在数组定义时,“常量表达式”外的方括号;以及元素引用时,“下标表达式”外的方括号,都是C语言语法规则所要求的, (5)数组名中存放的是一个地址常量,它代表整个数组的首地址。同一数组中的所有元素,按其下标的顺序占用一段连续的存储单元。
7.1.2 一维数组元素的引用 引用数组中的任意一个元素的形式: 数组名[下标表达式] 1.“下标表达式”可以是任何非负整型数据,取值范围是0~(元素个数-1)。 特别强调:在运行C语言程序过程中,系统并不自动检验数组 元素的下标是否越界。因此在编写程序时,保证数组下标不越界 是十分重要的。 2.1个数组元素,实质上就是1个变量,它具有和相同类型单 个变量一样的属性,可以对它进行赋值和参与各种运算。 3.在C语言中,数组作为1个整体,不能参加数据运算,只能 对单个的元素进行处理。
例7.1 数组元素的引用 #include<stdio.h> void main() {int i, a[10]; for(i=0;i<=9;i++) a[i]=i; /*给数组元素赋值*/ for(i=9;i>=0;i--) /*按逆序输出数组元素*/ printf("%5d",a[i]); }
7.1.3 一维数组元素的初始化:在定义数组时赋值7.1.3 一维数组元素的初始化:在定义数组时赋值 初始化格式: 数据类型 数组名[常量表达式]={初值表} 如 int a[10]={0,1,2,3,4,5,6,7,8,9}; (1)“初值表”中的初值个数,可以少于元素个数,即允许只给 部分元素赋初值,其余元素系统会自动赋0。 例:int a[10]={0,0,0,0,0,0,0,0,0,0};与int a[10]={0};相同 int a[10]={1,2,3,4,0,0,0,0,0,0};与int a[10]={1,2,3,4};相同 (2)如果对数组的全部元素赋以初值,定义时可以不指定数组 长度(系统根据初值个数自动确定)。如果被定义数组的长度, 与初值个数不同,则数组长度不能省略。如 int a[10]={0,1,2,3,4,5,6,7,8,9};与int a[ ] ={0,1,2,3,4,5,6,7,8,9}相同
7.1.4 一维数组举例 例7.2 用数组来处理Fibonacci数列问题 fibi=fibi-1+fibi-2 #include<stdio.h> void main() {int i,f[20]={1,1}; for(i=2;i<20;i++) f[i]=f[i-1]+f[i-2]; for(i=0;i<20;i++) printf("%d\t",f[i]); }
例7.3 用起泡法(冒泡法)对10个数排序(由小到大)例7.3 用起泡法(冒泡法)对10个数排序(由小到大) 冒泡法的基本思想:通过相邻两个数之间的比较和交换,使排序码(数值) 较小的数逐渐从底部移向顶部,排序码较大的数逐渐从顶部移向底部。就像 水底的气泡一样逐渐向上冒,故而得名。 由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趟后,整个排序过程结束。 外排序i从1到n-1,内排序j从1到n-i
main() {int i,j,t,a[11]; printf("input 10 numbers:\n"); for(i=1;i<11;i++) scanf("%d",&a[i]); for(i=1;i<=9;i++) for(j=1;j<=10-i;j++) if(a[j]>a[j+1]) {t=a[j];a[j]=a[j+1];a[j+1]=t;} printf("\nThe scorted numbers:\n"); for(i=1;i<11;i++) printf("%5d",a[i]);} 算法设计 1,定义变量与数组 2,输入数组元素 3,排序(由小到大) for i=1 to 9 for j=1 to 10-i if(a[i]>a[i+1])则交换 4,输出
7.2 二维数组的定义和引用 7.2.2 二维数组的定义 二维数组的定义形式如下: 类型说明符 数组名[行常量表达式][列常量表达式]; 例如:int a[3][4]; 定义了一个3行4列的数组,总共有12个数组元素 1.数组元素在内存中的排列顺序为“按行存放”,即先顺序存放第一行的元素,再存放第二行,以此类推。 2. 设有一个m*n的数组x,则第i行第j列的元素x[i][j]在数组中的位置为:i*n+j(注意:行号、列号均从0开始计数)。 3.可以把2维数组看作是一种特殊的1维数组:它的元素又是一个1维数组。
例如,对float a[3][4],可以把a看作是一个一维数组,它有3个元 素:a[0]、x[1]、a[2],每个元素又是一个包含4个元素的一维数组, 如图7.4所示。即把a[0]、a[1]、a[2]看作是3个一维数组的名字。 a[0]------a[0][0] a[0][1] a[0][2] a[0][3] a[1]------a[1][0] a[1][1] a[1][2] a[1][3] a[2]------a[2][0] a[2][1] a[2][2] a[2][3] a 7.2.2 二维数组的引用 引用格式:数组名[下标][下标] 其中下标可以是整型常量表达式,但要注意其值必须在相应范 围内:0~n-1 如:a[2][3], a[i][j];
7.2.3 二维数组的初始化 1.按行赋初值 数据类型 数组名[行常量表达式][列常量表达式]={{第0行初值表},{第1行 初值表},……,{最后1行初值表}}; 赋值规则:将“第0行初值表”中的数据,依次赋给第0行中各元素;将“第1行初值表”中的数据,依次赋给第1行各元素;以此类推。如 int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}} 2.按2维数组在内存中的排列顺序给各元素赋初值 数据类型 数组名[行常量表达式][列常量表达式]={初值表}; 赋值规则:按2维数组在内存中的排列顺序,将初值表中的数据,依次赋给 各元素。如: int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12} 3.可以对部分元素赋值,其余元素系统自动赋0。如: int a[3][4]={{1},{5},{9}}; 4.如果对全部元素都赋初值,则“行数”可以省略。注意:只能省略“行数”。 int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
7.2.4 二维数组程序举例 例7.4 将一个二维数组的行和列的元素互换保存到另一个数组元素中(转置) main() {int a[2][3]={1,2,3,4,5,6},b[3][2],i,j; printf("array a:\n"); for(i=0;i<2;i++) {for(j=0;j<3;j++) { printf("%5d",a[i][j]); b[j][i]=a[i][j];} printf("\n"); } for(i=0;i<3;i++) {for(j=0;j<2;j++) printf("%5d",b[i][j]); printf("\n");}}
例7.5 有一个3×4矩阵,要求编程求出其中最大的那个元素的值,以及其所在的行号与列号。例7.5 有一个3×4矩阵,要求编程求出其中最大的那个元素的值,以及其所在的行号与列号。 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;} printf("max=%d ,row=%d, colum=%d",max,row,colum); }
例 有M个学生,学习N门课程,已知所有学生的各科成绩,编程:分别例 有M个学生,学习N门课程,已知所有学生的各科成绩,编程:分别 求每个学生的平均成绩和每门课程的平均成绩。 /*功能:计算个人平均成绩与各科平均成绩,并在屏幕上显示出来。*/ #define NUM_std 5 /*定义符号常量人数为5*/ #define NUM_course 4 /*定义符号常量课程为4*/ #include "stdio.h" main() { int i,j; static float score[NUM_std+1][NUM_course+1]={{78,85,83,65}, {88,91,89,93}, {72,65,54,75}, {86,88,75,60}, {69,60,50,72}};
for(i=0;i<NUM_std;i++) {for(j=0;j<NUM_course;j++) { score[i][NUM_course] += score[i][j];/*求第i个人的总成绩*/ score[NUM_std][j] += score[i][j]; /*求第j门课的总成绩*/ } score[i][NUM_course] /= NUM_course;/*求第i个人的平均成绩*/ } for(j=0;j<NUM_course;j++) score[NUM_std][j] /= NUM_std; /*求第j门课的平均成绩*/ clrscr(); /*输出表头*/ printf("学生编号 课程1 课程2 课程3 课程4 个人平均\n"); /*输出每个学生的各科成绩和平均成绩*/
for(i=0;i<NUM_std;i++) { printf("学生%d\t",i+1); for(j=0;j<NUM_course+1;j++) printf("%6.1f\t",score[i][j]); printf("\n"); } /*输出1条短划线*/ for(j=0;j<8*(NUM_course+2);j++) printf("-"); printf("\n课程平均"); /*输出每门课程的平均成绩*/ for(j=0;j<NUM_course;j++) printf("%6.1f\t",score[NUM_std][j]); printf("\n"); getch(); }
7.3 字符数组 字符数组:存放字符数据的数组,每一个元素存放一个字符。 7.3.1 程序中定义字符数组 char c[10]; /* 定义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'; 字符型与整型可以通用,但有区别: char c[10]; /* 在内存中占10字节 */ int c[10]; /* 在内存中占20字节 */
7.3.2 字符数组的初始化 1.逐个元素初始化 char c[10] = {'I',' ','a','m',' ','h','a','p','p','y'}; 2、初始化数据少于数组长度,多余元素自动为“空”('\0',二进制0)。 char c[10] ={'c','','p','r','o','g','r','a','m'};/*9*/ 3、指定初值时,若未指定数组长度,则长度等于初值个数。 char c[ ] = {'I',' ','a','m',' ','h','a','p','p','y'};
7.3.3 字符数组的引用 引用一个元素,得到一个字符。 [例7.6] 输出一个字符串。 #include<stdio.h> void 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
[例] 输出一个菱形图。 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字符串和字符串结束标志 字符串例子:"I am a boy" 1、C语言中,字符串作为字符数组处理。字符数组可以用字符串来初始化,例、 char c[] = {"I am happy"}; 也可以这样初始化:(不要大括号) char c[] = "I am happy"; 2、字符串在存储时,系统自动在其后加上结束标志'\0'(占一字节,其值为二进制0)。但字符数组并不要求其最后一个元素是'\0',例、char c[] = {"China"};
char c[5] = {‘C’,’h’,’i’,’n’,’a’}; char c[10] = {"China"};
7.3.5 字符数组的输入输出 两种方法: 1、用“%c”格式符逐个输入输出。 2、用“%s”格式符按字符串输入输出。 例、char c[6]; scanf("%s",c); printf("%s",c); 注意: (1)输出时,遇'\0'结束,且输出字符中不包含'\0'。
(2)“%s”格式输出字符串时,printf()函数的输出项是字符数组名,而不是元素名。(2)“%s”格式输出字符串时,printf()函数的输出项是字符数组名,而不是元素名。 char c[6] = "China"; printf("%s",c); printf("%c",c[0]); printf("%s",c[0]); (3)“%s”格式输出时,即使数组长度大于字符串长度,遇'\0'也结束。例、 char c[10] = {"China"}; printf(“%s”,c); /*只输出5个字符 */ (4) “%s”格式输出时,若数组中包含一个以上'\0',遇第一个'\0'时结束。
(5)输入时,遇回车键结束,但获得的字符中不包含回车键本身,而是在字符串末尾添‘\0’。因此,定义的字符数组必须有足够的长度,以容纳所输入的字符。(如,输入5个字符,定义的字符数组至少应有6个元素)。(5)输入时,遇回车键结束,但获得的字符中不包含回车键本身,而是在字符串末尾添‘\0’。因此,定义的字符数组必须有足够的长度,以容纳所输入的字符。(如,输入5个字符,定义的字符数组至少应有6个元素)。 (6)一个scanf函数输入多个字符串,输入时以“空格”键作为字符串间的分隔。例、 char str1[5],str2[5],str3[5]; scanf("%s%s%s",str1,str2,str3); 输入数据:How are you? str1、str2、str3获得的数据见下图。
例 char str[13]; scanf("%s",str); 输入:How are you? 结果:仅“How”被输入数组str 如要想str获得全部输入(包含空格及其以后的字符),程序应怎样设计?
char c[13]; int i; for(i=0;i<13;i++) c[i] = getchar(); • (7) C语言中,数组名代表该数组的起始地址,因此,scanf()函数中不需要地址运算符&。(在Turbo C中,加上&运算符也可以)。例、 char str[13]; scanf("%s",str); scanf("%s",&str); (8)不能采用赋值语句将一个字符串直接赋给一个数组。例:char c[10];c[]=“good”; 但是可以初始化:如:char c[ ]= “good”;
7.3.6 字符串处理函数 在C的函数库中,提供了一些字符串处理函数。 在调用字符串处理函数时,在程序前面通常应设置一个相关的文件包含预处理命令。即 #include <stdio.h> #include <string.h> 1、puts()函数:输出字符串(以‘\0’结尾)。 例 char c[6]=“China”; printf、puts均以‘\0’结尾. printf("%s\n",c); printf需要格式控制符%s puts(c); puts不需要格式控制符,且自动换行
2.gets()函数:从终端接收一个字符串到字符数组2.gets()函数:从终端接收一个字符串到字符数组 char str[12]; gets(str); 注意:gets()、puts()一次只能输入输出一个字符串。而scanf()、printf()可以输入输出几个字符串。 3、strcat():连接字符串。 strcat(字符串1,字符串2); 功能:把“字符串2”连接到“字符串1”的后面。从str1原来的’\0’(字符串结束标志)处开始连接。 注意: 字符串1一般为字符数组,要有足够的空间,以确保连接字符串后不越界; 字符串2可以是字符数组名,字符串常量。
C h i n a \0 \0 \0 \0 \0 • 4、strcpy():字符串拷贝。 strcpy(字符串1,字符串2); 功能:将“字符串2”为首地址的字符串复制到“字符串1”为首地址的字符数组中。即把“字符串2”的值拷贝到“字符串1”中。 • 例如: • char str1[10],str2[ ]={“china”}; • strcpy(str1,str2); • 执行后str1的状态为:
str1-一般为字符数组,要有足够的空间,以确保复制字符串后不越界;str1-一般为字符数组,要有足够的空间,以确保复制字符串后不越界; str2-可以是字符数组名,字符串常量。 字符串(字符数组)之间不能赋值,但是通过此函数,可以间接达到赋值的效果。 • 5、strcmp():字符串比较。 strcmp(字符串1,字符串2); 比较“字符串1”、“字符串2”,例、 strcmp(str1,str2); strcmp("China", "Korea"); strcmp(str1, "Beijing");
比较规则:逐个字符比较ASCII码,直到遇到不同字符或‘\0’,比较结果是该函数的返回值。比较规则:逐个字符比较ASCII码,直到遇到不同字符或‘\0’,比较结果是该函数的返回值。 字符串1 < 字符串2, strcmp()返回值<0 字符串1 == 字符串2, strcmp()返回值==0 字符串2 > 字符串2, strcmp()返回值>0 长度不同的字符串也可以进行比较,比较结果当然是“不同”。 长度不同的字符串也可以进行比较,比较结果当然是“不同”。 注意、字符串只能用strcmp函数比较,不能用关系运算符“==”比较。例、 if (strcmp(str1,str2) == 0) printf("yes"); if (!strcmp(str1,str2)) printf("equal"); if (str1 == str2) printf("yes");
6、求字符串的长度函数strlen(str) • 功能:统计str为起始地址的字符串的长度(不包括“字符串结束标志”),并将其作为函数值返回。 • 7.strlwr”(str)函数:将字符串中大写字母转换成小写字母. • 8.strupr(str)函数:将字符串中小写字母转换成大写字母. 注意:在调用字符串处理函数时,在程序前面应设置一个相关的文件包含预处理命令,即#include <string.h>
7.3.7 字符数组应用举例 例:字符串输入与输出。 程序如下: #include <stdio.h> main( ) { char s[20],s1[20]; scanf(“%s”,s); printf(“%s \n”,s); scanf(“%s%s”,s,s1); /*从键盘上输入字符串,将How给s,将do给sl*/ printf(“s=%s,sl=%s”,s,s1);
puts(“\n”); gets(s); puts(s); } 程序运行结果: How do you do? ↙ How How do you do? ↙ S=How,S1=do How do you do? ↙ How do you do? 例中使用了scanf( )与gets( )两个函数来实现字符串的输入,要注意它们的差别,根据需要来选用。
例7.8:从键盘上输入两个字符串,若不相等,将短的字符串连接到长的字符串的末尾并输出。例7.8:从键盘上输入两个字符串,若不相等,将短的字符串连接到长的字符串的末尾并输出。 #include <stdio.h> #include <string.h> main( ) { char s1[80],s2[80]; gets(s1); gets(s2); if (strcmp(s1,s2)!=0) if (strlen(s1)>strlen(s2))
{ strcat(s1,s2); puts(s1); } else { strcat(s2,s1); puts(s2); } } 输入:you ↙ Thank ↙ 输出:Thank you
例7.9:输入三个字符串,并找出其中最大者。 分析:用strcmp()函数比较字符串的大小。首先比较前两个,把较大者拷贝给字符数组变量string(用strcpy()函数拷贝),再比较string和第三个字符串。 程序:设字符串最长为19个字符。 #include “string.h”/* strcmp、strcpy函数均在string.h中定义 */ #include “stdio.h”
main() {char string[20]; /* 存最大字符串 */ char str[3][20]; /* 三个字符串 */ int i; for(i=0;i<3;i++) gets(str[i]); /* 输入三个字符串 */ if (strcmp(str[0],str[1])>0) strcpy(string,str[0]); else strcpy(string,str[1]); if (strcmp(str[2],string) > 0) strcpy(string,str[2]); printf("\nthe largest string is: \n%s\n",string); }
小结: 1、数组(一维和二维,多维)名、数组元素的概念。一维数组常与一重循环配合、二维数组常与二重循环配合,对数组元素依次进行处理。 2、数组必须先定义后使用,数组的初始化方法。 3、数组元素在内存中的存储顺序。 4、数据排序算法。(冒泡排序法) 5、字符串的特点(作为字符数组处理、最后一字节加'\0')。 6、字符串处理函数的应用。
作业:1,习题7.15 2,从键盘输入两个字符串a,b把串b的前五个字符连接到串a中,若b的长度小于五,则将其所有元素连接到a中,试编程。