内蒙古机电职业技术学院.docx
- 文档编号:9256580
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:21
- 大小:33.04KB
内蒙古机电职业技术学院.docx
《内蒙古机电职业技术学院.docx》由会员分享,可在线阅读,更多相关《内蒙古机电职业技术学院.docx(21页珍藏版)》请在冰点文库上搜索。
内蒙古机电职业技术学院
内蒙古机电职业技术学院
教案首页
课程:
c语言程序设计授课顺次:
10学时:
2班级:
计信、自动化日期:
第节
课
题
第五章C语言自定义数据描述
目的要求
1、让学生掌握数组及多维数组
重点难点
1、C语言的数组与函数
教学过程
后附
教学手段
教学方法:
讲授、演示
教学媒体:
多媒体教学网
课后分析
以讲述理论知识为主,多举实例。
5C语言自定义数据描述
前面已经介绍了C语言的的基本数据类型:
整型、实型、字符型。
为了使程序员更简洁、更方便地描述复杂对象,C语言还提供了用户自定义数据的描述方法,即构造类型数据:
数组类型、结构体类型、共同体类型。
这些类型都是通过一定规则由基本类型构成的。
各种构造型数据类型的引入,使得C语言具有方便描述现实世界上复杂对象的能力。
5.1数组
数组是指具有相同类型的数据组成的序列,是有序集合。
用统一的数组名来标识数组,序列中的一个数据称为数组的一个元素,数组元素(或称数组分量)由其所在的位置序号(称数组的下标)来区分。
本节将主要讨论数组的定义,数组元素的引用,数组与函数的关系等有关问题。
5.1.1一维数组
1.一维数组的定义
只有一个下标的数组称为一维数组。
定义一个一维数组的一般形式为:
类型标识符数组名[元素个数];
例如:
inta[5];
它表示说明了一个整型数组,该数组名为a,共有5个元素,每个元素都可以作为一整型变量来使用。
关于数组元素引用的几点说明:
(1)类型标识符可以是前面已学的所有类型,如int,char,float,long,unsigned等,还可以是后面将要学习的结构体类型。
(2)数组名的命名规则与变量相同。
(3)数组元素个数亦称数组长度,是一个整型常量表达式,可以是字符常量和符号常量。
下面是合法的数组定义:
intx[10];
charch[20];
floatscore[30];
#definenumber10
longnum[number];
shortw[2*number];
下面的定义是非法的:
inta(5);
intn=10;
charc[n];在定义了数组之后,便可使用它了。
C语言规定只能逐个引用数组元素,而不能一次引用一个数组。
数组元素的描述与引用是由数组变量名加方括号中的下标组成。
即:
数组名[下标]下标是元素在整个数组中的顺序号,是从0开始的。
可以用整型常量或整型表达式,亦可使用字符表达式或后面将讲述的枚举类型表达式。
上面示例中的数组a共有5个元素,分别表示为a[0]、a[1]、a[2]、a[3]、a[4]。
注意,a[5]不是数组a的元素。
例如,有如下定义:
inta[5];
则:
a[0]=3;a[1]=0;a[3]=5;
a['C'-'A']=2;
a[1]=a[0]+a[2*2];
scanf("%d",&a[2]);
都是合法的数组元素引用。
例5.1从键盘上输入5个整数,保存在数组中,并以相反顺序输出。
main()
{inti,a[5];
for(i=0;i<5;i++)
scanf("%d",&a[i]);
printf("\n");
for(i=4;i>=0;i--)
printf("%3d",a[i]);
}
输入:
12345↙
输出:
54321
由于不能对数组进行整体输入(输出),数组元素必须逐个进行输入或输出(本例中使用(for循环语句来实现)。
第四行语句相当于语句:
scanf(“%d%d%d%d%d”,&a[0],&a[1],&a[2],&a[3],&a[4]);
决不能写成:
scanf(“%d”,a);
对一维数组,多使用for循环语句来处理。
处理时注意边界条件的判断,在第一个for循环中若写为:
for(i=0;i<=5;i++)则有问题,因为a[5]不是数组a的元素。
以下几点值得注意:
(1)数组下标取值应在0至元素个数—1的范围内。
如上例中a[0],a[1],a[2],a[3],a[4]是数组a的5个元素,而a[5]则不是,对a[5]的错误引用可能破坏数组a后的其它数据或程序,造成不可预料的损失,必须特别小心。
(2)数组元素可以象普通变量一样使用。
(3)对数组的输入、输出或赋值只能逐个对元素进行,不能整体输入或输出一个数组。
2.一维数组的存储结构与初始化每个变量都总是与一个特定的存储单元相联系(该单元的字节数与变量类型有关,如整型占2字节单元),而数组是多个相邻单元的汇集,整个数组占用一个连续的存储空间,数组是“有序”的即体现如此。
数组的使用简化了一组数据项的命名和引用每一项的方法。
C编译程序为所定义的数组变量在内存中分配一片连续的存储单元,元素按数组下标从小到大连续排列。
例如,数组a的存储示意图如图5.1(a)所示:
图5.1一维数组存储结构
可以用赋值语句或输入语句使数组中的元素得到值并保存在对应的各存储单元中,但要在运行时完成,占用运行时间。
C语言允许在定义静态或外部数组时,对数组各元素指定初值,即初始化。
初始化是在编译阶段完成的。
对数组的初始化有以下几种情况:
(1)在定义数组时对数组元素赋初值。
例如
staticinta[5]={3,6,0,7,30};
用花括弧把赋给各元素的初值括起来,各值以逗号分隔。
在内存中的存储形式如图5.1(b)所示。
初始化后各元素的值为:
a[0]=3,a[1]=6,a[2]=0,a[3]=7,a[4]=30。
(2)给部分元素赋初值
staticinta[5]={3,6};
表明只给前2个元素赋初值,即a[0]=3,a[1]=6,其它元素自动赋0值。
(3)对全部元素赋初值时,可以不指定数组长度,系统自动根据初值个数来决定数组长度。
例如
staticinta[]={0,2,4,6,8,10};
系统将a定义为一个6元素数组,等价于
staticinta[6]={0,2,4,6,8,10};
值得注意的是:
(1)若一个静态(static)或外部数组不进行初始化,则对数值型数组隐含初值为0,对字符数组,隐含初值为空字符'\0'(即Ascll码为0的字符)。
(2)如果不对自动(auto)数组初始化,则其初始值为一些不可预料的数。
自动数组的初始化只能由赋值语句或输入语句实现。
例5.2初始化数组示例。
main()
{inti,a[5]={3,6,0,7,30};
intb[5];
printf("\nArraya:
");
for(i=0;i<5;i++)
printf("%6d",a[i]);
printf("\nArrayb:
");
for(i=0;i<5;i++)
printf("%6d",b[i]);
}
输出结果:
Arraya:
360730
Arrayb:
-321398321170216
数组a初始化后,就有了确定的值。
数组b未进行初始化,虽然元素也有值(如b的输出),但其值是不确定的(程序在不同的时间或机器上运行可能得到不同结果)。
例5.3从键盘上输入5个数,输出最大、最小的元素。
#defineN5
main()
{inti,max,min;
inta[5];
for(i=0;i<5;i++)scanf("%d",&a[i]);
max=min=a[0];
for(i=0;i<5;i++){if(max
elseif(min>a[i])min=a[i];
}
printf("max=%d,min=%d",max,min);
}
若输入为:
10245678-70
则输出就为:
max=5678,min=-7
例中先假定第一个元素既是最大的,也是最小的,并用它对保存最大、最小值的变量max、min进行初始化,在for循环语句中再与所有元素比较,比max大的元素值赋给max,比min小的赋给min。
例5.4从键盘上输入10个数,用选择法将其按由小到大的顺序排列。
选择法的基本思想是:
先把第一个元素作为最小者,与后面元素比较,如第一个元素大,则与后面小元素交换(保证第一个元素总是最小),直到与最后一个元素比较完,第一趟就找出了最小元素,且保存在第一个元素位置。
再以第二个元素作为最小者(次小)与后面元素比较,后面元素小,则交换,直到最后一个元素,第二大的元素已找到。
以此类推,经9趟后排定。
程序如下:
main()
{inti,j,t;
inta[10];
for(i=0;i<10;i++)scanf("%d",&a[i]);
for(i=0;i<9;i++)/*10个元素选择9趟*/
for(j=i+1;j<10;j++)/*每趟进行10-i-1次比较*/
if(a[i]>a[j])
{t=a[i];/*利用中间变量t来实现a[i]与a[j]的交换*/
a[i]=a[j];
a[j]=t;
}
printf("\n");
for(i=0;i<10;i++)printf("%6d",a[i]);
}
输入:
034–145671244–324500
输出:
-3245–10004412344567
此例中,使用两重循环来实现排序。
外层循环控制排序趟数,若数组有n个元素,则共进行n-1趟。
内层循环完成在剩余的数中选择最小的数,比较次数随趟数递减,循环控制变量j的初值与外循环执行次数有关:
j=i+1。
当后面元素较大时,马上交换。
注意,不能直接a[i]=a[j],a[j]=a[i],这使得a[i]原来的值被破坏,无法实现a[i]与a[j]的交换。
而应先将a[i]暂时存放在一个中间变量t中,即t=a[i],在执行a[i]=a[j]后,再执行a[j]=t实现元素交换。
值得注意的是以上程序执行时元素的交换并不都是必须的。
事实上,只要记住比较时小元素的位置,即序号,在内循环结束后做一次交换即可,从而提高程序执行的效率。
上例经改写后程序如下
main()
{inti,j,t,k;
inta[10];
for(i=0;i<10;i++)scanf("%d",&a[i]);
for(i=0;i<9;i++)
{k=i;/*本趟排序中的第一个元素序号保存在k中*/
for(j=i+1;j<10;j++)
if(a[k]>a[j])k=j;/*记住新的小元素的序号*/
if(k!
=i)/*若k已变化,则找到了新的小数,交换*/
{t=a[i];
a[i]=a[k];
a[k]=t;
}
}
printf("\n");
for(i=0;i<10;i++)printf("%6d",a[i]);
}
经过改进后的程序每选一个元素只交换一次,提高了程序执行效率。
5.1.2多维数组
1.多维数组的定义与存储结构
在许多实际应用中,常常需要定义多维数组。
若一个一维数组,它的每一个元素亦是类型相同的一维数组时,便形成二维数组。
所谓数组的类型相同是指数组大小、元素类型相同。
例如:
有4个学生,每个学生考了三门课程,其成绩可以用一个二维数组score来描述。
score[0],score[1],score[2],score[3]分别代表4名学生的成绩,如图5.2所示
图5.2二维数组示意图
用第一维下标从0到3的变化区分4名不同学生,第二维从0到2的变化区分某学生的三门不同成绩。
二维数组的定义形式与一维数组类似:
类型标识符数组名[常量表达式1][常量表达式2];
二维数组从形式上看类似于矩阵。
表达式1表示最大行数,表达式2表示最大列数。
例如
inta[2][3];intscore[4][3];
以上定义了一个2×3(或称2行3列)的数组a及4×3的数组score。
C语言中,二维数组元素表示形式是数组名[下标1][下标2]下标1称第一维下标(或称行),下标2称第二维下标(或称列)。
下标从0开始变化,其值分别小于常量表达式1与常量表达式2。
若有定义
inta[2][3];
则:
a[0][0],a[0][1],a[0][2]
a[1][0],a[1][1],a[1][2]
是数组a的6个元素。
对二维数组元素的引用与一维数组类似:
scanf("%d",&a[0][0]);a[1][2]=a[0][0]+a[0][2];在前述定义下都是合法的引用,但引用a[1][3]是错误的。
了解了一维数组、二维数组的定义,我们可以类推出多维数组的定义。
intb[2][2][3];/*定义了一个3维数组*/
charC[2][3][2][2];/*定义了一个4维数组*/
多维数组元素的顺序仍由下标决定。
下标的变化是先变最右边的,再依次变化左边的下标。
在内存中,就是按这种顺序连续存储多维数组的各个元素。
对多维数组重点掌握二维数组与三维数组。
数组是同类数据的有序排列,利用数组名与下标可以实现对任意元素的随机访问,可以计算出某元素在数组中的序号及在内存中的地址。
以二维数组为例(多维数组类推):
设有一个m×n的二维数组a,其中第i行第j列元素a[i][j]在数组中所处位置为i×n+j+1。
从直观上理解,元素a[i][j]是第i行第j列。
由于下标从0开始计数,而每行有n列,故i×n是i行前各行元素数,再加上第j列,i×n+j+1是该元素的序号。
而在内存中的地址则为:
a+(i×n+j)×元素类型字节数,a是数组的起始地址。
可见,下标从0开始简化了地址的计算。
例5.3从键盘上输入9个整数,保存在二维数组中,按数组原来的位置输出第1行、第1列。
main()
{inti,j;
inta[3][3];
for(i=0;i<3;i++)
for(j=0;j<3;j++)
scanf("%d",&a[i][j]);
for(i=0;i<3;i++)
{for(j=0;j<3;j++)
if(i==1||j==1)printf("%6d",a[i][j]);
elseprintf("");
printf("\n");
}
}
输入:
123
456
789
输出为:
2
456
8
2.二维数组与多维数组的初始化
先看二维数组的初始化
(1)分行给二维数组赋初值,每个花括号内的数据对应一行元素。
如
staticinta[2][3]={{1,2,3},{4,5,6}};
元素a[0][0]=1,a[1][2]=6
(2)将所有初值写在一个花括号内,顺序给各元素赋值。
如
staticinta[2][3]={1,2,3,4,5,6};
显然第一种方式比第二种方式更直观,行列清楚,不易出错。
(3)只对部分元素赋值,没有初值对应的元素将赋0或空字符(对字符数组),
如:
staticinta[2][3]={{1,2},{4}};
各数组元素值为
(4)给全部元素赋初值或者分行初始化时,可以不指定第一维大小,系统自动根据初值数目与例数自动确定第一维大小,但第二维大小必须指定。
如
staticinta[][3]={1,2,3,4,5,6};
这定义了一个2×3数组a
staticinta[][3]={{},{0,5}};
定义的数组a的初值为:
对三维数组的初始化与二维数组很类似。
例如:
staticintb[2][2][3]={1,2,3,4,5,6,7,8,9,10,11,12};或staticintb[2][2][3]={{{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}}};以上方式第一维下标(最左边)亦可省写。
例5.6用如下的3×3矩阵初始化数组a[3][3],求其转置矩阵并输出之。
矩阵a:
转置矩阵是将原矩阵的元素按行列互换所形成的矩阵,使用二维数组来处理矩阵问题是很方便的,而二维数组常常用二重循环来实现,内循环处理列,外循环处理行。
程序如下:
main()
{inti,k;
inta[3][3]={{1,2,3},{4,5,6},{7,8,9}};
intb[3][3];
for(i=0;i<3;i++)
for(k=0;k<3;k++)b[i][k]=a[k][i];
for(i=0;i<3;i++)
{for(k=0;k<3;k++)printf("%5d",b[i][k]);
printf("\n\n");
}
}
输出:
147
258
369
5.1.3字符数组和字符串
字符数组是其元素类型为字符类型的数组,其定义与前面介绍的数组定义类似。
例如:
charch[15];1.字符串的概念及存储
字符串是指若干有效字符的序列。
C语言中的字符串可以包括转义字符及Ascll码表中的字符(控制字符以转义字符出现),其形式是用双引号括起来的字符序列。
在C语言中,没有字符串类型,字符串是存放在字符数组中。
若要将字符串Iamastudent保存在ch中,则可通过赋值语句将各字符分别赋给字符数组的各元素。
ch[0]='I';ch[1]='';ch[2]='a';ch[3]='m',ch[4]=''……
其存储状态为:
图5.5字符数组存储示意图
显然,操作低效且麻烦。
在实际应用中,常常需要将一个字符串作为一个整体来处理,而不必去考虑保存字符串的数组实际长度。
C语言规定以字符'\0'作为字符串结束标志。
2.字符数组的初始化与前面介绍的有关数组一样,在定义字符数组的同时进行初始化。
如charch[7]={’s’,’t’,’u’,’d’,’e’,’n’,’t’};
如图5.6(a)
在对全部元素指定初值时,可省写数组长度。
charch[]={’s’,’t’,’u’,’d’,’e’,’n’,’t’,’’};
注意在最后补了一个'',若不补,则ch长度为7。
如图5.6(b)。
br>
图5.6字符数组初始化示意图
另外,可以用字符串来直接初始化字符数组 。
charch[]={"student"}系统将双撇号括起来的字符依次赋给字符数组的各个元素,并自动在末尾补上字符串结束标志字符'\0',并一起存到字符数组中,ch的长度为8(而实际字符只有7个),其存储示意图如图5.6(c)所示。
注意:
(1)字符串结束标志'\0'仅用于判断字符串是否结束,输出字符串时不会输出。
(2)在对有确定长度的字符数组用字符串初始化时,其长度应大于字符串长度。
如:
charch[7]={"student"};
结束标志符'\0'未能存入ch中,而是存在ch数组之后的一个单元里,这可能会破坏其它数据,应特别注意。
可以改为:
charch[8]={"student"};(3)在初始化一个一维字符数组时,可以省略花括号。
如charch[8]="student";3.字符串的输入与输出(1)字符串的输入方法
(a)使用scanf函数输入字符串charch[15];charch1[6];scanf("%s",ch);"%s"是字符串格式符,在用scanf()函数输入字符串时,输入项直接用数组名ch,而不要加取地址符&。
因为ch就代表了该字符串的首地址。
在具体输入时,直接在键盘敲入字符串,最后以回车或空格作为结束输入标志。
这也限制了在字符串中不能包含有空格字符。
若按如下方法输入:
student↙
则ch中的结果如图5.6(c)所示,亦自动在最后补上'\0'。
(b)使用函数gets()输入字符串,直到遇到回车为止。
例如:
charch[15];
gets(ch);
若输入的字符串为:
Iamastudent.↙
则ch的内容为:
Iamastudent.\0
(2)字符串的输出方法
(a)用printf函数输出字符串
例如:
printf("%s,%c,%c",ch,ch[3],ch[13]);输出结果为:
Iamastudent.,m,t注意:
用printf函数输出字符串时,要用格式符"%s",输出时从数组的第一个字符开始逐个字符输出,直到遇到第一个'\0'为止(其后即使还有字符亦不输出)。
(b)用puts函数输出一个字符串。
例如:
puts(ch);将字符数组中包含的字符串输出,同时将'\0'转换成换行符。
因此,用puts输出一行,不必另加换行符'\n'。
4.字符串处理函数
由于字符串应用广泛,为方便用户对字符串的处理,C语言库函数中提供了一些常用的库函数。
(1)字符串拷贝函数strcpy调用格式:
strcpy(str1,str2);功能:
将字符串str2复制到字符数组str1中。
说明:
str1的长度应不小于str2的长度;str1必须写成数组名形式,而str2可以是字符串常量,亦可以是字符数组名形式,例如
staticcharc1[10],c2[8]={"student"};
strcpy(C1,C2);
注意:
不能直接使用赋值语句来实现拷贝(或赋值)
c1=c2;
c1="student";
以上两个赋值语句是非法的,因为数组是不能整体赋值的。
另外,拷贝时,字符串str2中的'\0'也一起拷贝。
str1的其它字符保持不变。
(2)字符串连接函数strcat
调用格式:
strcat(str1,str2);
功能:
将str2连同'\0'连接到str1的最后一个字符(非'\0'字符)后面。
连接后的新字符串在str1中。
例如
staticcharc1[14]={"Iama"};
staticcharc2[8]={"student"};
strcat(c1,c2);
图5.7表示连接前后c1与c2的内容。
连接前:
连接后:
图5.7连接前后c1与c2的内容变化图(3)字符串比较函数strcmp
调用格式:
strcmp(str1,str2);
功能:
若str1=str2,则函数返回值为0;
若str1>str2,则函数返回值为—正整数;
若str1 字符串的比较规则是: 两个字符串自左向右逐个字符比较,直到出现不同字符或遇到'\0'为止。 如全部字符相同,则两个字符串相等;若出现不同字符,则遇到的第一个不同字符的Ascll码大者为大。 比较结果由函数值带回。 比较两个字符串相等一般用下面的语句形式if(strcmp(str1,str2)==0){……}; 而不能直接判断: if(str1==str2){……}; (4)字符串长度函数strlen 调用格式: strlen(字符串); 功能: 求字符串的实际长度(不包括'\0'),由函数值返回。 例如: staticcharc[10]="student"; intlen; len=strlen(c); len的值为7,而strlen("good")函数值为4。 限于篇幅,其余字符串函数在这里不一一介绍,可参见附录三中的库函数。 例5.7初始化字符数组,将其中的制表符与换行符转换成为可见的转义字符后复制到另一字符串中。 main() {inti,j; chara[15]=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 内蒙古 机电 职业技术学院