第 7章 构造数据类型
构造数据类型,数组、结构体,共用体、用户自定义类型
§ 7.1 数组一组同类型的若干个(已知个数)多个相关变量的数据集合。
在内存中存放在地址连续的存储单元。
一个例子:对三个任意整数从小到大排序。
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 个数排序又如何?
我们需要通过循环来访问到每个变量,数组能满足这一要求。
7.1.1 一维数组的定义
定义方式,数据类型 数组名 [常量 表达式 ];
合法标识符表示元素个数下标从 0开始
[ ],数组运算符单目运算符优先级 (1)
左结合不能用 ( )
例 int a[6];
a[0]0
1
4
5
a[1]
a[2]
a[3]
a[4]
a[5]
2
3
a
编译时分配连续内存内存字节数 =数组维数 *
sizeof(元素数据类型数组名表示内存首地址,
是 地址常量
一维数组的引用
数组必须 先定义,后使用
只能逐个引用数组元素,不能一次引用整个数组
数组元素表示形式,数组名 [下标 ]
其中:下标可以是常量或整型表达式例 int i=15;
int data[i]; (?不能用变量定义数组维数 )
例 int a[10];
printf(“%d”,a); (?)
必须 for(j=0;j<10;j++)
printf(“%d\t”,a[j]); (?)
例 int data[5];
data[5]=10; //C语言对数组不作越界检查,使用时要 注意
一维数组的初始化
初始化方式在定义数组时,为数组元素赋初值
(在编译阶段使之得到初值)
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 i t ;
等价于,a[0]=0; a[1]=0; a[2]=0; a[3]=0; a[4]=0;
只给部分数组元素赋初值
int a[]={1,2,3,4,5,6};
编译系统根据初值个数确定数组维数
程序举例例 读 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
#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);
}
例 用数组求 Fibonacci数列前 20个数
f[0]
f[1]
f[2]
f[3]
f[4]
f[5]
f[19]
……...
1
1
f[19]
0
1
4
5
2
3
19
2
3
5
#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]);
}
}
例 用冒泡法对 10个数排序排序过程:
( 1)比较第一个数与第二个数,若为逆序 a[0]>a[1],则交换;然后比较第二个数与第三个数;依次类推,直至第 n-1个数和第
n个数比较为止 ——第一趟冒泡排序,结果 最大 的数被安置在最后一个元素位置上
( 2)对前 n-1个数进行第二趟冒泡排序,结果使 次大 的数被安置在第 n-1个元素位置
( 3)重复上述过程,共经过 n-1趟冒泡排序后,排序结束例 38
49
65
76
13
27
30
97第一趟
38
49
65
13
27
30
76
第二趟
38
49
13
27
30
65
第三趟
38
13
27
30
49
第四趟
13
27
30
38
第五趟
13
27
30
第六趟
49
38
65
97
76
13
27
30初始关键字
n=8
38
49
76
9713
9727
9730
97
13
76
76
7627
30
13
6527
6530
65
13
13
49
4930
4927
3827
3830
38
13
27
第七趟输入 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]
#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");
for(i=1;i<11;i++)
printf("%d ",a[i]);
}
例 用简单选择法对 10个数排序排序过程:
( 1)首先通过 n-1次比较,从 n个数中找出最小的,将它与第一个数交换 —第一趟选择排序,结果 最小 的数被安置在第一个元素位置上
( 2)再通过 n-2次比较,从剩余的 n-1个数中找出关键字 次小 的记录,
将它与第二个数交换 —第二趟选择排序
( 3)重复上述过程,共经过 n-1趟排序后,排序结束例 初始,[ 49 38 65 97 76 13 27 ]
k
j
i=1 13 49
一趟,13 [38 65 97 76 49 27 ]i=2 27 38
二趟,13 27 [65 97 76 49 38 ]
三趟,13 27 38 [97 76 49 65 ]
四趟,13 27 38 49 [76 97 65 ]
五趟,13 27 38 49 65 [97 76 ]
六趟,13 27 38 49 65 76 [97 ]
k
kk
k
j j j j j
j j j j j
输入 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真 假
#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");
for(i=1;i<11;i++)
printf("%d ",a[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]);
for(i=0;i<N;i++)
printf(“%d,,a[i]);
printf(“\n”);
for(i=0;i<N;i++)
printf(“%d,,b[i]);
printf(“\n”);
for(i=0;i<N;i++)
c[i]=a[i]+b[N-i-1];
for(i=0;i<N;i++)
printf(“%d,,c[i]);
}
数组定义:必须用 常量 表达式数组元素引用
§ 7.1.2 二维数组及多维数组
1、二维数组的定义
2、二维数组的初始化
3、二维数组元素的初始化
4、应用举例
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]
0
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]
int c[2][3][4]
0
1
2
34
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]
二维数组理解例 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
7a[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[i]由包含 4个元素的一维数组组成二维数组 a是由 3个元素组成
a[0]
a[1]
a[2]
行名
0
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]
2、二维数组元素的初始化
分行初始化:
例 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[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 0 4 0 0
部分初始化例 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 0 0 4 5 0
第一维 长度省略初始化例 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[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 0 0 0
部分初始化例 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 0
第一维 长度省略初始化例 比较 int a[2][3]={{5,6},{7,8}};
与 int a[2][3]={5,6,7,8};
5 6 0
7 8 0
5 6 7
8 0 0
例 int a[][10];
float f[2][]={1.2,2.2};
例 int a[5];
a={2,4,6,8,10};
例 int a[10];
float i=3;
a[i]=10;
例 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
0 2 31 4
h e l l o \0
0 2 31 4 5
3、二维数组元素的引用二维数组的访问也是通过访问其元素来实现的。
二维数组的引用方式为:
数组名 [下标表达式 ][下标表达式 ]
几点注意:
① 二维数组的下标 表达式 的范围和一维数组类似,可以是整型的变量,常量,表达式 。 第一维下标的范围是 0,1、
2…… 第一维长度 -1; 第二维下标范围是 0,1,2…… 第二维长度 -1。
在引用每一个数组元素时下 标 表达式的值不能越界!
② 虽然二维数组是特殊的一维数组,是元素为一维数组的一维数组,但并不能引用数组的行或列,只能引用单个是数组元素 。
③ 二维数组元素的表示方式不能写为如 b[1,2]、
b[2],[0],b(1,2),b(3)(1)的形式,而且两个下标之间也不能有空格 。
4,程序举例例 将二维数组行列元素互换,存到另一个数组中
a= 1 2 34 5 6 b= 1 42 5
3 6
#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]);
printf("\n");
}
}
例 求二维数组中最大元素值及其行列号
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
#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);
}
例 读入下表中值到数组,分别求各行、各列及表中所有数之和
12 4 6
15 7 9
8 23 3
2 5 17
12 4 6 22
15 7 9 31
8 23 3 34
2 5 17 24
37 39 35 111
#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;
for(i=0;i<4;i++)
for(j=0;j<3;j++)
{ 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");
}
}
【 例 7.4】 编程序查找一个矩阵中的鞍点,并输出。
32 30 56 49
15 7 9 31
8 23 3 34
2 5 17 24
37 19 35 111
#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]);
for(i=0;i<M;i++)
{ 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;
if (k>=M)
{ flag=1;
printf("\n%d,%d,%d",
i,m,a[i][m]);
}
}/*for i*/
if(flag==0)printf("\nnone,");
}/*main*/
例 有十个学生的成绩,求平均分
92 85 68 75 54 88 98 45 61 79
92
85
68
54
88
98
45
75
61
79
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
a[6]
a[7]
a[8]
a[9]
a#include <stdio.h>
main()
{ int k,a[10];
for(k=0;k<10;k++)
scanf(“%d”,&a[k]);
for(k=0;k<10;k++)
sum+=a[k];
printf(“Average is %d\n”,sum/10);
}
例 有 M 个学生,每个学生 N 门课成绩,
求每人的平均成绩,并安平均成绩从大到小排序,
按排序结果输出。
62 75 68 75
54 88 98 45
91 79 81 70
1
2
3
数学 化学英语 物理如原始数据为:
91 79 81 70 80.25
54 88 98 45 71.25
62 75 68 75 70.0
3
2
1
数学 化学英语 物理输出数据格式为:
§ 7.1.3 字符数组和字符串
1.字符数组的定义和使用
2.字符串和字符数组
3.常用字符串处理函数
4.字符数组应用举例
1,字符数组的定义和使用字符数组就是数据类型为? char”的数组 。
定义
字符数组的初始化
和前面所讲的数组相同,逐个字符赋值例 char c[10],ch[3][4];
例 char ch[]={?H?,?e?,?l?,?l?,?o?};
ch[0]
H e l l o
逐个字符赋值
ch[1] ch[2] ch[3] ch[4]
例 char ch[5]={?B?,?o?,?y?};
ch[0]
B o y \0 \0
逐个字符赋值
ch[1] ch[2] ch[3] ch[4]
用字符串常量 例 char ch[5]=“Boy”;
ch[0]
B o y \0 \0
字符串常量赋值
ch[1] ch[2] ch[3] ch[4]
例 char ch[]=,ello”;
ch[0]
H e l l o
字符串常量赋值
ch[1] ch[2] ch[3] ch[4]
字符数组的引用,
【 例 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;
scanf("%c",&c);
}
printf("\n");
for(j=k-1;j>=0;j--) /*逆序输出字符序列 */
printf("%c",a[j]);
}
字符串是作为一个整体对待的字符序列。在C语言中,
没有字符串这种数据类型,因此可以将字符串存放在字符数组中。这是处理字符串的方法之一。
例 char ch[5]=“Boy”;
ch[0]
B o y \0 \0
用字符串常量
ch[1] ch[2] ch[3] ch[4]
例 char ch[6]={“Hello”};
char ch[6]=“Hello”;
char ch[]=“Hello”;
用字符串常量
ch[0]
H e l l o
ch[1] ch[2] ch[3] ch[4]
\0
ch[5]
2.字符串和字符数组在用字符数组存放字符串时,字符数组必须预先设定足够的长,在足够长的情况下我们一般并不关心数组的具体长度,而是关心有效字符的长度 。
对于字符串,并不显式的保存它的长度,而是用字符串结束标志来表示字符串到此结束,隐含着字符串的长度,字符串结束标志也就是前面所介绍的空字符 '\0'。
没有‘ \0?,不能作为字符串用例 char ch[5]={?H?,?e?,?l?,?l?,?o?};
ch[0]
H e l l o
逐个字符赋值
ch[1] ch[2] ch[3] ch[4]
请注意区分字符常量和字符串常量:字符常量是用单引号引起来的单个字符,字符串常量是用双引号引起来的字符序列,当然,字符序列可以为空,也可以是一个字符。
不但用字符数组存放字符串采用 ‘ \0?表示字符串的结束,
对于字符串常量,也采用字符串结束标志 ‘ \0?来作为结束符。
编译系统在处理字符串时会自动的在字符串的最后一个字符之后加上 ‘ \0?,也就是说,对于含有 n个字符的字符串在内存中占 n+1个字节的空间,因为需要用一个字节来存放字符串结束标志 '\0'。
① ""表示空串,在内存中保存的是空字符 '\0',占一个字节 。
② "A"表示含有一个大写字母A的字符串,在内存中保存的是字母 A和空字符 '\0',占两个字节 。
③ 'A'表示字母 A,在内存中占一个字节 。
④ "ABCDEF"表示含有6个字母的字符串,在内存中占 7个字节
。
需要注意的是,处理字符串常量的时候,字符串结束标志是编译系统自动添加的,不用人为的在字符串最后加上 ‘ \0?
。
例 比较 int a[2][3]={{5,6},{7,8}};
与 int a[2][3]={5,6,7,8};
5 6 0
7 8 0
5 6 7
8 0 0
例 int a[][10];
float f[2][]={1.2,2.2};
例 int a[5];
a={2,4,6,8,10};
例 int a[10];
float i=3;
a[i]=10;
例 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
0 2 31 4
h e l l o \0
0 2 31 4 5
例 char diamond[][5]={{'.','.','*'},{'.','*','.','*'},
{'*','.','.','.','*'},{'.','*','.','*'},{'.','.','*'}};
二维字符数组初始化
.,* \0 \0
,*,* \0
*,,,*
,*,* \0
.,* \0 \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 p l e \0 \0
O r a n g e \0
G r a p e \0 \0
P e a r \0 \0 \0
P e a c h \0 \0
例 输出一个字符串
#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");
}
I
a
m
a
b
o
y
0
1
2
3
4
5
6
7
8
9
字符串
字符串及其结束标志
无字符串变量,用字符数组处理字符串
字符串结束标志:‘ \0’
例? hello”共 5个字符,在内存占 6个字节 字符串长度 5
h e l l o \0
104 101 108 108 111 0
内存存放字符 ASCII码
字符串的输入输出
逐个字符 I/O,%c
整个字符串 I/O,%s
例 用 %c
main()
{ char str[5];
int i;
for(i=0;i<5;i++)
scanf(“%c”,&str[i]);
for(i=0;i<5;i++)
printf(“%c”,str[i]);
}
例 用 %s
main()
{ char str[5];
scanf(“%s”,str);
printf(“%s”,str);
}
用字符数组名,不要加 &
输入串长度 <数组维数遇空格或回车结束自动加‘ \0?
用字符数组名,
遇‘ \0?结束例 main( )
{ char a[5]={?H?,?e?,?l?,?l?,?o?};
printf(“%s”,a);
}
例 main( )
{ char a[ ]=“Hello”;
printf(“%s”,a);
}
结果,Hello#-=*
h e l l o
0 2 31 4
结果,Hello
用? %s”输出时,遇 ‘ \0?结束
main()
{
char a[]={'h','e','l','\0','l','o','\0'};
printf("%s",a);
}
例输出,hel h e l \0 l o \0
数组中有多个 ‘ \0?时,
遇第一个结束
main()
{
int i;
char a[5];
scanf("%s",a);
for(i=0;i<5;i++)
printf("%d,",a[i]);
}
运行情况:
( 1)若输入 hel,正常
( 2)若输入 hell,正常
( 3)若输入 hello,用 %s 输出时,会出现问题
h e l \0
h e l l \0
h e l l o
输入字符串长度 <数组维数例 字符串输入举例
H o w \0
a r e \0
y o u? \0
#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);
}
运行情况:
输入,How are you?
输出,a=How
b=are
c=you?
输入,How are you?
输出,a=How
scanf中 %s输入时,遇空格或回车结束运行情况:
输入,How are you?
例 若准备将字符串,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;
3.常用字符串处理函数包含在头文件 string.h
字符串输出函数 puts
格式,puts(字符数组 )
功能:向显示器输出字符串(输出完,换行)
说明:字符数组必须以‘ \0?结束
字符串输入函数 gets
格式,gets(字符数组 )
功能:从键盘输入一以 回车结束 的字符串放入字符数组中,
并自动加‘ \0’
说明:输入串长度应小于字符数组维数例 #include <stdio.h>
main( )
{ char string[80];
printf(“Input a string:”);
gets(string);
puts(string);
}
输入,How are you?
输出,How are you?
字符串连接函数 strcat
格式,strcat(字符数组 1,字符数组 2)
功能:把字符数组 2连到字符数组 1后面返值:返回字符数组 1的首地址说明,?字符数组 1必须足够大
连接前,两串均以‘ \0’结束 ;连接后,串 1的‘ \0’取消,
新串最后加‘ \0’
字符串拷贝函数 strcpy
格式,strcpy(字符数组 1,字符串 2)
功能:将字符串 2,拷贝到字符数组 1中去返值:返回字符数组 1的首地址说明,?字符数组 1必须足够大
拷贝时‘ \0’一同拷贝
不能使用赋值语句为一个字符数组赋值例 char str1[20],str2[20];
str1={“Hello!”}; (?)
str2=str1; (?)
例 strcpy与 strcat举例
#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);
}
T
r
b
o
C
+
+
0
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
\0
24
…….
…….
T
r
b
o
\0
0
1
2
3
4
5
6
7
8
9
u
24
…….
…...
字符串比较函数 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”; 答案,1 3 1
#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
【 例 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");
}
#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++;}
printf("\n");
k=0;
while(c[k]!= '\0') /*以大写形式输出字符串 */
{if (c[k]>= 'A'&&c[k]<= 'Z') putchar(c[k]+32);
else putchar(c[k]);
k++;}
}
【 例 7.7】 输入一个由字母组成的字符串,再分别以大写字母和小写字母形式输出该字符串。
应用举例例 输入一行字符,统计其中有多少个单词输入一字符串给 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
#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);
}
当前字符 =空格是否未出现新单词,使 word=0,num不累加前一字符为空格 (word==0),新单词出现,
word=1,num加 1
前一字符为非空格 (word==1),未出现新单词,num不变否
0
是
1
1
是
1
未
0
1
否
0
是
1
2
否
1
未
1
2
是
1
未
0
2
否
0
是
1
3
是
1
未
0
3
否
0
是
1
4
否
1
未
1
4
否
1
未
1
4
否
1
未
1
4
例 输入,I?am?a?boy.
当前字符是否空格
word原值新单词开始否
word新值
num值
I a m a b o y,
例 有三个字符串,找出其中最大者
H o w \0
H e l l o \0
H i g h \0
str[0]
str[1]
str[2]
#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);
}
7.2.1 结构体类型定义 ------形式
7.2.2 结构体变量
1、结构体变量的定义
2、结构体变量的初始化
3,结构体变量的引用
7.2.3 结构体数组
7.2.4 位段
7.2.5 向函数传递结构体型数据
§ 7.2 结构体结构体:是 一种 自定义 de 构造 数据类型。
用途:把 不同类型 的数据组合成一个整体。
struct [结构体名 ]
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
成员类型可以是基本型或构造型struct是 关键字,
不能省略合法标识符可省,无名结构体7.2.1 结构体类型定义,
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
name
num
sex
age
score
addr
2字节
2字节
20字节
1字节
4字节
30字节
…
…..
结构体 类型 定义描述结构的组织形式(图纸),不分配内存结构体类型的定义例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
7.2.2 结构体变量
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;
(2)、定义结构体类型的同时定义结构体变量一般形式:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列 ;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
(3)、直接无名结构体的同时定义结构体变量一般形式,struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列 ;
例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
用 无名结构体 直接定义变量 只能一次
几点说明
结构体类型与结构体变量概念不同
类型,不分配内存 ; 变量,分配内存
类型,不能赋值、存取、运算 ; 变量,可以
结构体成员名 (域名)与程序中变量名地位相同
结构体可嵌套例 struct date
{ int month;
int day;
int year;
};
struct student
{ int num;
char name[20];
struct date birthday;
}stu;
num name birthdaymonth day year
例 struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu;
num name birthdaymonth day year
2、结构体变量的初始化和其他类型的变量相同,
在定义结构体变量时赋初值形式一:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
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”};
形式二,struct 结构体名{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
形式三,struct{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
3 结构体变量的引用
引用规则
结构体变量 不能整体引用,只能引用变量 成员
可以将一个 结构体变量赋值给另一个结构体变量
结构体嵌套时 逐级引用成员 (分量 )运算符优先级,1
结合性,从左向右引用方式,结构体变量名,成员名例 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;
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];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
stu2=stu1; ( )
例 struct student
{ int n m;
char a e[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu1,stu2;
num name birthdaymonth day year
stu1.birthday.month=12;例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
if(stu1==stu2)
…….,(?)
7.2.3 结构体数组
1、结构体数组的定义和初始化定义:三种形式:
形式一,
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];
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
初始化:与其他类型的数组赋初值的方法相同例 struct
{ int num;
char name[20];
char sex;
int age;
}stu[ ]={{……},{……},{……}};
顺序初始化,
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 Ya,,?F?,19}};
全部初始化时维数可省
2、结构体数组引用引用方式,结构体数组名 [下标 ].成员名
stu[1].age++;
struct student
{ int num;
char name[20];
char sex;
int age;
}str[3];
strcpy(stu[0].name,”ZhaoDa”);
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
例,统计后选人选票
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
0
0
0
7.2.5 向函数传递结构体型数据函数之间的参数传递也可以是结构体型数据,既可以通过参数传送结构体变量的成员,也可以通过参数传递整个结构体变量 。
1.向函数传递结构体变量的成员若结构体变量的成员是基本类型,则作函数的实参时的用法与普通变量作函数的实参的用法相同,形参与实参之间仍然是,值传递,的方式 。
2.向函数传递结构体变量
ANSI C允许函数之间传递结构体变量 。 若实参是结构体变量,那么形参也应是同类型的结构体变量 。
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);
printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c);
}
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");
}
arga,27b,3
c,30
(main)
(func)
parm
a,27
b,3
c,30
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
ain)例 用结构体变量作函数参数由上面的例子可见:在发生函数调用时,
形参结构体变量也要占用内存空间,接收实参结构体变量传递来的信息,因此函数之间传递结构体变量会带来时间和空间的巨大开销;而且,形参与实参之间是? 值传递? 的方式,被调函数对形参结构体变量的修改并不能传递给实参,即主调函数无法得到处理后的数据,所以虽然语法上允许,但一般很少采用这种传递方式 。 而是采用传递结构体地址的方法,使得在被调用单位与调用单位函共享结构体变量数据 。
§ 7.3 共用体有时需要将几个不同时出现的变量共享一个内存单元,如:将一个整型变量、实型变量、字符型变量共同放入同一个地址空间(当然这几个变量不能同时用),怎么办? C提供了共用体(联合体)类型支持 。
7.3.1 共用体类型 union 共用体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};例 union data
{ int i;
char ch;
float f;
}; 类型定义 不分配内存fch
i
100地址开始定义形式:
形式二,
union data
{ int i;
char ch;
float f;
}a,b;
形式一,
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
形式三,
union
{ int i;
char ch;
float f;
}a,b,c;
7.3.2 共用体变量的定义
f
ch
i
f
ch
i
a b
共用体 变量定义 分配内存,
长度 =最长成员 所占字节数共用体 变量任何时刻只有 一个成员 存在
1、共用体变量的定义
2 共用体变量引用
引用方式:
例 a.i=1;
a.ch=?a?;
a.f=1.5;
printf(“%d”,a.i); (?编译通过,运行结果不对 )
引用规则
不能引用共用体变量,只能 引用其成员共用体指针名 ->成员名共用体变量名,成员名 (*共用体指针名 ).成员名
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; (?)
不能 在定义共用体变量时 初始化例 union
{ int i;
char ch;
float f;
}a={1,?a?,1.5}; (?)
可以用一个共用体变量为另一个变量赋值 例 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; (?)
例 将一个整数按字节输出
01100001 01000001
低字节高字节
01000001
01100001
ch[0]
ch[1]
运行结果:
i=60501
ch0=101,ch1=141
ch0=A,ch1=a
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]);
}
结构体与共用体
区别,存储方式不同
struct node
{ char ch[2];
int k;
}a;
union node
{ char ch[2];
int k;
}b;
achk
bch k
变量的各成员同时存在任一时刻只有一个成员存在
联系,两者可相互嵌套例,结构体中嵌套共用体
name num sex job class position
Li
Wang
1011
2086
F
M
S
T
501
prof
循环 n次读入姓名、号码、性别、职务
job==?s?真真 假假读入 class 读入
position
输出
“输入错”
循环 n次
job==?s?真 假输出,姓名,号码,
性别,职业,班级输出,姓名,号码,
性别,职业,职务
job==?t?
struct
{ int num;
char name[10];
char sex;
char job;
union
{ int class;
char position[10];
}category;
}person[2];
例共用体中嵌套结构体,机器字数据与字节数据的处理
00010010 00110100
低字节高字节
00110100
00010010
low
high
0x1234
00010010 11111111
低字节高字节
11111111
00010010
low
high
0x12ff
struct w_tag
{ char low;
char high;
};
union u_tag
{ struct w_tag byte_acc;
int word_acc;
}u_acc;
word_acc byte_acc.lowbyte_acc.high
u_acc
§ 7.5 用 typedef 定义 已知 类型
功能,用自定义名字为 已有 数据类型命名
类型定义 简单形式,typedef type name;
例 typedef int INTEGER;类型定义语句关键字 已有数据类型名 用户定义的类型名例 typedef float REAL;
类型定义后,与已有类型一样使用例 INTEGER a,b,c;
REAL f1,f2;
int a,b,c;
float f1,f2; 说明,1.typedef 没有创造 新数据类型
2.typedef 是定义类型,不能定义变量
3.typedef 与 define 不同
define typedef
预编译时处理 编译时处理简单字符置换 为已有类型命名
typedef定义类型步骤
按定义变量方法先写出定义体 如 int i;
将变量名换成新类型名 如 int INTEGER;
最前面加 typedef 如 typedef int INTEGER;
用新类型名定义变量 如 INTEGER i,j;
例 定义数组类型
int a[100];
int ARRAY[100];
typedef int ARRAY[100];
ARRAY a,b,c;
int a[100],b[100],c[100];
例 定义指针类型
char *str;
char *STRING;
typedef char *STRING;
ST ING p,s[10];
char *p;
char *s[10];
例 定义函数指针类型
int (*p)();
int (*POWER)();
typedef int (*POWER)();
POWER p1,p2;
int (*p1)(),(*p2)();
例 定义结构体类型
struct date
{ int month;
int day;
int year;
}d;
例 定义结构体类型
struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
typedef struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
DATE birthday,*p;
struct date
{ int month;
int day;
int year;
}birthday,*p;
类型定义可嵌套例 typedef struct club
{ char name[20];
int size;
int year;
}GROUP;
typedef GROUP *PG;
PG pclub;
GROUP *pclub;
struct club *pclub;
GROUP为结构体类型
PG为指向 GROUP的指针类型
构造数据类型,数组、结构体,共用体、用户自定义类型
§ 7.1 数组一组同类型的若干个(已知个数)多个相关变量的数据集合。
在内存中存放在地址连续的存储单元。
一个例子:对三个任意整数从小到大排序。
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 个数排序又如何?
我们需要通过循环来访问到每个变量,数组能满足这一要求。
7.1.1 一维数组的定义
定义方式,数据类型 数组名 [常量 表达式 ];
合法标识符表示元素个数下标从 0开始
[ ],数组运算符单目运算符优先级 (1)
左结合不能用 ( )
例 int a[6];
a[0]0
1
4
5
a[1]
a[2]
a[3]
a[4]
a[5]
2
3
a
编译时分配连续内存内存字节数 =数组维数 *
sizeof(元素数据类型数组名表示内存首地址,
是 地址常量
一维数组的引用
数组必须 先定义,后使用
只能逐个引用数组元素,不能一次引用整个数组
数组元素表示形式,数组名 [下标 ]
其中:下标可以是常量或整型表达式例 int i=15;
int data[i]; (?不能用变量定义数组维数 )
例 int a[10];
printf(“%d”,a); (?)
必须 for(j=0;j<10;j++)
printf(“%d\t”,a[j]); (?)
例 int data[5];
data[5]=10; //C语言对数组不作越界检查,使用时要 注意
一维数组的初始化
初始化方式在定义数组时,为数组元素赋初值
(在编译阶段使之得到初值)
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 i t ;
等价于,a[0]=0; a[1]=0; a[2]=0; a[3]=0; a[4]=0;
只给部分数组元素赋初值
int a[]={1,2,3,4,5,6};
编译系统根据初值个数确定数组维数
程序举例例 读 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
#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);
}
例 用数组求 Fibonacci数列前 20个数
f[0]
f[1]
f[2]
f[3]
f[4]
f[5]
f[19]
……...
1
1
f[19]
0
1
4
5
2
3
19
2
3
5
#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]);
}
}
例 用冒泡法对 10个数排序排序过程:
( 1)比较第一个数与第二个数,若为逆序 a[0]>a[1],则交换;然后比较第二个数与第三个数;依次类推,直至第 n-1个数和第
n个数比较为止 ——第一趟冒泡排序,结果 最大 的数被安置在最后一个元素位置上
( 2)对前 n-1个数进行第二趟冒泡排序,结果使 次大 的数被安置在第 n-1个元素位置
( 3)重复上述过程,共经过 n-1趟冒泡排序后,排序结束例 38
49
65
76
13
27
30
97第一趟
38
49
65
13
27
30
76
第二趟
38
49
13
27
30
65
第三趟
38
13
27
30
49
第四趟
13
27
30
38
第五趟
13
27
30
第六趟
49
38
65
97
76
13
27
30初始关键字
n=8
38
49
76
9713
9727
9730
97
13
76
76
7627
30
13
6527
6530
65
13
13
49
4930
4927
3827
3830
38
13
27
第七趟输入 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]
#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");
for(i=1;i<11;i++)
printf("%d ",a[i]);
}
例 用简单选择法对 10个数排序排序过程:
( 1)首先通过 n-1次比较,从 n个数中找出最小的,将它与第一个数交换 —第一趟选择排序,结果 最小 的数被安置在第一个元素位置上
( 2)再通过 n-2次比较,从剩余的 n-1个数中找出关键字 次小 的记录,
将它与第二个数交换 —第二趟选择排序
( 3)重复上述过程,共经过 n-1趟排序后,排序结束例 初始,[ 49 38 65 97 76 13 27 ]
k
j
i=1 13 49
一趟,13 [38 65 97 76 49 27 ]i=2 27 38
二趟,13 27 [65 97 76 49 38 ]
三趟,13 27 38 [97 76 49 65 ]
四趟,13 27 38 49 [76 97 65 ]
五趟,13 27 38 49 65 [97 76 ]
六趟,13 27 38 49 65 76 [97 ]
k
kk
k
j j j j j
j j j j j
输入 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真 假
#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");
for(i=1;i<11;i++)
printf("%d ",a[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]);
for(i=0;i<N;i++)
printf(“%d,,a[i]);
printf(“\n”);
for(i=0;i<N;i++)
printf(“%d,,b[i]);
printf(“\n”);
for(i=0;i<N;i++)
c[i]=a[i]+b[N-i-1];
for(i=0;i<N;i++)
printf(“%d,,c[i]);
}
数组定义:必须用 常量 表达式数组元素引用
§ 7.1.2 二维数组及多维数组
1、二维数组的定义
2、二维数组的初始化
3、二维数组元素的初始化
4、应用举例
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]
0
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]
int c[2][3][4]
0
1
2
34
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]
二维数组理解例 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
7a[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[i]由包含 4个元素的一维数组组成二维数组 a是由 3个元素组成
a[0]
a[1]
a[2]
行名
0
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]
2、二维数组元素的初始化
分行初始化:
例 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[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 0 4 0 0
部分初始化例 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 0 0 4 5 0
第一维 长度省略初始化例 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[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 0 0 0
部分初始化例 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 0
第一维 长度省略初始化例 比较 int a[2][3]={{5,6},{7,8}};
与 int a[2][3]={5,6,7,8};
5 6 0
7 8 0
5 6 7
8 0 0
例 int a[][10];
float f[2][]={1.2,2.2};
例 int a[5];
a={2,4,6,8,10};
例 int a[10];
float i=3;
a[i]=10;
例 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
0 2 31 4
h e l l o \0
0 2 31 4 5
3、二维数组元素的引用二维数组的访问也是通过访问其元素来实现的。
二维数组的引用方式为:
数组名 [下标表达式 ][下标表达式 ]
几点注意:
① 二维数组的下标 表达式 的范围和一维数组类似,可以是整型的变量,常量,表达式 。 第一维下标的范围是 0,1、
2…… 第一维长度 -1; 第二维下标范围是 0,1,2…… 第二维长度 -1。
在引用每一个数组元素时下 标 表达式的值不能越界!
② 虽然二维数组是特殊的一维数组,是元素为一维数组的一维数组,但并不能引用数组的行或列,只能引用单个是数组元素 。
③ 二维数组元素的表示方式不能写为如 b[1,2]、
b[2],[0],b(1,2),b(3)(1)的形式,而且两个下标之间也不能有空格 。
4,程序举例例 将二维数组行列元素互换,存到另一个数组中
a= 1 2 34 5 6 b= 1 42 5
3 6
#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]);
printf("\n");
}
}
例 求二维数组中最大元素值及其行列号
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
#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);
}
例 读入下表中值到数组,分别求各行、各列及表中所有数之和
12 4 6
15 7 9
8 23 3
2 5 17
12 4 6 22
15 7 9 31
8 23 3 34
2 5 17 24
37 39 35 111
#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;
for(i=0;i<4;i++)
for(j=0;j<3;j++)
{ 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");
}
}
【 例 7.4】 编程序查找一个矩阵中的鞍点,并输出。
32 30 56 49
15 7 9 31
8 23 3 34
2 5 17 24
37 19 35 111
#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]);
for(i=0;i<M;i++)
{ 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;
if (k>=M)
{ flag=1;
printf("\n%d,%d,%d",
i,m,a[i][m]);
}
}/*for i*/
if(flag==0)printf("\nnone,");
}/*main*/
例 有十个学生的成绩,求平均分
92 85 68 75 54 88 98 45 61 79
92
85
68
54
88
98
45
75
61
79
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
a[6]
a[7]
a[8]
a[9]
a#include <stdio.h>
main()
{ int k,a[10];
for(k=0;k<10;k++)
scanf(“%d”,&a[k]);
for(k=0;k<10;k++)
sum+=a[k];
printf(“Average is %d\n”,sum/10);
}
例 有 M 个学生,每个学生 N 门课成绩,
求每人的平均成绩,并安平均成绩从大到小排序,
按排序结果输出。
62 75 68 75
54 88 98 45
91 79 81 70
1
2
3
数学 化学英语 物理如原始数据为:
91 79 81 70 80.25
54 88 98 45 71.25
62 75 68 75 70.0
3
2
1
数学 化学英语 物理输出数据格式为:
§ 7.1.3 字符数组和字符串
1.字符数组的定义和使用
2.字符串和字符数组
3.常用字符串处理函数
4.字符数组应用举例
1,字符数组的定义和使用字符数组就是数据类型为? char”的数组 。
定义
字符数组的初始化
和前面所讲的数组相同,逐个字符赋值例 char c[10],ch[3][4];
例 char ch[]={?H?,?e?,?l?,?l?,?o?};
ch[0]
H e l l o
逐个字符赋值
ch[1] ch[2] ch[3] ch[4]
例 char ch[5]={?B?,?o?,?y?};
ch[0]
B o y \0 \0
逐个字符赋值
ch[1] ch[2] ch[3] ch[4]
用字符串常量 例 char ch[5]=“Boy”;
ch[0]
B o y \0 \0
字符串常量赋值
ch[1] ch[2] ch[3] ch[4]
例 char ch[]=,ello”;
ch[0]
H e l l o
字符串常量赋值
ch[1] ch[2] ch[3] ch[4]
字符数组的引用,
【 例 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;
scanf("%c",&c);
}
printf("\n");
for(j=k-1;j>=0;j--) /*逆序输出字符序列 */
printf("%c",a[j]);
}
字符串是作为一个整体对待的字符序列。在C语言中,
没有字符串这种数据类型,因此可以将字符串存放在字符数组中。这是处理字符串的方法之一。
例 char ch[5]=“Boy”;
ch[0]
B o y \0 \0
用字符串常量
ch[1] ch[2] ch[3] ch[4]
例 char ch[6]={“Hello”};
char ch[6]=“Hello”;
char ch[]=“Hello”;
用字符串常量
ch[0]
H e l l o
ch[1] ch[2] ch[3] ch[4]
\0
ch[5]
2.字符串和字符数组在用字符数组存放字符串时,字符数组必须预先设定足够的长,在足够长的情况下我们一般并不关心数组的具体长度,而是关心有效字符的长度 。
对于字符串,并不显式的保存它的长度,而是用字符串结束标志来表示字符串到此结束,隐含着字符串的长度,字符串结束标志也就是前面所介绍的空字符 '\0'。
没有‘ \0?,不能作为字符串用例 char ch[5]={?H?,?e?,?l?,?l?,?o?};
ch[0]
H e l l o
逐个字符赋值
ch[1] ch[2] ch[3] ch[4]
请注意区分字符常量和字符串常量:字符常量是用单引号引起来的单个字符,字符串常量是用双引号引起来的字符序列,当然,字符序列可以为空,也可以是一个字符。
不但用字符数组存放字符串采用 ‘ \0?表示字符串的结束,
对于字符串常量,也采用字符串结束标志 ‘ \0?来作为结束符。
编译系统在处理字符串时会自动的在字符串的最后一个字符之后加上 ‘ \0?,也就是说,对于含有 n个字符的字符串在内存中占 n+1个字节的空间,因为需要用一个字节来存放字符串结束标志 '\0'。
① ""表示空串,在内存中保存的是空字符 '\0',占一个字节 。
② "A"表示含有一个大写字母A的字符串,在内存中保存的是字母 A和空字符 '\0',占两个字节 。
③ 'A'表示字母 A,在内存中占一个字节 。
④ "ABCDEF"表示含有6个字母的字符串,在内存中占 7个字节
。
需要注意的是,处理字符串常量的时候,字符串结束标志是编译系统自动添加的,不用人为的在字符串最后加上 ‘ \0?
。
例 比较 int a[2][3]={{5,6},{7,8}};
与 int a[2][3]={5,6,7,8};
5 6 0
7 8 0
5 6 7
8 0 0
例 int a[][10];
float f[2][]={1.2,2.2};
例 int a[5];
a={2,4,6,8,10};
例 int a[10];
float i=3;
a[i]=10;
例 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
0 2 31 4
h e l l o \0
0 2 31 4 5
例 char diamond[][5]={{'.','.','*'},{'.','*','.','*'},
{'*','.','.','.','*'},{'.','*','.','*'},{'.','.','*'}};
二维字符数组初始化
.,* \0 \0
,*,* \0
*,,,*
,*,* \0
.,* \0 \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 p l e \0 \0
O r a n g e \0
G r a p e \0 \0
P e a r \0 \0 \0
P e a c h \0 \0
例 输出一个字符串
#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");
}
I
a
m
a
b
o
y
0
1
2
3
4
5
6
7
8
9
字符串
字符串及其结束标志
无字符串变量,用字符数组处理字符串
字符串结束标志:‘ \0’
例? hello”共 5个字符,在内存占 6个字节 字符串长度 5
h e l l o \0
104 101 108 108 111 0
内存存放字符 ASCII码
字符串的输入输出
逐个字符 I/O,%c
整个字符串 I/O,%s
例 用 %c
main()
{ char str[5];
int i;
for(i=0;i<5;i++)
scanf(“%c”,&str[i]);
for(i=0;i<5;i++)
printf(“%c”,str[i]);
}
例 用 %s
main()
{ char str[5];
scanf(“%s”,str);
printf(“%s”,str);
}
用字符数组名,不要加 &
输入串长度 <数组维数遇空格或回车结束自动加‘ \0?
用字符数组名,
遇‘ \0?结束例 main( )
{ char a[5]={?H?,?e?,?l?,?l?,?o?};
printf(“%s”,a);
}
例 main( )
{ char a[ ]=“Hello”;
printf(“%s”,a);
}
结果,Hello#-=*
h e l l o
0 2 31 4
结果,Hello
用? %s”输出时,遇 ‘ \0?结束
main()
{
char a[]={'h','e','l','\0','l','o','\0'};
printf("%s",a);
}
例输出,hel h e l \0 l o \0
数组中有多个 ‘ \0?时,
遇第一个结束
main()
{
int i;
char a[5];
scanf("%s",a);
for(i=0;i<5;i++)
printf("%d,",a[i]);
}
运行情况:
( 1)若输入 hel,正常
( 2)若输入 hell,正常
( 3)若输入 hello,用 %s 输出时,会出现问题
h e l \0
h e l l \0
h e l l o
输入字符串长度 <数组维数例 字符串输入举例
H o w \0
a r e \0
y o u? \0
#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);
}
运行情况:
输入,How are you?
输出,a=How
b=are
c=you?
输入,How are you?
输出,a=How
scanf中 %s输入时,遇空格或回车结束运行情况:
输入,How are you?
例 若准备将字符串,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;
3.常用字符串处理函数包含在头文件 string.h
字符串输出函数 puts
格式,puts(字符数组 )
功能:向显示器输出字符串(输出完,换行)
说明:字符数组必须以‘ \0?结束
字符串输入函数 gets
格式,gets(字符数组 )
功能:从键盘输入一以 回车结束 的字符串放入字符数组中,
并自动加‘ \0’
说明:输入串长度应小于字符数组维数例 #include <stdio.h>
main( )
{ char string[80];
printf(“Input a string:”);
gets(string);
puts(string);
}
输入,How are you?
输出,How are you?
字符串连接函数 strcat
格式,strcat(字符数组 1,字符数组 2)
功能:把字符数组 2连到字符数组 1后面返值:返回字符数组 1的首地址说明,?字符数组 1必须足够大
连接前,两串均以‘ \0’结束 ;连接后,串 1的‘ \0’取消,
新串最后加‘ \0’
字符串拷贝函数 strcpy
格式,strcpy(字符数组 1,字符串 2)
功能:将字符串 2,拷贝到字符数组 1中去返值:返回字符数组 1的首地址说明,?字符数组 1必须足够大
拷贝时‘ \0’一同拷贝
不能使用赋值语句为一个字符数组赋值例 char str1[20],str2[20];
str1={“Hello!”}; (?)
str2=str1; (?)
例 strcpy与 strcat举例
#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);
}
T
r
b
o
C
+
+
0
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
\0
24
…….
…….
T
r
b
o
\0
0
1
2
3
4
5
6
7
8
9
u
24
…….
…...
字符串比较函数 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”; 答案,1 3 1
#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
【 例 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");
}
#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++;}
printf("\n");
k=0;
while(c[k]!= '\0') /*以大写形式输出字符串 */
{if (c[k]>= 'A'&&c[k]<= 'Z') putchar(c[k]+32);
else putchar(c[k]);
k++;}
}
【 例 7.7】 输入一个由字母组成的字符串,再分别以大写字母和小写字母形式输出该字符串。
应用举例例 输入一行字符,统计其中有多少个单词输入一字符串给 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
#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);
}
当前字符 =空格是否未出现新单词,使 word=0,num不累加前一字符为空格 (word==0),新单词出现,
word=1,num加 1
前一字符为非空格 (word==1),未出现新单词,num不变否
0
是
1
1
是
1
未
0
1
否
0
是
1
2
否
1
未
1
2
是
1
未
0
2
否
0
是
1
3
是
1
未
0
3
否
0
是
1
4
否
1
未
1
4
否
1
未
1
4
否
1
未
1
4
例 输入,I?am?a?boy.
当前字符是否空格
word原值新单词开始否
word新值
num值
I a m a b o y,
例 有三个字符串,找出其中最大者
H o w \0
H e l l o \0
H i g h \0
str[0]
str[1]
str[2]
#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);
}
7.2.1 结构体类型定义 ------形式
7.2.2 结构体变量
1、结构体变量的定义
2、结构体变量的初始化
3,结构体变量的引用
7.2.3 结构体数组
7.2.4 位段
7.2.5 向函数传递结构体型数据
§ 7.2 结构体结构体:是 一种 自定义 de 构造 数据类型。
用途:把 不同类型 的数据组合成一个整体。
struct [结构体名 ]
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
成员类型可以是基本型或构造型struct是 关键字,
不能省略合法标识符可省,无名结构体7.2.1 结构体类型定义,
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
name
num
sex
age
score
addr
2字节
2字节
20字节
1字节
4字节
30字节
…
…..
结构体 类型 定义描述结构的组织形式(图纸),不分配内存结构体类型的定义例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
7.2.2 结构体变量
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;
(2)、定义结构体类型的同时定义结构体变量一般形式:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列 ;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
(3)、直接无名结构体的同时定义结构体变量一般形式,struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列 ;
例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
用 无名结构体 直接定义变量 只能一次
几点说明
结构体类型与结构体变量概念不同
类型,不分配内存 ; 变量,分配内存
类型,不能赋值、存取、运算 ; 变量,可以
结构体成员名 (域名)与程序中变量名地位相同
结构体可嵌套例 struct date
{ int month;
int day;
int year;
};
struct student
{ int num;
char name[20];
struct date birthday;
}stu;
num name birthdaymonth day year
例 struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu;
num name birthdaymonth day year
2、结构体变量的初始化和其他类型的变量相同,
在定义结构体变量时赋初值形式一:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
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”};
形式二,struct 结构体名{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
形式三,struct{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
3 结构体变量的引用
引用规则
结构体变量 不能整体引用,只能引用变量 成员
可以将一个 结构体变量赋值给另一个结构体变量
结构体嵌套时 逐级引用成员 (分量 )运算符优先级,1
结合性,从左向右引用方式,结构体变量名,成员名例 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;
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];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
stu2=stu1; ( )
例 struct student
{ int n m;
char a e[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu1,stu2;
num name birthdaymonth day year
stu1.birthday.month=12;例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
if(stu1==stu2)
…….,(?)
7.2.3 结构体数组
1、结构体数组的定义和初始化定义:三种形式:
形式一,
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];
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
初始化:与其他类型的数组赋初值的方法相同例 struct
{ int num;
char name[20];
char sex;
int age;
}stu[ ]={{……},{……},{……}};
顺序初始化,
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 Ya,,?F?,19}};
全部初始化时维数可省
2、结构体数组引用引用方式,结构体数组名 [下标 ].成员名
stu[1].age++;
struct student
{ int num;
char name[20];
char sex;
int age;
}str[3];
strcpy(stu[0].name,”ZhaoDa”);
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
例,统计后选人选票
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
0
0
0
7.2.5 向函数传递结构体型数据函数之间的参数传递也可以是结构体型数据,既可以通过参数传送结构体变量的成员,也可以通过参数传递整个结构体变量 。
1.向函数传递结构体变量的成员若结构体变量的成员是基本类型,则作函数的实参时的用法与普通变量作函数的实参的用法相同,形参与实参之间仍然是,值传递,的方式 。
2.向函数传递结构体变量
ANSI C允许函数之间传递结构体变量 。 若实参是结构体变量,那么形参也应是同类型的结构体变量 。
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);
printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c);
}
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");
}
arga,27b,3
c,30
(main)
(func)
parm
a,27
b,3
c,30
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
ain)例 用结构体变量作函数参数由上面的例子可见:在发生函数调用时,
形参结构体变量也要占用内存空间,接收实参结构体变量传递来的信息,因此函数之间传递结构体变量会带来时间和空间的巨大开销;而且,形参与实参之间是? 值传递? 的方式,被调函数对形参结构体变量的修改并不能传递给实参,即主调函数无法得到处理后的数据,所以虽然语法上允许,但一般很少采用这种传递方式 。 而是采用传递结构体地址的方法,使得在被调用单位与调用单位函共享结构体变量数据 。
§ 7.3 共用体有时需要将几个不同时出现的变量共享一个内存单元,如:将一个整型变量、实型变量、字符型变量共同放入同一个地址空间(当然这几个变量不能同时用),怎么办? C提供了共用体(联合体)类型支持 。
7.3.1 共用体类型 union 共用体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};例 union data
{ int i;
char ch;
float f;
}; 类型定义 不分配内存fch
i
100地址开始定义形式:
形式二,
union data
{ int i;
char ch;
float f;
}a,b;
形式一,
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
形式三,
union
{ int i;
char ch;
float f;
}a,b,c;
7.3.2 共用体变量的定义
f
ch
i
f
ch
i
a b
共用体 变量定义 分配内存,
长度 =最长成员 所占字节数共用体 变量任何时刻只有 一个成员 存在
1、共用体变量的定义
2 共用体变量引用
引用方式:
例 a.i=1;
a.ch=?a?;
a.f=1.5;
printf(“%d”,a.i); (?编译通过,运行结果不对 )
引用规则
不能引用共用体变量,只能 引用其成员共用体指针名 ->成员名共用体变量名,成员名 (*共用体指针名 ).成员名
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; (?)
不能 在定义共用体变量时 初始化例 union
{ int i;
char ch;
float f;
}a={1,?a?,1.5}; (?)
可以用一个共用体变量为另一个变量赋值 例 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; (?)
例 将一个整数按字节输出
01100001 01000001
低字节高字节
01000001
01100001
ch[0]
ch[1]
运行结果:
i=60501
ch0=101,ch1=141
ch0=A,ch1=a
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]);
}
结构体与共用体
区别,存储方式不同
struct node
{ char ch[2];
int k;
}a;
union node
{ char ch[2];
int k;
}b;
achk
bch k
变量的各成员同时存在任一时刻只有一个成员存在
联系,两者可相互嵌套例,结构体中嵌套共用体
name num sex job class position
Li
Wang
1011
2086
F
M
S
T
501
prof
循环 n次读入姓名、号码、性别、职务
job==?s?真真 假假读入 class 读入
position
输出
“输入错”
循环 n次
job==?s?真 假输出,姓名,号码,
性别,职业,班级输出,姓名,号码,
性别,职业,职务
job==?t?
struct
{ int num;
char name[10];
char sex;
char job;
union
{ int class;
char position[10];
}category;
}person[2];
例共用体中嵌套结构体,机器字数据与字节数据的处理
00010010 00110100
低字节高字节
00110100
00010010
low
high
0x1234
00010010 11111111
低字节高字节
11111111
00010010
low
high
0x12ff
struct w_tag
{ char low;
char high;
};
union u_tag
{ struct w_tag byte_acc;
int word_acc;
}u_acc;
word_acc byte_acc.lowbyte_acc.high
u_acc
§ 7.5 用 typedef 定义 已知 类型
功能,用自定义名字为 已有 数据类型命名
类型定义 简单形式,typedef type name;
例 typedef int INTEGER;类型定义语句关键字 已有数据类型名 用户定义的类型名例 typedef float REAL;
类型定义后,与已有类型一样使用例 INTEGER a,b,c;
REAL f1,f2;
int a,b,c;
float f1,f2; 说明,1.typedef 没有创造 新数据类型
2.typedef 是定义类型,不能定义变量
3.typedef 与 define 不同
define typedef
预编译时处理 编译时处理简单字符置换 为已有类型命名
typedef定义类型步骤
按定义变量方法先写出定义体 如 int i;
将变量名换成新类型名 如 int INTEGER;
最前面加 typedef 如 typedef int INTEGER;
用新类型名定义变量 如 INTEGER i,j;
例 定义数组类型
int a[100];
int ARRAY[100];
typedef int ARRAY[100];
ARRAY a,b,c;
int a[100],b[100],c[100];
例 定义指针类型
char *str;
char *STRING;
typedef char *STRING;
ST ING p,s[10];
char *p;
char *s[10];
例 定义函数指针类型
int (*p)();
int (*POWER)();
typedef int (*POWER)();
POWER p1,p2;
int (*p1)(),(*p2)();
例 定义结构体类型
struct date
{ int month;
int day;
int year;
}d;
例 定义结构体类型
struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
typedef struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
DATE birthday,*p;
struct date
{ int month;
int day;
int year;
}birthday,*p;
类型定义可嵌套例 typedef struct club
{ char name[20];
int size;
int year;
}GROUP;
typedef GROUP *PG;
PG pclub;
GROUP *pclub;
struct club *pclub;
GROUP为结构体类型
PG为指向 GROUP的指针类型