Download presentation
Presentation is loading. Please wait.
1
第7章 构造数据类型 构造数据类型:数组、结构体、共用体、用户自定义类型 7.1 数组
第7章 构造数据类型 构造数据类型:数组、结构体、共用体、用户自定义类型 7.1 数组 一组同类型的若干个(已知个数)多个相关变量的数据集合。 在内存中存放在地址连续的存储单元。
2
一个例子:对三个任意整数从小到大排序。 main() {int a,b,c; scanf(“%d,%d,%d”,&a,&b,&c); if(a>b){t=a;a=b;b=t;} if(a>c) {t=a;a=c;c=t;} if(b>c) {t=b;b=c;b=t;} printf(“%a,%b,%c\n); } 思考:若是10个数、100个数、1000个数…n个数排序又如何? 我们需要通过循环来访问到每个变量,数组能满足这一要求。
3
定义方式: 数据类型 数组名[常量表达式];
7.1.1 一维数组的定义 定义方式: 数据类型 数组名[常量表达式]; 例 int a[6]; 合法标识符 [ ] :数组运算符 单目运算符 优先级(1) 左结合 不能用( ) 表示元素个数 下标从0开始 a[0] 1 4 5 a[1] a[2] a[3] a[4] a[5] 2 3 a 编译时分配连续内存 内存字节数=数组维数* sizeof(元素数据类型) 数组名表示内存首地址, 是地址常量
4
一维数组的引用 例 int i=15; 例 int data[5]; int data[i]; (不能用变量定义数组维数)
data[5]=10; //C语言对数组不作越界检查,使用时要 注意 一维数组的引用 数组必须先定义,后使用 只能逐个引用数组元素,不能一次引用整个数组 数组元素表示形式: 数组名[下标] 其中:下标可以是常量或整型表达式 例 int a[10]; printf(“%d”,a); () 必须 for(j=0;j<10;j++) printf(“%d\t”,a[j]); ()
5
等价于:a[0]=1; a[1]=2; a[2]=3; a[3]=4; a[4]=5;
一维数组的初始化 初始化方式 int a[5]={1,2,3,4,5}; 等价于:a[0]=1; a[1]=2; a[2]=3; a[3]=4; a[4]=5; 在定义数组时,为数组元素赋初值 (在编译阶段使之得到初值) 说明: 数组不初始化,其元素值为随机数 对static数组元素不赋初值,系统会自动赋以0值 只给部分数组元素赋初值 当全部数组元素赋初值时,可不指定数组长度 如 int a[5]={6,2,3}; 等价于: a[0]=6; a[1]=2;a[2]=3; a[3]=0; a[4]=0; 如 int a[3]={6,2,3,5,1}; () static int a[5]; 等价于:a[0]=0; a[1]=0; a[2]=0; a[3]=0; a[4]=0; int a[]={1,2,3,4,5,6}; 编译系统根据初值个数确定数组维数
6
程序举例 #include <stdio.h> #define SIZE 10 main()
{ int x[SIZE],i,max,min; printf("Enter 10 integers:\n"); for(i=0;i<SIZE;i++) { printf("%d:",i+1); scanf("%d",&x[i]); } max=min=x[0]; for(i=1;i<SIZE;i++) { if(max<x[i]) max=x[i]; if(min>x[i]) min=x[i]; printf("Maximum value is %d\n",max); printf("Minimum value is %d\n",min); 例 读10个整数存入数组,找出其中最大值和最小值 步骤: 1. 输入:for循环输入10个整数 2. 处理: (a) 先令max=min=x[0] (b) 依次用x[i]和max,min比较(循环) 若max<x[i],令max=x[i] 若min>x[i],令min=x[i] 3. 输出:max和min
7
#include <stdio.h> main() { int i; int f[20]={1,1};
例 用数组求Fibonacci数列前20个数 f[0] f[1] f[2] f[3] f[4] f[5] f[19] ……... 1 4 5 2 3 19 #include <stdio.h> main() { 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]); } 2 3 5
8
例 用冒泡法对10个数排序 排序过程: (1)比较第一个数与第二个数,若为逆序a[0]>a[1],则交换;然
例 用冒泡法对10个数排序 排序过程: (1)比较第一个数与第二个数,若为逆序a[0]>a[1],则交换;然 后比较第二个数与第三个数;依次类推,直至第n-1个数和第 n个数比较为止——第一趟冒泡排序,结果最大的数被安置在 最后一个元素位置上 (2)对前n-1个数进行第二趟冒泡排序,结果使次大的数被安置在 第n-1个元素位置 (3)重复上述过程,共经过n-1趟冒泡排序后,排序结束
9
38 例 初始关键字 n=8 第一趟 第二趟 第三趟 第四趟 13 第五趟 第六趟 第七趟 49 13 27 38 13 38 49 27 30 76 65 13 27 49 30 38 13 97 49 76 27 65 30 97 27 76 30 65 76 30 97 97
10
#include <stdio.h> main() { int a[11],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]) {t=a[i]; a[i]=a[i+1]; a[i+1]=t;} printf("The sorted numbers:\n"); printf("%d ",a[i]); } 输入n 个数给a[1] 到 a[n] for j=1 to n-1 for i=1 to n-j a[i]>a[i+1] 真 假 a[i]a[i+1] 输出a[1] 到 a[n]
11
例 用简单选择法对10个数排序 排序过程: (1)首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数
例 用简单选择法对10个数排序 排序过程: (1)首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数 交换—第一趟选择排序,结果最小的数被安置在第一个元素位置上 (2)再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录, 将它与第二个数交换—第二趟选择排序 (3)重复上述过程,共经过n-1趟排序后,排序结束
12
k k k 例 i=1 初始: [ ] 13 49 j j j j j j k k i=2 一趟: [ ] 27 38 j j j j j 二趟: [ ] 三趟: [ ] 四趟: [ ] 五趟: [ ] 六趟: [97 ]
13
#include <stdio.h> main() { int a[11],i,j,k,x;
printf("Input 10 numbers:\n"); for(i=1;i<11;i++) scanf("%d",&a[i]); printf("\n"); for(i=1;i<10;i++) { k=i; for(j=i+1;j<=10;j++) if(a[j]<a[k]) k=j; if(i!=k) { x=a[i]; a[i]=a[k]; a[k]=x;} } printf("The sorted numbers:\n"); printf("%d ",a[i]); 输入n 个数给a[1] 到 a[n] for i=1 to n-1 for j=i+1 to n a[j]<a[k] 真 假 k=j 输出a[1] 到 a[n] k=i a[i]a[k] i != k
14
{ int a[N],b[‘B’-60],c[]={1,2,3,4,5,6},i; for(i=0;i<N;i++)
#define N 6 main() { int a[N],b[‘B’-60],c[]={1,2,3,4,5,6},i; for(i=0;i<N;i++) scanf(“%d%d”,&a[i],&b[i]); printf(“%d ”,a[i]); printf(“\n”); printf(“%d ”,b[i]); c[i]=a[i]+b[N-i-1]; printf(“%d ”,c[i]); } 数组定义:必须用常量表达式 数组元素引用
15
7.1.2 二维数组及多维数组 1、二维数组的定义 2、二维数组的初始化 3、二维数组元素的初始化 4、应用举例
16
1、二维数组的定义 定义方式: 数据类型 数组名[常量表达式][常量表达式]; 数组元素的存放顺序 原因:内存是一维的 二维数组:按行序优先
int c[2][3][4] 1 2 3 4 5 6 7 ………... 20 21 22 23 c[0][0][0] c[0][0][1] c[0][0][2] c[0][0][3] c[0][1][0] c[0][1][1] c[0][1][2] c[0][1][3] c[0][2][0] c[0][2][1] c[0][2][2] c[0][2][3] c[1][0][0] c[1][0][1] c[1][0][2] c[1][0][3] c[1][1][0] c[1][1][1] c[1][1][2] c[1][1][3] c[1][2][0] c[1][2][1] c[1][2][2] c[1][2][3] 1、二维数组的定义 定义方式: 数据类型 数组名[常量表达式][常量表达式]; 元素个数=行数*列数 列数 行数 数组元素的存放顺序 原因:内存是一维的 二维数组:按行序优先 多维数组:最右下标变化最快 例 int a[3][4]; float b[2][5]; int c[2][3][4]; int a[3,4]; () int a[3][2] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] 1 4 5 2 3 a[0][0] a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1]
17
二维数组理解 a[0] 例 int a[3][4]; a[1] a[2] 1 4 5 2 3 a[0][1] a[0][2] a[0][3]
1 4 5 2 3 a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[0][0] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[1][2] 6 7 10 11 8 9 a[0] a[1] a[2] 二维数组a是由3个元素组成 例 int a[3][4]; 2016 17 2018 19 2020 21 2022 23 2008 9 2010 11 2012 13 2014 15 2000 1 2002 3 2004 5 20006 7 a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[0] a[1] a[2] 行名 每个元素a[i]由包含4个元素 的一维数组组成
18
2、二维数组元素的初始化 分行初始化: 例 int a[2][3]={{1,2,3},{4,5,6}}; a[0][0] a[0][1]
全部初始化 例 int a[2][3]={{1,2},{4}}; a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 1 2 4 部分初始化 例 int a[][3]={{1},{4,5}}; a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 1 4 5 第一维长度省略初始化 例 int a[2][3]={1,2,4}; a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 1 2 4 部分初始化 按元素排列顺序初始化 例 int a[2][3]={1,2,3,4,5,6}; a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 1 2 3 4 5 6 全部初始化 例 int a[][3]={1,2,3,4,5}; a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 1 2 3 4 5 第一维长度省略初始化
19
h e l l o \0 h e l l o 例 char name[0]; float weight[10.3];
int array[-100]; 例 char str[]=“Hello”; char str[]={‘H’,‘e’,‘l’,‘l’,‘o’}; h e l l o 2 3 1 4 h e l l o \0 5 例 int a[10]; float i=3; a[i]=10; 例 int a[5]; a={2,4,6,8,10}; 例 int a[][10]; float f[2][]={1.2 ,2.2}; 例 比较 int a[2][3]={{5,6},{7,8}}; 与 int a[2][3]={5,6,7,8};
20
二维数组的访问也是通过访问其元素来实现的。二维数组的引用方式为: 数组名[下标表达式][下标表达式] 几点注意:
3、二维数组元素的引用 二维数组的访问也是通过访问其元素来实现的。二维数组的引用方式为: 数组名[下标表达式][下标表达式] 几点注意: ① 二维数组的下标表达式的范围和一维数组类似,可以是整型的变量、常量、表达式。第一维下标的范围是0、1、2……第一维长度-1; 第二维下标范围是0、1、2……第二维长度-1。 在引用每一个数组元素时下标表达式的值不能越界! ② 虽然二维数组是特殊的一维数组,是元素为一维数组的一维数组,但并不能引用数组的行或列,只能引用单个是数组元素。 ③ 二维数组元素的表示方式不能写为如b[1,2]、b[2],[0]、b(1,2)、b(3)(1)的形式,而且两个下标之间也不能有空格。
21
4、程序举例 例 将二维数组行列元素互换,存到另一个数组中 #include <stdio.h> main()
例 将二维数组行列元素互换,存到另一个数组中 #include <stdio.h> 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",b[i][j]); a= b= 1 4 2 5 3 6
22
#include <stdio.h> main() { int a[3][4]={{1,2,3,4}, {9,8,7,6},
{-10,10,-5,2}}; int i,j,row=0,colum=0,max; 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=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
23
例 读入下表中值到数组,分别求各行、各列及表中所有数之和 #include <stdio.h> main()
例 读入下表中值到数组,分别求各行、各列及表中所有数之和 #include <stdio.h> main() { int x[5][4],i,j; for(i=0;i<4;i++) for(j=0;j<3;j++) scanf("%d",&x[i][j]); for(i=0;i<3;i++) x[4][i]=0; for(j=0;j<5;j++) x[j][3]=0; { x[i][3]+=x[i][j]; x[4][j]+=x[i][j]; x[4][3]+=x[i][j]; } for(i=0;i<5;i++) { for(j=0;j<4;j++) printf("%5d\t",x[i][j]); printf("\n"); }
24
{int a[M][N]; int i,j,k,m; int flag=0;
#define M 5 #define N 4 main() {int a[M][N]; int i,j,k,m; int flag=0; printf("please input array:\n"); for(i=0;i<M;i++) for(j=0;j<N;j++) scanf("%d",&a[i][j]); { m=0; for(j=2;j<N;j++) if (a[i][j]<a[i][m]) m=j; for(k=0;k<M;k++) if(a[k][m]>a[i][m]) break; 【例7.4】编程序查找一个矩阵中的鞍点,并输出。 if (k>=M) { flag=1; printf("\n%d,%d,%d", i,m,a[i][m]); } }/*for i*/ if(flag==0)printf("\nnone. "); }/*main*/
25
#include <stdio.h> main() { int k , a[10]; for(k=0;k<10;k++)
例 有十个学生的成绩,求平均分 a a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 92 85 68 54 88 98 45 75 61 79 #include <stdio.h> main() { int k , a[10]; for(k=0;k<10;k++) scanf(“%d”,&a[k]); sum+=a[k]; printf(“Average is %d\n”,sum/10); }
26
求每人的平均成绩,并安平均成绩从大到小排序, 按排序结果输出。
例 有 M 个学生,每个学生 N 门课成绩, 求每人的平均成绩,并安平均成绩从大到小排序, 按排序结果输出。 如原始数据为: 输出数据格式为: 1 2 3 数学 化学 英语 物理 3 2 1 数学 化学 英语 物理
27
7.1.3 字符数组和字符串 1.字符数组的定义和使用 2.字符串和字符数组 3.常用字符串处理函数 4.字符数组应用举例
28
字符数组就是数据类型为“char”的数组 。
1、字符数组的定义和使用 字符数组就是数据类型为“char”的数组 。 定义 例 char ch[5]={‘B’,’o’,’y’}; ch[0] B o y \0 逐个字符赋值 ch[1] ch[2] ch[3] ch[4] 例 char c[10], ch[3][4]; 例 char ch[5]=“Boy”; ch[0] B o y \0 字符串常量赋值 ch[1] ch[2] ch[3] ch[4] 例 char ch[]={‘H’,’e’,’l’,’l’,’o’}; ch[0] H e l o 逐个字符赋值 ch[1] ch[2] ch[3] ch[4] 例 char ch[]=“Hello”; ch[0] H e l o 字符串常量赋值 ch[1] ch[2] ch[3] ch[4] 字符数组的初始化 和前面所讲的数组相同,逐个字符赋值 用字符串常量
29
字符数组的引用: 【例7.5】从键盘输入一行字符,存放在字符数组中,然后 逆序输出。 main() {char a[80],c; int k=0,j; printf("\nplease input the chars: "); scanf("%c",&c); while(c!= '\n') /*输入字符序列输入字符为回车时结束*/ {a[k++]=c; } printf("\n"); for(j=k-1;j>=0;j--) /*逆序输出字符序列*/ printf("%c",a[j]);
30
2.字符串和字符数组 字符串是作为一个整体对待的字符序列。在C语言中, 没有字符串这种数据类型,因此可以将字符串存放在字符数组
中。这是处理字符串的方法之一。 在用字符数组存放字符串时,字符数组必须预先设定足够的长,在足够长的情况下我们一般并不关心数组的具体长度,而是关心有效字符的长度。 对于字符串,并不显式的保存它的长度,而是用字符串结束标志来表示字符串到此结束,隐含着字符串的长度,字符串结束标志也就是前面所介绍的空字符'\0'。 没有‘\0’,不能作为字符串用! 例 char ch[5]={‘H’,’e’,’l’,’l’,’o’}; ch[0] H e l o 逐个字符赋值 ch[1] ch[2] ch[3] ch[4] 例 char ch[6]={“Hello”}; char ch[6]=“Hello”; char ch[]=“Hello”; 用字符串常量 ch[0] H e l o ch[1] ch[2] ch[3] ch[4] \0 ch[5] 例 char ch[5]=“Boy”; ch[0] B o y \0 用字符串常量 ch[1] ch[2] ch[3] ch[4]
31
不但用字符数组存放字符串采用‘\0’表示字符串的结束,
对于字符串常量,也采用字符串结束标志‘\0’来作为结束符。 编译系统在处理字符串时会自动的在字符串的最后一个字符 之后加上‘\0’,也就是说,对于含有n个字符的字符串在内存 中占n+1个字节的空间,因为需要用一个字节来存放字符串结 束标志'\0'。 请注意区分字符常量和字符串常量:字符常量是用单引号引起来的单个字符,字符串常量是用双引号引起来的字符序列,当然,字符序列可以为空,也可以是一个字符。
32
① ""表示空串,在内存中保存的是空字符'\0',占一个字节。
② "A"表示含有一个大写字母A的字符串,在内存中保存的是字母A和空字符'\0',占两个字节。 ③ 'A'表示字母A,在内存中占一个字节。 ④ "ABCDEF"表示含有6个字母的字符串,在内存中占7个字节。 需要注意的是:处理字符串常量的时候,字符串结束标志是编译系统自动添加的,不用人为的在字符串最后加上‘\0’ 。
33
h e l l o \0 h e l l o 例 char name[0]; float weight[10.3];
int array[-100]; 例 char str[]=“Hello”; char str[]={‘H’,‘e’,‘l’,‘l’,‘o’}; h e l l o 2 3 1 4 h e l l o \0 5 例 int a[10]; float i=3; a[i]=10; 例 int a[5]; a={2,4,6,8,10}; 例 int a[][10]; float f[2][]={1.2 ,2.2}; 例 比较 int a[2][3]={{5,6},{7,8}}; 与 int a[2][3]={5,6,7,8};
34
例 char diamond[][5]={{'.', '.','*'},{'.','*','.','*'},
{'*', '.', '.', '.' ,'*'},{'.','*', '.','*'},{'.', '.','*'}}; 二维字符数组初始化 . * \0 diamond[0] diamond[1] diamond[2] diamond[3] diamond[4] 例 char fruit[][7]={“Apple”,”Orange”, ”Grape”,”Pear”,”Peach”}; 二维字符数组初始化 fruit[0] fruit[1] fruit[2] fruit[3] fruit[4] A p l e \0 O r a n g G P c h
35
#include <stdio.h> main()
例 输出一个字符串 I a m b o y 1 2 3 4 5 6 7 8 9 #include <stdio.h> 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"); }
36
h e l l o \0 字符串 字符串及其结束标志 无字符串变量,用字符数组处理字符串 字符串结束标志:‘\0’
内存存放字符ASCII码
37
字符串的输入输出 逐个字符I/O: %c 整个字符串I/O: %s 例 用%c main() { char str[5]; int i;
用字符数组名,不要加& 输入串长度<数组维数 遇空格或回车结束 自动加‘\0’ 例 用%c main() { char str[5]; int i; for(i=0;i<5;i++) scanf(“%c”, &str[i]); printf(“%c”, str[i]); } 例 用%s main() { char str[5]; scanf(“%s”, str); printf(“%s”, str); } 用字符数组名, 遇‘\0’结束
38
h e l l o 例 main( ) { char a[5]={‘H’,’e’,’l’,’l’,’o’}; printf(“%s”,a);
2 3 1 4 结果:Hello#-=* 用“%s”输出时,遇‘\0’结束 例 main( ) { char a[ ]=“Hello”; printf(“%s”,a); } 结果:Hello
39
main() { char a[]={'h','e','l','\0','l','o','\0'}; printf("%s",a); }
例 main() { char a[]={'h','e','l','\0','l','o','\0'}; printf("%s",a); } 输出:hel h e l \0 l o \0 数组中有多个‘\0’时, 遇第一个结束
40
main() { int i; char a[5]; scanf("%s",a); for(i=0;i<5;i++)
printf("%d,",a[i]); } 输入字符串长度<数组维数 h e l \0 h e l l \0 h e l l o 运行情况: (1)若输入 hel , 正常 (2)若输入 hell , 正常 (3)若输入 hello , 用%s 输出时,会出现问题
41
#include <stdio.h> main() { char a[15],b[5],c[5];
运行情况: 输入:How are you? 输出:a=How b=are c=you? 例 字符串输入举例 #include <stdio.h> main() { char a[15],b[5],c[5]; scanf("%s%s%s",a,b,c); printf("a=%s\nb=%s\nc=%s\n",a,b,c); scanf("%s",a); printf("a=%s\n",a); } scanf中%s输入时,遇空格或回车结束 运行情况: 输入:How are you? H o w \0 a r e \0 y o u ? \0
42
例 若准备将字符串“This is a string.”记录下来,
错误的输入语句为: (A)scanf(“%20s”,s); (B)for(k=0;k<17;k++) s[k]=getchar(); (C)while((c=getchar())!=‘\n’) s[k++]=c;
43
例 #include <stdio.h> main( ) { char string[80];
3.常用字符串处理函数 包含在头文件 string.h 例 #include <stdio.h> main( ) { char string[80]; printf(“Input a string:”); gets(string); puts(string); } 输入: How are you? 输出: How are you ? 字符串输出函数puts 格式:puts(字符数组) 功能:向显示器输出字符串(输出完,换行) 说明:字符数组必须以‘\0’结束 字符串输入函数gets 格式:gets(字符数组) 功能:从键盘输入一以回车结束的字符串放入字符数组中, 并自动加‘\0’ 说明:输入串长度应小于字符数组维数
44
例 char str1[20],str2[20]; str1={“Hello!”}; () str2=str1; ()
字符串连接函数strcat 格式:strcat(字符数组1,字符数组2) 功能:把字符数组2连到字符数组1后面 返值:返回字符数组1的首地址 说明:字符数组1必须足够大 连接前,两串均以‘\0’结束;连接后,串1的‘\0’取消, 新串最后加‘\0’ 例 char str1[20],str2[20]; str1={“Hello!”}; () str2=str1; () 字符串拷贝函数strcpy 格式:strcpy(字符数组1,字符串2) 功能:将字符串2,拷贝到字符数组1中去 返值:返回字符数组1的首地址 说明:字符数组1必须足够大 拷贝时‘\0’一同拷贝 不能使用赋值语句为一个字符数组赋值
45
#include <string.h> #include <stdio.h> void main()
例 strcpy与strcat举例 T r b o 1 2 3 4 5 6 7 8 9 u \0 24 ……. T r b o \0 1 2 3 4 5 6 7 8 9 u 24 ……. …... T r b o C + 1 2 3 4 5 6 7 8 9 u \0 24 ……. #include <string.h> #include <stdio.h> void main() { char destination[25]; char blank[] = " ", c[]= "C++", turbo[] = "Turbo"; strcpy(destination, turbo); strcat(destination, blank); strcat(destination, c); printf("%s\n", destination); }
46
例 对于以下字符串,strlen(s)的值为: (1)char s[10]={‘A’,‘\0’,‘B’,‘C’,‘\0’,‘D’};
字符串比较函数strcmp 格式:strcmp(字符串1,字符串2) 功能:比较两个字符串 比较规则:对两串从左向右逐个字符比较(ASCII码), 直到遇到不同字符或‘\0’为止 返值:返回int型整数,a. 若字符串1< 字符串2, 返回负整数 b. 若字符串1> 字符串2, 返回正整数 c. 若字符串1== 字符串2, 返回零 说明:字符串比较不能用“==”,必须用strcmp 字符串长度函数strlen 格式:strlen(字符数组) 功能:计算字符串长度 返值:返回字符串实际长度,不包括‘\0’在内 例 对于以下字符串,strlen(s)的值为: (1)char s[10]={‘A’,‘\0’,‘B’,‘C’,‘\0’,‘D’}; (2)char s[ ]=“\t\v\\\0will\n”; (3)char s[ ]=“\x69\082\n”; 答案:
47
#include <string.h> #include <stdio.h> main()
{ char str1[] = ”Hello!", str2[] = ”How are you?”,str[20]; int len1,len2,len3; len1=strlen(str1); len2=strlen(str2); if(strcmp(str1, str2)>0) { strcpy(str,str1); strcat(str,str2); } else if (strcmp(str1, str2)<0) { strcpy(str,str2); strcat(str,str1); } else strcpy(str,str1); len3=strlen(str); puts(str); printf(”Len1=%d,Len2=%d,Len3=%d\n”,len1,len2,len3); } 例 strcmp与strlen举例 How are you?Hello! Len1=6,Len2=12,Len3=18
48
【例7.6】不使用字符串比较函数,比较两个字符串的大小。
#include "stdio.h" main() {char a[20],b[20]; int k,flag; printf("\nplease input the first string: "); gets(a); /*输入第一个字符串*/ printf("\nplease input the second string: "); gets(b); /*输入第二个字符串*/ k=0; while(a[k]==b[k]&&a[k]!= '\0'&&b[k]!= '\0') k++; /*比较对应字符的大小*/ flag=a[k]-b[k]; printf("\nthe first string "); /*输出比较的结果*/ if (flag==0) printf("="); else if (flag<0) printf("<"); else printf(">"); printf("the second string \n"); }
49
#include "stdio.h" main() {char c[60]; int k; printf("\nplease input the string : "); gets(c); /*输入字符串*/ printf("\n"); k=0; while(c[k]!= '\0') /*以小写形式输出字符串*/ {if (c[k]>= 'a'&&c[k]<= 'z') putchar(c[k]-32); else putchar(c[k]); k++;} while(c[k]!= '\0') /*以大写形式输出字符串*/ {if (c[k]>= 'A'&&c[k]<= 'Z') putchar(c[k]+32); } 【例7.7】输入一个由字母组成的字符串,再分别以大写字母和小写字母形式输出该字符串。
50
#include <stdio.h> main() { char string[81]; int i,num=0,word=0;
应用举例 #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); } 例 输入一行字符,统计其中有多少个单词 输入一字符串给 string i=0 num=0 word=0 当((c=string[i])!=‘\0’) c=空格 真 假 word=0 word=1 num=num+1 i=i+1 输出:num word==0
51
例 输入:I am a boy. 当前字符=空格 是 否 未出现新单词,使word=0,num不累加
是否空格 word原值 新单词开始否 word新值 num值 I a m b o y . 否 是 1 是 1 未 否 是 1 2 否 1 未 2 是 1 未 2 否 是 1 3 是 1 未 3 否 是 1 4 否 1 未 4 否 1 未 4 否 1 未 4
52
#include <stdio.h> #include <string.h> main()
{ char string[20],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); } 例 有三个字符串,找出其中最大者 H o w \0 H e l l o \0 H i g h \0 str[0] str[1] str[2]
53
7.2 结构体 7.2.1 结构体类型定义------形式 7.2.2 结构体变量 1、结构体变量的定义 7.2.3 结构体数组
7.2 结构体 7.2.1 结构体类型定义------形式 结构体变量 1、结构体变量的定义 2、结构体变量的初始化 3、 结构体变量的引用 7.2.3 结构体数组 7.2.4 位段 7.2.5 向函数传递结构体型数据
54
结构体:是一种自定义 de 构造数据类型。 用途:把不同类型的数据组合成一个整体。 7.2.1 结构体类型定义: 合法标识符
可省:无名结构体 7.2.1 结构体类型定义: struct [结构体名] { 类型标识符 成员名; ……………. }; 成员类型可以是 基本型或构造型 struct是关键字, 不能省略
55
… ….. 例 struct student { int num; char name[20]; char sex; int age;
score addr 2字节 20字节 1字节 4字节 30字节 … ….. 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; 结构体类型定义描述结构 的组织形式(图纸),不分配内存 结构体类型的定义
56
7.2.2 结构体变量 1、结构体变量的定义 (1)、先定义结构体类型,再定义结构体变量
结构体变量 1、结构体变量的定义 (1)、先定义结构体类型,再定义结构体变量 一般形式: struct 结构体名 { 类型标识符 成员名; ……………. }; struct 结构体名 变量名表列; 例 #define STUDENT struct student STUDENT { int num; char name[20]; char sex; int age; float score; char addr[30]; }; STUDENT stu1,stu2; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu1,stu2;
57
(2)、定义结构体类型的同时定义结构体变量
一般形式: struct 结构体名 { 类型标识符 成员名; ……………. }变量名表列; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;
58
(3)、直接无名结构体的同时定义结构体变量
一般形式: struct { 类型标识符 成员名; ……………. }变量名表列; 例 struct { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; 用无名结构体直接定义 变量只能一次
59
几点说明 结构体类型与结构体变量概念不同 结构体成员名(域名)与程序中变量名地位相同 结构体可嵌套 例 struct date
类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体成员名(域名)与程序中变量名地位相同 结构体可嵌套 例 struct date { int month; int day; int year; }; struct student { int num; char name[20]; struct date birthday; }stu; num name birthday month day year 例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu; num name birthday month day year
60
2、结构体变量的初始化 和其他类型的变量相同, 在定义结构体变量时赋初值 形式一: 例 struct student { int num;
类型标识符 成员名; ……………. }; struct 结构体名 结构体变量={初始数据}; 例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }; struct student stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
61
形式二: 例 struct student { int num; char name[20]; char sex; int age;
类型标识符 成员名; ……………. }结构体变量={初始数据}; 形式二: 例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
62
形式三: 例 struct { int num; char name[20]; char sex; int age;
类型标识符 成员名; ……………. }结构体变量={初始数据}; 例 struct { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
63
3 结构体变量的引用 引用规则 引用方式: 结构体变量名.成员名 结构体变量不能整体引用,只能引用变量成员 例 struct student
{ int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; printf(“%d,%s,%c,%d,%f,%s\n”,stu1); () stu1={101,“Wan Lin”,‘M’,19,87.5,“DaLian”}; () 引用方式: 结构体变量名.成员名 例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu1,stu2; num name birthday month day year stu1.birthday.month=12; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu1.num=10; stu1.score=85.5; stu1.score+=stu2.score; stu1.age++; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu2=stu1; ( ) 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; if(stu1==stu2) …… () 成员(分量)运算符 优先级: 1 结合性:从左向右 可以将一个结构体变量赋值给另一个结构体变量 结构体嵌套时逐级引用
64
7.2.3 结构体数组 1、结构体数组的定义和初始化 定义:三种形式: 形式一: 形式二: 形式三: struct student
num name sex age stu[0] stu[1] 25B 形式一: struct student { int num; char name[20]; char sex; int age; }; struct student stu[2]; 形式二: struct student { int num; char name[20]; char sex; int age; }stu[2]; 形式三: struct { int num; char name[20]; char sex; int age; }stu[2];
65
初始化:与其他类型的数组赋初值的方法相同
分元素初始化: struct student { int num; char name[20]; char sex; int age; }; struct student stu[ ]={{100,“Wang Lin”,‘M’,20}, {101,“Li Gang”,‘M’,19}, {110,“Liu Yan”,‘F’,19}}; 全部初始化时维数可省 顺序初始化: struct student { int num; char name[20]; char sex; int age; }; struct student stu[ ]={100,“Wang Lin”,‘M’,20, 101,“Li Gang”,‘M’,19, 110,“Liu Yan”,‘F’,19}; 例 struct { int num; char name[20]; char sex; int age; }stu[ ]={{……},{……},{……}};
66
strcpy(stu[0].name,”ZhaoDa”);
2、结构体数组引用 引用方式: 结构体数组名[下标].成员名 num name sex age stu[0] stu[1] 25B stu[1].age++; struct student { int num; char name[20]; char sex; int age; }str[3]; strcpy(stu[0].name,”ZhaoDa”);
67
}leader[3]={“Li”,0,“Zhang”,0,”Wang“,0}; main()
例: 统计后选人选票 struct person { char name[20]; int count; }leader[3]={“Li”,0,“Zhang”,0,”Wang“,0}; main() { int i,j; char leader_name[20]; for(i=1;i<=10;i++) { scanf("%s",leader_name); for(j=0;j<3;j++) if(strcmp(leader_name,leader[j].name)==0) leader[j].count++; } for(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count); name count Li Zhang Wang
68
函数之间的参数传递也可以是结构体型数据,既可以通过参数传送结构体变量的成员,也可以通过参数传递整个结构体变量。
7.2.5 向函数传递结构体型数据 函数之间的参数传递也可以是结构体型数据,既可以通过参数传送结构体变量的成员,也可以通过参数传递整个结构体变量。 1.向函数传递结构体变量的成员 若结构体变量的成员是基本类型,则作函数的实参时的用法与普通变量作函数的实参的用法相同,形参与实参之间仍然是“值传递”的方式。 2.向函数传递结构体变量 ANSI C允许函数之间传递结构体变量。若实参是结构体变量,那么形参也应是同类型的结构体变量。
69
例 用结构体变量作函数参数 (main) (main) (main) (main) a :27 a :27 struct data
例 用结构体变量作函数参数 arg a :27 b: 3 c :30 (main) (func) parm copy arg a :27 b: 3 c :30 (main) (func) parm a :18 b: 5 c :90 arg a :27 b: 3 c :30 (main) arg a :27 b: 3 c :30 (main) struct data { int a, b, c; }; main() { void func(struct data); struct data arg; arg.a=27; arg.b=3; arg.c=arg.a+arg.b; printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c); printf("Call Func()....\n"); func(arg); } void func(struct data parm) { printf("parm.a=%d parm.b=%d parm.c=%d\n",parm.a,parm.b,parm.c); printf("Process...\n"); parm.a=18; parm.b=5; parm.c=parm.a*parm.b; printf("parm.a=%d parm.b=%d parm.c=%d\n",parm.a,parm.b,parm.c); printf("Return...\n");
70
由上面的例子可见:在发生函数调用时,形参结构体变量也要占用内存空间,接收实参结构体变量传递来的信息,因此函数之间传递结构体变量会带来时间和空间的巨大开销;而且,形参与实参之间是“值传递”的方式,被调函数对形参结构体变量的修改并不能传递给实参,即主调函数无法得到处理后的数据,所以虽然语法上允许,但一般很少采用这种传递方式。而是采用传递结构体地址的方法,使得在被调用单位与调用单位函共享结构体变量数据。
71
7.3 共用体 有时需要将几个不同时出现的变量共享一个内存单元,如:将一个整型变量、实型变量、字符型变量共同放入同一个地址空间(当然这几个变量不能同时用),怎么办?C提供了共用体(联合体)类型支持。 共用体类型 union 共用体名 { 类型标识符 成员名; ……………. }; 定义形式: 例 union data { int i; char ch; float f; }; f ch i 100地址开始 类型定义不分配内存
72
7.3.2 共用体变量的定义 1、共用体变量的定义 形式一: union data { int i; char ch; float f;
共用体变量的定义 1、共用体变量的定义 形式一: union data { int i; char ch; float f; }; union data a,b,c,*p,d[3]; 形式二: union data { int i; char ch; float f; }a,b; 形式三: union { int i; char ch; float f; }a,b,c; f ch i a b 共用体变量任何时刻 只有一个成员存在 共用体变量定义分配内存, 长度=最长成员所占字节数
73
p->i p->ch p->f
2 共用体变量引用 引用方式: 共用体指针名->成员名 共用体变量名.成员名 (*共用体指针名).成员名 引用规则 不能引用共用体变量,只能引用其成员 union data { int i; char ch; float f; }; union data a,b,c,*p,d[3]; a.i a.ch a.f p->i p->ch p->f (*p).i (*p).ch (*p).f d[0].i d[0].ch d[0].f 共用体变量中起作用的成员是最后一次存放的成员 不能在定义共用体变量时初始化 例 union { int i; char ch; float f; }a; a=1; () 例 a.i=1; a.ch=‘a’; a.f=1.5; printf(“%d”,a.i); (编译通过,运行结果不对) 例 float x; union { int i; char ch; float f; }a,b; a.i=1; a.ch=‘a’; a.f=1.5; b=a; () x=a.f; () 例 union { int i; char ch; float f; }a={1,’a’,1.5}; () 可以用一个共用体变量为另一个变量赋值
74
x.ch[0],x.ch[1],x.ch[0],x.ch[1]); }
例 将一个整数按字节输出 main() { union int_char { int i; char ch[2]; }x; x.i=24897; printf("i=%o\n",x.i); printf("ch0=%o,ch1=%o\n ch0=%c,ch1=%c\n", x.ch[0],x.ch[1],x.ch[0],x.ch[1]); } 低字节 高字节 ch[0] ch[1] 运行结果: i=60501 ch0=101,ch1=141 ch0=A,ch1=a
75
结构体与共用体 区别: 存储方式不同 struct node { char ch[2]; ch int k; a }a; k
union node }b; a ch k b 变量的各成员同时存在 任一时刻只有一个成员存在 联系: 两者可相互嵌套
76
例: 结构体中嵌套共用体 struct { int num; char name[10]; char sex; char job;
class position Li Wang 1011 2086 F M S T 501 prof 例: 结构体中嵌套共用体 struct { int num; char name[10]; char sex; char job; union { int class; char position[10]; }category; }person[2]; 循环n次 读入姓名、号码、性别、职务 job==‘s’ 真 假 读入class 读入 position 输出 “输入错” 输出:姓名,号码, 性别,职业,班级 性别,职业,职务 job==‘t’
77
例共用体中嵌套结构体,机器字数据与字节数据的处理
struct w_tag { char low; char high; }; union u_tag { struct w_tag byte_acc; int word_acc; }u_acc; 低字节 高字节 low high 0x1234 低字节 高字节 low high 0x12ff word_acc byte_acc.low byte_acc.high u_acc
78
7.5 用typedef 定义已知类型 功能:用自定义名字为已有数据类型命名 类型定义简单形式: typedef type name;
例 typedef int INTEGER; 例 INTEGER a,b,c; REAL f1,f2; 类型定义语句关键字 已有数据类型名 用户定义的类型名 例 typedef float REAL; int a,b,c; float f1,f2; 类型定义后,与已有类型一样使用 说明: 1.typedef 没有创造新数据类型 2.typedef 是定义类型,不能定义变量 3.typedef 与 define 不同 define typedef 预编译时处理 编译时处理 简单字符置换 为已有类型命名
79
typedef定义类型步骤 类型定义可嵌套 按定义变量方法先写出定义体 如 int i; 将变量名换成新类型名 如 int INTEGER;
最前面加typedef 如 typedef int INTEGER; 用新类型名定义变量 如 INTEGER i,j; 类型定义可嵌套 例 定义结构体类型 struct date { int month; int day; int year; }d; 例 定义结构体类型 struct date { int month; int day; int year; }DATE; 例 定义数组类型 int a[100]; int ARRAY[100]; typedef int ARRAY[100]; ARRAY a,b,c; 例 定义指针类型 char *str; char *STRING; typedef char *STRING; STRING p,s[10]; 例 定义函数指针类型 int (*p)(); int (*POWER)(); typedef int (*POWER)(); POWER p1,p2; 例 定义结构体类型 typedef struct date { int month; int day; int year; }DATE; 例 定义结构体类型 DATE birthday, *p; GROUP为结构体类型 PG为指向GROUP的指针类型 例 typedef struct club { char name[20]; int size; int year; }GROUP; typedef GROUP *PG; PG pclub; struct date { int month; int day; int year; }birthday, *p; int (*p1)(),(*p2)(); int a[100],b[100],c[100]; char *p; char *s[10]; GROUP *pclub; struct club *pclub;
Similar presentations