550 likes | 618 Views
第六章 数 组. (时间: 6 次课 6 学时理论 +6 学时实践). 6. 教学目的和要求:了解掌握 C 中一维数组、二维数组、字符数组的定义和引用;能熟练进行数组数据类型的程序设计。 重难点:数组的应用. 数组是同一类型的一组值( 10 个 char 或 15 个 int ),在内存中顺序存放。整个数组共用一个名字,而其中的每一项又称为一个元素。 1 、定义方式: 类型说明符 数组名 [ 常量表达式 ];
E N D
第六章 数 组 (时间:6次课 6学时理论+6学时实践) 6
教学目的和要求:了解掌握C中一维数组、二维数组、字符数组的定义和引用;能熟练进行数组数据类型的程序设计。教学目的和要求:了解掌握C中一维数组、二维数组、字符数组的定义和引用;能熟练进行数组数据类型的程序设计。 重难点:数组的应用
数组是同一类型的一组值(10个char或15个int),在内存中顺序存放。整个数组共用一个名字,而其中的每一项又称为一个元素。数组是同一类型的一组值(10个char或15个int),在内存中顺序存放。整个数组共用一个名字,而其中的每一项又称为一个元素。 1、定义方式: 类型说明符 数组名[常量表达式]; 例:int a[4]; // 表明a数组由4个int型元素组成,其元素分别为:a[0], a[1], a[2], a[3] C不允许对数组的大小作动态的定义,即数组的大小不能是变量,必须是常量。如果要根据不同的数值改变数组的大小,可用常量表达式。 一、一维数组的定义和引用
下面是一些一维数组说明的例子: int array[100]; //说明一个元素个数为 100的整型数组 float f[20]; //说明一个元素个数为20的浮点型数组 static char c[50]; //说明一个元素个数为50的静态字符型数组 int a[10+20]; //说明一个元素个数为30的整型数组,这里10+20是一个常量表达式 int array[100]; //说明一个元素个数为 100的整型数组 float f[20]; //说明一个元素个数为20的浮点型数组 static char c[50]; //说明一个元素个数为50的静态字符型数组 int a[10+20]; //说明一个元素个数为30的整型数组, 这里10+20是一个常量表达式 一、一维数组的定义和引用
2、一维数组元素的引用 数组元素的引用是通过数组名和下标来确定的。 格式: <数组名>[<下标表达式>] 其中 <下标表达式>表示了数组中的某一个元素的顺序号,必须是整型常量、整型变量或整型表达式。 说明:1)若数组的元素个数说明为n,则下标表达式的范围是从0到n-1,共n个整数,超出这个范围就称为数组下标越界。 2)数组元素可以象普通数据一样进行赋值和算术运算以及输入和输出操作。 一、一维数组的定义和引用
2、一维数组元素的引用 例:void main(void ) { int i, a[10]; for ( i=0; i<10; i++) a[i]=i; for ( i=9; i>=0 ; i--) printf(“%d\t”,a[i]); printf(“\n”); } 一、一维数组的定义和引用
3、一维数组的初始化 数组初始化指在定义数组的同时给数组元素赋值。 注意:1)对数组中的一部分元素列举初值,未赋值的部分是0。 2)不能给数组整体赋值,只能一个一个地赋值。 3)可以用 int a[ ]= {0,1, 2, 3, 4, 5, 6, 7, 8, 9};给数组赋值,编译器会自动计算出内的元素项数,并将数组定义为该长度。 4)用局部static 或全局定义的数组不赋初值,系统均默认其为‘\0’。 一、一维数组的定义和引用
例:求Fibonacci数列:1,1,2,3,5,8,......的前20个数,即:F1=1 (n=1) F2=1 (n=2) Fn=Fn-1+Fn-2 (n>=3) void main (void) { int i; int f [20]={1,1}; for (i=2 ; i<20 ; i++ ) f [i]=f [i-1]+f [i-2]; for ( i=0; i<20; i++) { if (i%5= =0) printf(“\n”); printf(“%d\t”,f[i]); } } 一、一维数组的定义和引用
1、定义方式 类型说明符 数组名[常量表达式][常量表达式]; 在内存中,多维数组依然是直线顺序排列的,第一个元素位于最低地址处。 2、二维数组的引用 与一维数组一样,二维数组必须先定义,其维数必须是常量。具体引用时(赋值、运算、输出)其元素等同于变量。 二、二维数组的定义和引用
例:void main(void) { int a[2][3], i, j; Printf(“Input 2*3 numbers\n”); for (i=0; i<2; i++) // 输入 for(j=0; j<3; j++) scanf(“%d”,&a[i][j]); for (i=0; i<2; i++) // 输出 { for(j=0; j<3; j++) printf(“%d\t”,a[i][j]); printf(“\n”); } } 二、二维数组的定义和引用
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}; //依次赋值 3)部分赋值 int a[3][4]={{1},{5},{9}}; /* a[0][0]=1, a[1][0]=5, a[2][0]=9 其余元素为0 */ 二、二维数组的定义和引用
二、二维数组的定义和引用 4)分行或全部赋值时,可以省略第一维,第二维不可省。 int a[ ][4]={{1,2},{5,6,7,8,}{9,10,11,12}}; 5)不能给数组整体赋值,只能一个一个地赋值。 int a[2][3]={1,2,3,.....,12}; 6)用static 定义的数组不赋初值,系统均默认其为‘\0’。 static int a[2][3];
二、二维数组的定义和引用 例:有一个3×4的矩阵,要求编程序求出其中值最大的那个元素的值,以及其所在的行号和列号。 max=a[0][0]; //使max开始时取a[0][0]的值 for (i=0;i<=2;i++) //从第0行到第2行 for (j=0;j<=3;j++) //从第0列到第3列 if (a[i][j]>max) //如果某元素大于max { max=a[i][j]; //max将取该元素的值 row=i; //记下该元素的行号i colum=j; //记下该元素的列号j } printf(“%d\t%d\t%d\n”, row, colum, <max);
二、二维数组的定义和引用 例:输入一个十进制数,输出它对应的八进制数。 void main(void) { int x , i, n , a[100]; scanf(“%d”,&x); i=0; while(x) { a[i]=x%8; x=x/8; i++; } n=i; for(i=n-1;i>=0;i--) printf(“%d”,a[i]); printf(“\n”); }
三、字符数组 • 用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符。 • 1、字符数组的定义 • 定义格式:char 数组名[常量表达式]; • 2、字符数组的初始化 • 与数值数组的初始化相同,取其相应字符的ASCII值。 • 如果字符个数大于数组长度,做错误处理;如果数值个数小于数组长度,后面的字节全部为‘\0’。 • 如果省略数组长度,则字符数即为数组长度。 • 同理,也可定义和初始化一个二维或多维的字符数组。分层或省略最后一维。
三、字符数组 3、字符数组的引用 void main(void) { char c[10]={‘I’, ‘’, ‘a’, ‘m’, ‘’, ‘a’, ‘’ , ‘b’, ‘o’, ‘y’}; int i; for (i=0; i<10; i++) printf(“%d”,c[i]); printf(“\n”); }
4、字符串和字符串结束标志 C语言将字符串作为字符数组来处理。 字符串常量:“CHINA”,在机内被处理成一个无名的字符型一维数组。 C语言中约定用‘\0’作为字符串的结束标志,它占内存空间,但不计入串长度。有了结束标志‘\0’后,程序往往依据它判断字符串是否结束,而不是根据定义时设定的长度。 可以用字符串的形式为字符数组赋初值。如果数组定义的长度大于字符串的长度,后面均为‘\0’。在语句中字符数组不能用赋值语句整体赋值。 三、字符数组
三、字符数组 • C语言没有提供字符串数据类型,可以通过字符数组来处理字符串。 • 必须在字符数组末尾出现串结束符‘\0’,如对于字符数组char s[10],若将它用来存放字符串"A String",则在内存中的该字符数组存放的形式如: • s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9] • 字符串的存放形式
三、字符数组 字符串的初始化有以下两种形式: 1)与字符数组的初始化形式相同: charstr[]={‘a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’\0’};① 字符串可以进行部分初始化,即 char pstr[8]={‘a’,’b’,’c’,’d’,’\0’}; ② 其中未赋值的部分将自动赋值为’\0’,因此pstr也可以进行如下的初始化 char pstr[8]={‘a’,’b’,’c’,’d’}; ③
三、字符数组 ②式与③式是等价的。 char ch[8]={‘A’,’ ‘,’S’,’t’,’r’,’i’,’n’,’g’}; ④ ④式与③式是不一样的,④式中ch是一个不 带串结束符的 字符数组,不能对它使用与字 符串有关的标准库函数。
三、字符数组 (2) 对字符串的初始化还有两种简写形式,如对 char str[]= {‘a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’\0’}; 下列两式都是等价的简写形式: char str[]="A string"; char str[]={"A string"}; 系统会自动在字符串后添加一个串结束符’\0’。
5、字符数组的输入输出 逐个字符的输入输出。这种输入输出的方法,通常是使用循环语句来实现。如: char str[10]; printf(“输入十个字符:”); for(int i=0;i<10;i++) printf(“%d”,str[i]); //将输入的十个字符依次送给数组str中的各个元素 ...... 把字符数组作为字符串输入输出。对于一维字符数组的输入,在scanf中仅给出数组名;输出时,在printf中也只给出数组名。 三、字符数组
例:void main (void ) { char s1[50],s2[60]; printf(“输入二个字符串:”); scanf(“%s%s”,s1,s2); printf(“\n s1 = %s”, s1); printf(“\n s2 = %s”, s2); } 三、字符数组
三、字符数组 例:字符数组使用的一个实例。 假设有10本书按0~9编好号,当某本书被读过后,在上面做一个标记"T",表示已读过,否则做一个标记"F",表示未读。现要求随便抽一本书,判断它是否读过。
三、字符数组 #include <stdio.h> main() {char book[10]= {‘T’,‘F’,‘F’,‘T’,‘F’,‘T’,‘T’,‘F’,‘T’,‘F’}; int num; printf("请给出书的编号(0-9):"); scanf("%d",&num); if(book[num]==‘T’) printf("该书已读过"); else printf("该书未读过"); } 运行结果如下: 请给出书的编号(0-9):5 该书已读过
C中没有对字符串变量进行赋值、合并、比较的运算符,但提供了许多字符串处理函数,用户可以调用#include “string.h”。 所有字符串处理函数的实参都是字符数组名。 1、合并两个字符串的函数 strcat (str1, str2) 将第二个字符串 str2 接到第一个字符串 str1 后。 注意:第一个字符串要有足够的空间。 四、字符串处理函数
例:字符串的连接。 #include <string.h> void main() { char *s1=”123”,*s2=”abcdef”,*s3; s3=strcat(s1,s2); printf(”%u,%u,%u\n”,s1,s2,s3); puts(s1); puts(s2); puts(s3); } 四、字符串处理函数 程序运行结果: 12,24025,16 s1=123abcdef s2=abcdef s3=123abcdef
2、复制两个字符串的函数 strcpy (str1, str2) static char str1[20]={“I am a ”}; static char str2[ ]={“boy”}; strcpy (str1, str2); 四、字符串处理函数
例:分析下面程序的运行结果。 #include "conio.h" #include "string.h" #include "stdio.h" void main() {static char c1[10]="abcdefghi",c2[]="china"; strcpy(c1,c2); clrscr(); puts(c1); printf("%c",c1[7]); } 四、字符串处理函数
例:实参为字符指针的复制情况。 #include <string.h> void main() { char *s1=”123”,*s2=”abcedf”,*s3; s3=strcpy(s1,s2); printf(”%u,%u,%u\n”,s1,s2,s3); puts(s1); puts(s2); puts(s3); } 四、字符串处理函数
3、比较两个字符串的函数 strcmp (str1, str2) 此函数用来比较str1和str2中字符串的内容。函数对字符串中的ASCII字符逐个两两比较,直到遇到不同字符或‘\0’为止。函数值由两个对应字符相减而得。 该函数具有返回值,返回值是两字符串对应的第一个不同的ASCII码的差值。 若两个字符串完全相同,函数值为0。 例如: strcmp(" d ", " abc ") 结果为正整数。 strcmp(" dog ", " door ") 结果为负整数。 四、字符串处理函数
例:输入三个字符串,按英文字母序排列后输出。 include <string.h> void main() {char s1[10]="China",s2[10]="America",s3[10]="Japan",t[10]; if(strcmp(s1,s2)>0) {strcpy(t,s1);strcpy(s1,s2);strcpy(s2,t);} if(strcmp(s2,s3)>0) {strcpy(t,s2);strcpy(s2,s3);strcpy(s3,t);} puts(s1); puts(s2); puts(s3); } 四、字符串处理函数 程序输出结果: America China Japan
例:比较用户输入的字符串是否为表示同意的yes(用户可以用大写或小写)。 #include "string.h" #include "stdio.h" void main() {int k; char s1[5],s2[]="yes"; printf("input a string:\n"); gets(s1); k=0; while(s1[k]!=’\0’) {if(s1[k]>=’a’ && s1[k]<=’z’) s1=s1-32; k++; } 四、字符串处理函数
k=0; while(s2[k]!=’\0’) {if(s2[k]>=’a’ && s2[k]<=’z’) s2=s2-32; k++; } if(strcmp(s1,s2)!=0) printf("st1!=st2\n"); else printf("st1=st2\n"); } 四、字符串处理函数 程序运行情况: input a string: Yes↙ st1=st2
4、求字符串长度的函数 strlen (str1) 函数参数为数组名,返回值为数组首字母到‘\0’的长度。并非数组在内存中空间的大小。 四、字符串处理函数
例:写出程序的运行结果。 #include "stdio.h" #include "string.h" void main() { static char st[20]={"hello\0abce\0abc\0"}; printf("%d\n",strlen(st)); } 程序运行结果: 5 四、字符串处理函数
5、strlwr (str1) 将str1中的大写字母转换成小写字母。 6、strupr (str1) 将str1中的小写字母转换成大写字母。 7、函数strncmp(字符串1,字符串2 , maxlen) 函数原型为: int strncmp(char str1[ ], char str2[ ],int m) 说明:a)第三个参数为正整数,它限定了至多比较的字符个数。 b)若串1或串2的长度小于maxlen的值时,函数的功能与strcmp( )相同。 c)当二个字符串的长度均大于maxlen的值时,maxlen为至多要比较的字符个数。 四、字符串处理函数
8、函数strncpy(字符数组名1, 字符串2, maxlen) 函数原型为: void strncmp(char str1[ ], char str2[ ],int m) 说明:a)第三个参数为正整数,它限定了至多拷贝的字符个数。 b)若字符串2的长度小于maxlen的值时,函数的功能与strcpy( )相同。 c)当字符串2的长度大于maxlen的值时,maxlen为至多要拷贝的字符个数。 注意,二字符串之间不能直接进行比较, 赋值等操作, 这些操作必须通过字符串函数来实现。 四、字符串处理函数
例:用选择法对6个数排序(由小到大) 设定一个变量,放入数组中的最小数的序号,然后将其与最上面的数比较交换。 for (i=0; i<n-1; i++) { min=i; for (j=i; j<n ; j++) if (a[min]>a[j]) min=j ; t=a[min]; a[min]=a[i]; a[i]=t; } 四、字符串处理函数
五、 数组与函数 • 1 数组元素做函数参数 • 使用时与普通变量一样 • 值传递方式 实参 形参 在函数调用时将值传递给
例:一个数组中有10个整型元素,求数组中所有素数之和。 int prime(int x) {int f=1,k; if(x==1) f=0; for(k=2;k<=sqrt(x);k++) if(x%k==0) {f=0;break;} return(f); } #include "stdio.h" #include "math.h" void main() {int a[10],i,sum=0; int prime(int x); printf("enter 10 numbers:\n"); for(i=0;i<10;i++) {scanf("%d",&a[i]); if(prime(a[i])) sum+=a[i]; } printf("sum=%d\n",sum); }
五、 数组与函数 2 数组名做函数参数 地址传递方式,实参与形参共地址,相当于对同一对象的两个不同名字。 实参 形参 在函数调用时将其地址值传递给
五、 数组与函数 例:分析下面程序的运行结果。 #include "stdio.h" int f(int b[],int m,int n) { int i,s=0; for(i=m;i<n;i=i+2) s=s+b[i]; return s; } void main() { int x,a[]={1,2,3,4,5,6,7,8,9}; x=f(a,3,7); printf("%d\n",x); }
六、数组程序设计举例 例1:判断一个字符串是否为回文串(回文串指正读反读都一样的字符串,如:字符串“abc121cba”) #include "string.h" #include "stdio.h" void main() {char x[20];int i,j,n; gets(x); n=strlen(x); i=0;j=n-1; while(x[i]==x[j]&&i<j) {i++;j--;} if(i>=j) printf("The number is palindrome"); else printf("The number is not palindrome"); }
例2:输入一个整数,判断该整数是否全部由奇数字组成或全部由偶数字组成。若全部由奇数字组成或全部由偶数字组成,输出“YES!”,否则输出“NO!”。例2:输入一个整数,判断该整数是否全部由奇数字组成或全部由偶数字组成。若全部由奇数字组成或全部由偶数字组成,输出“YES!”,否则输出“NO!”。 #include <conio.h> #include <stdio.h> void main() {char s[20]; int odd=1,even=1; int i; clrscr(); printf("enter a number:"); gets(s);i=0; while(s[i]!='\0') {if((s[i]-48)%2==0) odd=0; else even=0; i++; } if(odd==1 || even==1) printf("YES!"); else printf("NO!"); }
第1趟比较 7 -9 -9 -9 -9 -9 7 7 7 7 13 13 13 6 6 6 6 6 13 13 20 20 20 20 20 第1次 第2次 第3次 第4次 结果 例3:输入5个数,用“起泡法”对这5个数由小到大排序。
第2趟比较 -9 -9 -9 -9 7 7 6 6 6 6 7 7 13 13 13 13 第1次 第2次 第3次 结果
第3趟比较 第4趟比较 -9 -9 -9 -9 -9 6 6 6 6 6 7 第1次 结果 7 7 第1次 第2次 结果
第i趟 剩余数据个数 第i趟比较元素 j的范围[0,N-i] 两两比较次数 1 N a[0]与a[1],a[1]与a[2]...a[N-2]与a[N-1] [0,N-1] N-1 2 N-1 a[0]与a[1],a[1]与a[2]...a[N-3]与a[N-2] [0,N-2] N-2 3 N-2 a[0]与a[1],a[1]与a[2]...a[N-4]与a[N-3] [0,N-3] N-3 ... ... ... ... ... k N-k+1 a[0]与a[1],a[1]与a[2]...a[N-k+1]与a[N-k] [0,N-k] N-k ... ... ... ... ... N-1 2 a[0]与a[1] [0,1] 1 表1 用起泡法为N个数排序的情况分析表
#define N 5 #include "stdio.h" void main() {int a[N],temp,i,j; printf("input numbers:\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]) {temp=a[j];a[j]=a[j+1];a[j+1]=temp;} for(i=0;i<N;i++) printf(“%d ”,a[i]); }