C程期末复习.docx
《C程期末复习.docx》由会员分享,可在线阅读,更多相关《C程期末复习.docx(19页珍藏版)》请在冰豆网上搜索。
C程期末复习
期末复习
第一部分:
C中的数据
首先,从主调函数和被调函数(模块间)要处理的任务数据的角度来总结数据的知识点:
C语言中所讲授的数据有基本类型(整型、实型和字符型)和构建类型(数组、结构体、共用体、链表结点)之分。
构建类型是由基本类型构建而成,因此我们有必要对基本类型的数据做以更细致的研究。
一.基本类型的数据
程序中的数据无非是以常量和变量两种形式描述。
在这里我们不妨思考两个问题:
(1)为什么要用变量?
(2)常量经常用在什么地方?
(一)常量
对于基本类型常量我们要掌握:
常量分几类?
每类的书写规则是什么?
(1)整型常量:
有十、八、十六进制三种表示形式。
(3.3.1、3.3.3)
(2)实型常量:
有小数和指数两种表示形式.(3.4.1、3.4.3)
(3)字符型常量:
有普通字符(可以是ASCII码表中的任何一个字符)、转义字符(表示控制命令的转义字符和用八进制十六进制描述的转义字符)(3.5.1)
(4)字符串常量(3.5.4)
(5)符号常量:
实际上是不带参数的宏定义(3.2.1、9.1.1)
对于常量部分的考察无非是辨别书写形式,字符类的常量特别注意转义字符的辨认。
这就要求我们熟记书写规则。
例如以下题目:
t-1:
下面哪个是正确的整型常量表示
A)019B)0X34gC)-123D)o56E)12,000
t-2:
下面哪个是错误的实型常量表示
A).23B)3.8E-4.5C)45E12D)92.45
t-3:
下面哪个是正确的字符常量表示:
A)”b”B)’\\’C)’\34’D)’\0x9’E)’0123’
t-4:
下面那个是正确的字符串常量表示:
A)’abc’B)“”C)“”D)“\0x120”E)”abRT\0\\”
F)”A”
t-5:
字符串“ab034\0\\t\v\012”中有多少个字符?
t-6:
puts(“ab034\0\\t\v\012”);的结果是什么?
strlen(“ab034\0\\t\v\012”)的值是多少?
(二)变量
对于基本类型的变量,我们知道要使用变量必须先定义变量,定义的基本格式是:
数据类型变量名;要正确定义变量就必须清楚两点
(1)什么样的变量名才是合法的?
(3.2.2)
(2)如何用类型符来描述所要定义的变量,这就涉及到变量所分配的字节数、存储特点、有无符号及各自表示的数值范围等。
变量的三大类:
整型变量(3.3.2)
分配字节:
2字节(int/short)4字节(long)(TC2.0)
存储特点:
存储的是数值的补码形式
符号标识:
signedunsigned
表示数值范围:
表3-1
实型变量(3.4.2)
分配字节:
4字节(float)8字节(double)16字节(longdouble)
存储特点:
图3-7
表示数值范围:
表3-2
字符型变量(3.5.2、3.5.3)
分配字节:
1字节(char)
存储特点:
存储字符的ASCII值
符号标识:
signedunsigned
表示数值范围:
signedchar:
-128~+127
Unsignedchar:
0~255
基本类型变量这部分知识主要的考察形式:
(1)变量名(标识符)的正确与否鉴别
(2)变量类型标识符的识别与应用
(3)变量定义语句中对变量进行初始化的形式正确与否鉴别(3.6)
例如以下题目:
t-7:
以下正确的变量标识符是:
A)3sumB)INTC)_3maxD)caseE)p&sumF)s_m_a
t-8:
以下正确的变量类型声明是:
A)signedintB)intlongC)unsignedlongD)shortlong
t-9:
下面程序段在tc2.0和cfree3.0运行时的输出各是什么?
unsignedinta=65535;
printf("%d",a);
t-10:
以下正确的定义语句是:
A)inta=b=5;B)charch=97;C)unsignedintx,y=-5;D)inta=3,b=5;E)intc=3
(二)建构类型的数据
程序给出的任务数据可以是基本类型的,也可以是集合性质的。
集合中的所有数据可以是同类型的即数组(7.1.1~7.1.3、7.2.1~7.2.3、7.3.1~7.3.4),也可以是不同类型的(例如学生记录)即结构体(11.1~11.5)。
在这部分知识中主要考察的形式有:
数组及结构体的定义、初始化和引用
计算集合(数组、结构体变量)存储所需要的空间
数组定义时缺省形式的一些规则:
在定义一维数组时,若给出了所有初始值则一维中括号内的数值可以省略,由初始值的个数来确定其值。
但若没有给出初始值,则不能省略中括号内的值。
例如:
inta[]={1,2,3};intb[]={3};都对。
inta[];不对。
二维数组的第2维列数任何情况下都不能缺省,第1维中的数值若在给出初始值的按情况下可以缺省。
例如inta[2][]={{1,2}{3,4}}不对。
inta[][2]={1,2,3,4,5};正确。
只有在数组定义时可以给数组整体赋值,不能单独用赋值运算“=”给数组整体赋值,特别是字符串数组。
例如inta[3];a={1,2,3};charb[10];b=”china”;charc[2][10];c[0]=”chian”;c[1]=”japan”都不对,只能是inta[3]={1,2,3};charb[10]=”china”;charc[2][10]={“china”,”japan”};
(5)函数体内定义的数组名是地址常量,而由数组名表示的一些表达式也是常量表达式。
如inta[3]={1,2,3};a,a+i都是常量。
intb[3][3]={..};b,b[0],b+i,*(b+i)也都是常量形式。
常量形式意味着该式只能出现在等号的右边,而不能作为左值。
例如以下题目:
t-11:
以下正确的数组定义形式是:
A)intn;scanf(“%d”,&n) ;inta[n] ;
B)#defineN10inta[N];
C)intb[3][4];
D)charb[][4];
t-12:
以下不正确的数组定义和初始化形式是:
A)inta[]={1,2,3};B)inta[]={0};C)inta[][3]={1,2,3,4};
D)inta[2][2]={{1,1},{2,2},{3,3}}E)chara[10]={“hello”};F)chara[]=”hello”;
G)inta[2][]={{1,1},{2,2}};H)chara[10];a=”hello”;
I)chara[2][10];a[0]=”hello”;a[1]=”tom”;G)chara[2][10]={“hello”,“tom”};
t-13:
在TC2.0中存储以下结构体类型的变量需要多少字节?
structA{
intx,y;
chars[10];
floata;
};
t-14:
以下结构体类型声明是否正确:
A)structA{B)structA{C)structA{
intx=2;structAa;inta;
floatb;intb;structA*p;
};};};
t-15:
若有数组inta[2][2]={1,2,3,4},则能引用数组元素4的形式为:
A)a[1][2]B)*(a+1)C)*(*(a+1)+1)D)*(a+3)E)a[1][1]F)*(a[1]+1)
t-16:
若有数组inta[3]={1,2,3};则能引用数组元素2的形式为:
A)a[1]B)*(a+1)C)&a[1]D)a+1
t-17:
若有如下程序段,则对于“TOM”串中首字符T的正确引用形式为:
structA{
intage;
charname[10];
};
StructAt[2]={1,”TOM”,2,”MIKE”},*p=t;
A)(*p).nameB)t[2].nameC)t[1].name[0]D)p->name[0]
第二部分:
数据的输入输出
讨论完C中的数据我们再讨论各种数据的输入与输出。
如果数据输入不当再完美的程序也不可能显示出预期的结果。
这部分作业的输入出现的问题较多,我们要熟记输入规则但不能死记硬背。
下面的这三对函数都包含在文件“stdio.h“中,因他们的输入输出终端是标准设备-键盘和显示器,因此称为标准的IO函数,标准IO函数的使用与缓冲区有密切的联系。
学习本部分时最重要的是要理解输入缓冲区中数据流和输入函数格式匹配的输入机制(参见本章手册中的参考资料)
C中的输入输出是调用系统库函数来实现的,常见有三对库函数:
scanf()/printf():
可输入输出任何类型的数据。
一次函数调用可以实现多个数据的IO。
gets()/puts():
只对字符串数据进行输入输出操作。
一次函数调用只可实现一个串的IO。
getchar()/putchar():
只对字符数据进行输入和输出操作。
一次函数调用只可实现一个字符的IO。
对于这几对函数的使用主要考察:
scanf、printf的使用规则(4.5,可参考本章教学目标)
getchar和putchar的使用格式(4.4)
gets与scanf的使用区别
例如以下题目:
t-18:
若有程序段inta;floatx;charc[10];scanf(“%2d%f%s”,&a,&x,c);
当程序执行时从键盘输入23456.78abcd,问变量a、x、和c中的值各是什么?
t-19:
若有定义inta ;floatb ;则scanf(“a=%d;b=%f”,&a,&b) ;的输入形式是什么?
t-20:
若有定义floatx ;则语句scanf(“%5.2f”,&x)是否正确?
t-21:
若有定义chara,b ;对于scanf(“%c%c”,&a,&b );若输入AB,则a、b的值各是什么?
t-22:
若用getchar()函数输入一个字符存储到字符变量ch中再将其输出,则以下正确的写法是:
A)getchar(ch) ;B)ch=getchar() ;C)ch=putchar();D)putchar(ch);
t-23:
若有语句scanf(“%s”,a);程序运行时若输入hellotom!
,则存储到a中的串是什么?
t-24:
若有inta=97;floatx=34.56;charc=’B’ ;则语句printf(“%c%d%d”,a,x,c )的输出是什么?
t-25:
若有程序段:
chara,b,s[10],t[10];
a=getchar();b=getchar();
gets(s);gets(t);
printf("a=%c,b=%c,s=%s,t=%s",a,b,s,t);
程序运行时若输入A
B
Hello
TOM
程序输出是什么?
t-26:
若有定义
inta;longintb;unsignedlongc;
floatx;longdoubley;charch;
写出每个变量对应的格式符。
t-27:
若要分别输入两个串“hello”和“tom”至数组s和t中,下面四个程序段运行结果是否一样?
可以有什么样的推论?
若运行后输入的两个串以回车为结束符。
程序段1:
程序段2:
程序段3:
chars[10],t[10];chars[10],t[10];chars[10],t[10];
gets(s);gets(t);scanf(“%s”,s);gets(t);gets(s);scanf(“%s”,t);
程序段4:
chars[10],t[10];
scanf(“%s”,s);scanf(“%s”,t);
t-28:
第4章实验一的强化练习。
第三部分:
函数之间对任务数据的处理方法
在编写多模块程序也即存在函数调用这样的程序时,我们必须首先设计模块之间任务数据的交接方法,即主调函数如何让被调函数得到要访问的任务数据。
部分初学者对此不解,不明白为什么在子函数中不能通过直接引用主调函数中的变量名来访问主调函数中的任务数据,例如这样的题目:
在main函数中定义了变量x和变量y并赋予值,而子函数sum的任务就是对主函数中的这两个数据求和,部分初学者也许认为在sum函数中直接用表达式x+y就可以求出主调函数中这两个变量的和了。
要明白这个错误的原因我们还是要对程序的模块化设计思想做以分析。
这个思想的设计起因很简单,正如我们可以理解为什么学校里要划分院系,而院系里再分班;也正如为什么公司里都划分各个职能部门一样。
变量的作用域属性和存储属性也就是这个设计思想规则的体现。
模块之间只能通过接口(实参/形参返回值)来互通信息。
为了保证模块内部信息(数据)的隐藏性,规定模块内部定义的变量也只能在本块内被引用,这就是作用域规则下的局部变量。
在某些时候可能几个模块需要共享一些数据,这些数据可以被多个模块访问,这就是作用域规则下的全局变量。
例如在战争游戏中,指挥部和后勤部都会需要战士的人数,指挥部用这个数目来调兵遣将,后勤部用这个数目来供给口粮和装备。
不同的模块之间存在信息共享(全局变量),而同一个模块的多次调用之间也可以共享某些信息(静态局部变量)。
对于作用域和存储类型这两部分内容要掌握:
完整的变量定义格式:
存储类型符数据类型符变量名;
能根据变量的定义位置来判断哪些是局部变量,哪些是全局变量,他们各自的作用域范围是什么。
能根据变量定义中的存储类型符来判断变量的存储类型,从而确定变量在内存生存期的起点和终点。
所有的全局变量都是静态存储的,也即存储类型符只能是static/extern两种之一,这两个的区别是前者限定这个全局变量只能被当前文件所使用,而后者声明的变量可以被其他文件所使用。
若全局变量缺省存储类型符则默认为extern。
静态变量在使用前都应有初始值,若未显示赋值则系统有默认值-0或者NULL。
局部变量有静态类型也有动态类型,若存储类型符缺省则应默认为auto。
常见题型:
t-28:
读程序写结果:
#include
intfun(int);
intn=1;
voidmain()
{intx=2,y=3;
printf("1:
x=%d,y=%d,n=%d\n",x,y,n);
{intx=7;
printf("2:
x=%d,y=%d,n=%d\n",x,y,n);
}
y=fun(x);
printf("3:
x=%d,y=%d,n=%d\n",x,y,n);
y=fun(x);
printf("4:
x=%d,y=%d,n=%d\n",x,y,n);
}
intfun(intx)
{staticm=3;
m++;
n+=x;
printf("5:
x=%d,m=%d,n=%d\n",x,m,n);
returnm+n;
}
因变量作用域的限制使得接口传递信息时采取一种机制:
将主调函数的实参值进行复制,形参到的是实参的副本,即传值调用的机制。
但这种机制在处理集合数据时带来问题,我们不可能将集合中的每一个数据都做为一个实参,为了解决这个问题考虑将集合数据在内存中存储的首地址(是一个地址值)拷贝给子函数,这样子函数就需要定义指针变量来接收传递来的地址值,这种处理机制称传址调用,子函数能利用指针变量间接访问到主调函数中的数据。
对于返回结果是集合性质的数据也采用相同的处理方法,即返回这个结果集合的首地址,也即返回值是指针的函数功能。
若主调函数要子函数处理的是多个同类型的数据集合,例如多个一维整型数组,或者多个串,那么为了传递简便通常在主调函数中先对这多个数据集合做些处理,例如将这几个集合的首地址存储在一个指针数组中,这样传递实参时只要将这个指针数组的首地址传递给子函数,而子函数将定义一个二级指针来存放指针数组的首地址,继而通过这个二级指针来间接访问到这多个数据集合。
例如chara[10]=”..”,b[10]=”..”,c[10]=”..”;char*p[3]={a,b,c};有函数调用fun(p,3),则形参定义相应为:
(char**pp,intn).
例如如下题型:
请分析下面函数调用表达式中的实参来写出对应的子函数中形参变量的定义,并说出这种调用形式下数据的访问方法(传值调用还是传址调用):
t-29:
根据实参写出对应的形参变量的定义
(1)主调函数中若有定义:
intx=2,y=3;
函数调用:
fun(x,y);
形参定义:
(2)主调函数中若有定义:
intx=2,y=3;
函数调用:
fun(&x,&y);
形参定义:
(3)主调函数中若有定义:
charx=’A’,y=’B’;
函数调用:
fun(x,y);
形参定义:
(4)主调函数中若有定义:
inta[5]={1,2,3,4,5};
函数调用:
fun(a[0]);
形参定义:
(5)主调函数中若有定义:
inta[5]={1,2,3,4,5};
函数调用:
fun(&a[0]);或者fun(a);
形参定义:
利用形参变量对数组元素的间接访问形式
(6)主调函数中若有定义:
inta[3][3]={1,2,3,4,5,6};
函数调用:
fun(a[2][2]);
形参定义:
(7)主调函数中若有定义:
inta[3][3]={1,2,3,4,5,6};
函数调用:
fun(&a[2][2]);
形参定义:
利用形参变量对数组元素的间接访问形式
(8)主调函数中若有定义:
inta[3][3]={1,2,3,4,5,6};
函数调用:
fun(a,3,3);
形参定义:
(9)主调函数中若有定义:
inta[3][3]={1,2,3,4,5,6};
函数调用:
fun(*a,9);或者fun(&a[0][0],9);或者fun(a[0],9)
形参定义:
利用形参变量对数组元素的间接访问形式
(10)主调函数中若有定义:
chara[3][10]={“hello”,”jack”,”tom”};
函数调用:
fun(a,3);
形参定义:
利用形参变量对数组元素的间接访问形式
(11)主调函数中若有定义:
inta[5]={1,1,1,1,1};
intb[5]={2,2,2,2,2};
intc[5]={3,3,3,3,3};
int*p[3]={a,b,c};
函数调用:
fun(p,3);
形参定义:
利用形参变量对数组元素的间接访问形式
(12)主调函数中若有定义:
chara[5]=”hello”;
charb[5]=”jack”;
char*p[2]={a,b,c};
函数调用:
fun(p,2);
形参定义:
利用形参变量输出串jack
(13)主调函数中若有定义:
chara[3][10]={”hello”,”jack”,”tom”};
char*p[3]={a[0],a[1],a[2]};
函数调用:
fun(p,3);
形参定义:
利用形参变量输出串jack
(14)主调函数中若有定义:
StructA{
Intx;
Charn[10];
};
StructAm={1,”mike”};
函数调用:
fun(m);
形参定义:
StructAa[3]={1,”mike”,2,”jack”,3,”tom”};
函数调用:
fun(a,3);利用形参变量输出串mike
形参定义:
函数调用:
fun(a[0])
形参定义:
在多模块的程序中应能写出或者找出函数的三要素-函数调用、函数声明(原型)、函数定义,函数声明根据情况可以缺省。
或者给出其中一个要素能写出其它的两个要素,例如以下题目:
t-30:
函数原型:
doublefun(int,float);
函数调用:
函数定义头部:
t-31 :
函数原型:
char*fun(char*,char) ;
函数调用:
函数定义头部:
t-32 :
函数原型:
intfun(int[],int) ;或者intfun(int*,int) ;
函数调用:
函数定义头部:
t-33 :
函数原型:
intfun(int(*)[3],int,int) ;
函数调用:
函数定义头部:
t-34 :
函数原型:
intfun(int**,int,int) ;
函数调用:
函数定义头部:
t-35 :
函数原型:
函数调用:
p=fun(a,b) ;/*若以有定义char*p ,a[10] ,b[10] ;*/
函数定义头部:
t-36 :
函数原型:
函数调用:
sum=fun(a,5) ;/*若以有定义intsum,a[5]={..} ;*/
函数定义头部:
t-37 :
函数原型:
函数调用:
sum=fun(a,5,5) ;/*若以有定义intsum,a[5][5]={..} ;*/
函数定义头部:
t-38 :
函数原型:
函数调用:
fun(p,3) ;/*若以有定义char(*p)[3]={“..”,“..”,“..”}*/
函数定义头部:
t-39 :
函数原型:
函数调用:
sum=fun(&a[0][0],9) ;/*若以有定义intsum,a[3][3]={...}*/
函数定义头部:
t-40 :
函数原型:
函数调用:
fun(x) ;/*若以有定义structAx={...}*/
函数定义头部:
t-41:
函数原型:
函数调用:
fun(a,3) ;/*若以有定义structAa[3]={...}*/
函数定义头部:
t-42:
函数原型:
函数调用:
函数定义头部:
intsum(int(*p)[3],intm,intn)
t-43:
函数原型:
函数调用:
函数定义头部:
int*sum(int*p)
在这部分内容中,对于给出的程序我们要非常明确程序采用的调用方式是传值还是传址,两个模块的接口处实参和形参的匹配,子函数返回值和主函数接收值的匹配。
第四部分:
模块内部的任务实现(算法:
解题思路)
多数题目在解题的过程中可能都会用到选择和循环,因此我们有必要首先对程序的这两种结构进行讨论。
选择结构的应用比较简单,只是把我们思维中的选择逻辑依葫芦画瓢的用计算机语句翻译出来就可以,而循环结构的应用对于初学者来说需要花费一定的精力,理解循环的构成,分析每一类题目循环的应用特点。
C语言中的分支语句(第5章)只提供了四种,其中三种if语句(简单if/两分支if/多分支if),一种switch语句。
而应用这四种语句或嵌套能实现任何复杂情况的选择逻辑。
按选择逻辑分类,可有两分支的选