全国计算机等级考试
二级C语言考前复习资料(笔试)
本课主要知识点:
1.知识点:C程序基础
l C语言是一种结构化程序设计语言。三种基本结构:顺序、选择、循环。
例1:(2010-09-11)以下关于结构化程序设计的叙述中正确的是(C)
A)一个结构化程序必须同时由顺序、分支、循环三种结构组成
B) 结构化程序使用goto语句会很便捷
C) 在C语言中,程序的模块化是利用函数实现的
D)由三种基本结构构成的程序只能解决小规模的问题
例2:(2011-03-26)计算机高级语言程序的运行方法有编译执行和解释执行两种,以下叙述中正确的是(A)
A)C语言程序仅可以编译执行
B)C语言程序仅可以解释执行
C)C语言程序既可以编译执行又可以解释执行
D)以上说法都不对
【解析】计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序。翻译的方式有两种,一个是编译,一个是解释。C语言程序仅可以编译。
例3:(2011-03-26)以下叙述中错误的是( D)
A)C语言的可执行程序是由一系列机器指令构成的
B)用C语言编写的源程序不能直接在计算机上运行
C)通过编译得到的二进制目标程序需要连接才可以运行
D)在没有安装C语言集成开发环境的机器上不能运行C源程序生成的.exe文件
【解析】C程序开发过程:编辑—>(.c)编译—>(.obj)链接—>可执行文件(.exe)
2.知识点:C语言程序的构成
l C程序是由函数构成的,一个C程序有且仅有一个main函数。一个函数由两部分组成:函数的首部和函数体。函数体包括声明部分和执行部分。一个C程序总是从main函数开始执行(即程序的入口),由main函数结束,(即程序的出口)。
例1:(2010-03-12)以下叙述正确的是(B)
A)C语言程序是由过程和函数组成的
B) C语言函数可以嵌套调用,例如:fun(fun(x))
C) C语言函数不可以单独编译
D)C语言中除了main函数,其他函数不可作为单独文件形式存在
例2:(2011-09-11)以下叙述中错误的是 (C)
A.C语言编写的函数源程序,其文件名后缀可以是C
B.C语言编写的函数都可以作为一个独立的源程序文件
C.C语言编写的每个函数都可以进行独立的编译并执行
D.一个C语言程序只能有一个主函数
3.知识点:标识符
l 命名规则:
①标识符中只能包含字母(a-z,A-Z),数字(0-9),下划线(_)。
②第一个字符必须是字母或下划线。
分类③用户自定义的标识符 ⅰ格式合法,ⅱ不能使用关键字,ⅲ见名知意
例1:(2010-03-13)以下C语言用户标识符中,不合法的是(D)
A)_1 B)AaBc C)a_b D)a-b
4.知识点:数据类型
例1:(2010-03-16)以下关于C语言数据类型使用的叙述中错误的是(D)
A)若要准确无误差的表示自然数,应使用整数类型
B)若要保存带有多位小数的数据,应使用双精度类型
C)若要处理如“人员信息”等含有不同类型的相关数据,应自定义结构体类型
D)若只处理“真”和“假”两种逻辑值,应使用逻辑类型
【解析】结构数据类型是根据已定义的一个或多个数据类型用构造的方法来定义的,一个结构类型的值可以分解成若干个“成员”或“元素”,每个“成员”都是一个基本数据类型或又是一个构造类型,C项正确。C语言没有逻辑类型,故D项错误。
例2:(2011-03-26)定义无符号整数类为UInt,下面可以作为类UInt实例化值的是(B)
A)-369 B)369 C)0.369 D)整数集合{1,2,3,4,5}
【解析】无符号整数类型为只有正整数和0,所有选择B。
5.知识点:常量
l 整型常量
十进制整常数:没有前缀,其数码为0-9。例如65535,-568
八进制整常数:以0开头,其数码为0-7。例如015
十六进制整常数:以0X或0x开头,其数码为0-9,A-F或a-f。例如0x2A
长整型数:整型常数后缀为L或l。例如358000L
无符号数:整型常数后缀为U或u。例如158u
l 实型常量的形式
小数形式:必须有小数点,小数点前后不能同时没有数字。
指数形式:aEn(其中a表示十进制数,E阶码标志,n阶码)。E前E后必须有数字,E后必为整数,可以带符号。例如2.1E-3、5E8
例1:(2011-09-13)以下选项中关于C语言常量的叙述错误的是:(D)
A.所谓常量,是指在程序运行过程中,其值不能被改变的量
B.常量分为整型常量、实型常量、字符常量和字符串常量
C.常量可分为数值型常量和非数值型常量
D.经常被使用的变量可定义成常量
【解析】根据常量的基本概念,则不难判断A、B、C均正确。
例1:(2009-04-13)以下选项中,能用作数据常量的是(D)
A)o115 B)0118 C)1.5e1.5 D)115L
【解析】八进制整常数以0开头,A项错误;八进制整常数的数码味0-7,B项错误;实型常量的指数形式E后必为整数,故C项错误;长整型数后缀为L或l,故D项正确。
例2:(2010-03-26)以下选项中可用作C程序合法实数的是( A)
A).1e0 B)3.0e0.2 C)E9 D)9.12E
【解析】实型指数表示方式“E前E后比有数,E后必须是整数”,故选A
l 字符常量:用单引号‘’括起来的一个字符。包括普通字符常量和转义字符。
普通字符常量:如‘a’、‘A’、‘1’。
转义字符:由一对单引号引起来的以\开头的若干字符的组合。如‘\n’表示回车换行、‘\\’表示反斜线符、‘\’’表示单引号符、‘\”’表示双引号、‘\ddd’表示八进制数、‘\xhh’表示十六进制数。
例3:(2010-09-15)以下选项中能表示合法常量的是(C)
A)整数:1,200 B)实数:1.5E2.0 C)字符斜杠:‘\\’ D)字符串:“\007”
【解析】表示整常量不能用逗号分隔,A项错误;实型常量的指数形式E后必为整数,故B项错误;’\007’是转义字符,只能用单引号括起来,不能用双引号或其他括号,故D项错误。例4:(2010-03-26)以下选项中不能用作C程序合法常量的是( B)
A)1,234 B)'\123' C)123 D)"\x7G"
【解析】A中的‘,’在编译时会出错的,直接写成1234即可,B是一个三位八进制数代表的字符,C是一个数字常量,D是一个字符串,其中\x7是一个一位十六进制数代表的字符,也即D中的字符串是两个字符,如果sizeof的话是3,如果strlen的话是2。
6.知识点:变量
l 整型变量和实型变量
以考试标准Viusal c++6.0为例,说明各类型变量所占的位数。
类型 |
所占 位数 |
所占 字节数 |
|
类型 |
所占 位数 |
所占 字节数 |
short |
16 |
2 |
unsigned int |
32 |
4 |
|
int |
32 |
4 |
unsigned long |
32 |
4 |
|
long |
32 |
4 |
float |
32 |
4 |
|
unsigned short |
16 |
2 |
double |
64 |
8 |
例1:(2010-09-38)有以下程序
#include
main(0)
{int s,t,A=100;double B=6;
s=sizeof(A); t=sizeof(B);
printf(“%d,%d\n”,s,t);
}
在VC6平台上编译运行,程序运行后的输出结果是(C)
A)2,4 B)4,4 C)4,8 D)10,6
【解析】在VC6平台上,int型占4个字节,double型占8个字节,故答案是C。
l 字符变量:一个字符变量只能存放一个字符。字符串不能存放在字符变量中,只能用字符数组或指针存放字符串。
例1:(2009-09-22)有以下定义语句,编译时会出现编译错误的是(C)
A)char a=’a’; B)char a=‘\n’; C)char a=‘aa’; D)char a=‘\x2d’;
【解析】一个字符变量只能存放一个字符,A项字符变量存放的是普通字符常量;B、D项字符变量存放的转义字符;字符常量只能是单个字符,不能是字符串,’aa’不是单个字符,故C项错误。
7.知识点:ASCII码
l ‘0’的ASCII码值为48;‘A’的ASCII码值为65;‘a’的ASCII码值为97。
l 大写字母与小写字母的ASCII码值相差32。
例1:(2009-09-23)有以下程序
#include
main()
{char c1,c2;
c1=’A’+’8’-‘4’;
c2=’A’+’8’-‘5’;
printf(“%c,%d\n”,c1,c2);
}
已知字母A的ASCII码为65,程序运行后的输出结果是(A)
A)E,68 B)D,69 C)E,D D)输出无定值
【解析】’A’的ASCII码值为65,’8’的ASCII码值为56,’4’的ASCII码值为52,65+56-52=69,对应于字符’E’。’5’的ASCII码值为53,65+56-53=68,对应于字符’D’。字符变量c1以%c格式输出,即’E’。字符变量c2以%d格式输出,即68。故答案是A。
8.知识点:进制转换
l 十进制转换成二进制、八进制、十六进制:将十进制的数字除以2(8、16),得到的商数继续除以2,直到商为0,然后将各次相除所得的余数从后往前排列。
l 二进制、八进制、十六进制转换成十进制:将二(八、十六)进制数的每一位数从高位到低位乘以2的n-1次幂,n为该位所在的位数。
l 二进制与八进制之间的转换:每个八进制数字转换成3位二进制数字。
l 二进制与十六进制之间的转换:每个十六进制数字转换成4位二进制数字。
例1:(2010-09)以下程序运行后的输出结果是 2008 。
#include
main()
{int a=200,b=010;
printf(“%d%d\n”,a,b);
}
【解析】八进制数010转换成十进制数为8,按“%d%d”格式分别输出a、b,即2008。
9.知识点:运算符的优先级
级别由大到小:(逻辑)非 >算(术运算符) >关(系运算符) >(逻辑)与 >(逻辑)或 >条(件运算符) >赋(值运算符)
10.知识点:强制类型转换运算符
l 一般形式:(类型说明符)(表达式)
l 功能:把表达式的运算结果强制转换成类型说明符所表示的类型
例1:(2009-04-06)表达式(int)((double)(5/2)+2.5)的值是4。
【解析】(int)((double)(5/2)+2.5)→(int)((double)2)+2.5)→(int)(2.000000+2.5)→(int)(4.500000) →4。
例2:以下程序运行后的输出结果是() 。
main()
{ int a;
a=(int)((double)(3/2)+0.5+(int)1.99*2);
printf("%d\n",a);
}
答案:3
【解析】(3/2)=1,(double)(3/2)+0.5=1.5,(int)1.99*2=2,所以(double)(3/2)+0.5+(int)1.99*2=3.5,故a=3。
11.知识点:算术运算符: +、—、*、/、%
%:参与运算的量均为整型。
/:当除号左右两边都是整数的时候,商也要是整数,如果不是整数则舍弃小数部分。当参与运算量有一个为实型,则商为double型。
例1:(2011-09-14)若有定义语句:inta=10;double b=3.14;,则表达式‘A’+a+b值得类型是(C)
A.char B.int C.double D.float
【解析】各种类型数据混合运算时,最终结果的类型可依据以下转换规律:
char ->short -> int -> long -> float -> double
例1:(2011-09-15)如有定义语句:intx=12,y=8,z;,在其后执行语句z=0.9+x/y,则z的值为(B)
A.1.9 B.1 C.2 D.2.4
【解析】x,y,z均为整型变量,因此x/y结果为1,即z=0.9+1=1.9,z最终结果为1
例1:(2010-09-14)有以下定义:int a;long b;double x,y;则以下选项中正确的表达式是(A)
A)a%(int)(x-y) B)a=x!=y; C) (a*y)%b D)y=x+y=x
【解析】参与%运算的左右操作数均为整型,故A项正确,C项错误。B项是赋值语句,不是表达式。赋值运算符左边必须是变量,而不是表达式,而D项中x+y=x,错误。
12.知识点:逗号表达式
l 一般形式:表达式1,表达式2……表达式n
l 求值过程:自左向右依次求解,最后一个表达式的值为整个逗号表达式的值。
例1:(2009-04-14)设有定义:int x=2;以下表达式中,值不为6的是(D)
A)x*=x+1 B)x++,2*x C)x*=(1+x) D)2*x,x+=2
【解析】A项x=x*(x+1)=2*(2+1)=6;B项x++后,x的值为3,2*x的值为6,整个逗号表达式的值为6;C项x=x*(1+x)=2*3=6;D项x=x+2=2+2=4,整个逗号表达式的值为4。故答案是D。
13.知识点:自增自减运算符
++i i自加1后再参与运算
i++ i参与运算后再自加1
--i i自减1后再参与运算
i-- i参与运算后再自减1
++和- -的运算对象只能为变量,不能是常量或表达式。
例1:(2009-09-06)若有定义语句:int a=5;则表达式:a++的值是 5 。
【解析】表达式a++的值是a未加1之前的值,即5。.
l 当++或—与printf语句结合时,若++/--x的形式,则先自增/自减,然后输出;若x++/--的形式,则先输出x原值,在进行自增/自减操作。
例2:(2011-03-26)有以下程序
#include
main()
{ int x=011;
printf("%d\n",++x);
}
程序运行后的输出结果是(C)
A)12 B)11 C)10 D)9
【解析】011是一个八进制的数,转为十进制则为1*8+1=9;++x是x先自增1再参与其他运算,所以先x自增1为10再输出即为10,故选C。
14.知识点:赋值表达式
l 一般形式:变量名=表达式
l 赋值运算符左边必须是变量,而不是表达式。
例1:(2010-03-14)若有定义:double a=22;int i=0,k=18;则不符合C语言规定的赋值语句是( C)
A)a=a++,i++; B)i=(a+k)<=(i+k); C)i=a%11; D)i=!a;
【解析】a为double型,参与%运算的操作数均为整型,故C项错误。
例2:(2011-03-26)若有定义语句:int a=3,b=2,c=1;,以下选项中错误的赋值表达式是(A)
A)a=(b=4)=3; B)a=b=c+1; C)a=(b=4)+c; D)a=1+(b=c=4);
【解析】赋值表达式的左边必须是变量不能是表达式。而答案A中,(b=4)是一个赋值表达式。
l 复合赋值运算符和表达式
+=、—=、*=、/=、%=、<<=、>>=、 &=、 ^=、 |=
例2:(2010-09-16)表达式a+=a-=a=9的值是(D)
A)9 B)-9 C)18 D)0
【解析】赋值运算符的结合性是从右到左,a=9→a=a-9=0→a=a+0=0+0=0。故答案是D。
15.知识点:位运算
l 按位与运算&
规则:0&0=0 0&1=0 1&0=0 1&1=1
l 按位或运算|
规则:0|0=0 0|1=1 1|0=1 1|1=1
l 按位异或运算∧
规则:0∧0=0 0∧1=1 1∧0=1 1∧1=0
l 求反运算~
规则:~0=1 ~1=0
l 左移运算<<
规则:把<<左边的运算数的各二进位全部左移若干位,高位丢弃,低位补0。左移一位相当于该数乘以2。左移n位相当于该数乘以2n。
例1:(2010-09-40)有以下程序
#include
main()
{short c=124;
c=c____D____;
printf(“%d\n”,c);
}
若要使程序的运行结果为248,应在下划线处填入的是
A)>>2 B)|248 C)&0248 D)<<1
【解析】左移一位相当于该数乘以2,124>>1相当于124乘以2,等于248。故答案是D。
例2:(2009-04-39)有以下程序
#include
main()
{int a=5,b=1,t;
t=(a<<2)|b;
printf(“%d\n”,t);
}
程序运行后的输出结果是(A)
A)21 B)11 C)6 D)1
【解析】左移2位相当于该数乘以22。5<<2相当于5乘以4等于20。20|1=21。故答案是A。
l 右移运算>>
把>>左边的运算数的各二进位全部右移若干位。高位补0,低位丢弃。右移一位相当于该数除以2。右移n位相当于除以2n。
例3:(2009-09-39)若有以下程序段
int r=8;
printf(“%d\n”,r>>1);
输出结果是(C)
A)16 B)8 C)4 D)2
【解析】右移一位相当于该数除以2。8>>1相当于除以2,等于4,故答案是C。
16.知识点:关系运算符和表达式
例1:(2010-09-08)在C语言中,当表达式值为0时表示逻辑值“假”,当表达式值为
非0 时表示逻辑值“真”。
例2:(2010-03-06)设x为int型变量,请写出一个关系表达式 (x%3==0)&&(x%7==0) ,用以判断x同时为3和7的倍数时,关系表达式的值为真。
17.知识点:逻辑运算符和表达式
l 逻辑运算符优先级从高到低:!、&&、||
l 逻辑运算的真值表
a |
b |
a&&b |
a||b |
!a |
真 |
真 |
真 |
真 |
假 |
真 |
假 |
假 |
真 |
假 |
假 |
真 |
假 |
真 |
真 |
假 |
假 |
假 |
假 |
真 |
l 进行逻辑运算时,若&&左边的值为0,则不再对右边的运算对象进行运算,整个表达式的值为0。
例1:(2011-09-17)若有定义语句:int k1=10,k2=20;,执行表达式(k1=k1>k2)&&(k2=k2>k1)后,k1和k2的值分别为 (B)
A. 0和1 B.0和20 C.10和1 D. 10和20
【解析】k1>k2为假,因此k1= k1>k2结果0,逻辑与左边表达式为假,右边表达式不再处理,因此k1结果为0,k2不变,仍为20
例2:int a=2;则表达式(!a==1)&&(a++==2)的值为0,a的值为2。
【解析】!a为0,!a==1的值为0,&&左边的值为0,则不再对右边的运算对象进行运算,所以a的值为2。
l 若||左边的运算对象的值为1,则不再对右边的运算对象进行运算,整个表达式的值为1。
例2:(2010-03-17)若a是数值类型,则逻辑表达式(a==1)||(a!=1)的值是(A)
A)1 B)0 C)2 D)不知道a的值,不能确定
【解析】a的值有两种情况:a等于1或a不等于1。故逻辑表达式(a==1)||(a!=1)的值为1。
18.知识点:格式输入函数printf()
(1)一般形式:printf(“格式控制字符串”,输出列表);
(2)遇到控制字符,按照控制字符的规定输出,遇到非格式字符串按原样输出。
例1:(2009-04-07)若变量x,y已定义为int类型且x的值为99,y的值为9,请将输出语句printf(“ x/y=%d ”,x/y);补充完整,使其输出的计算结果形式为:x/y=11。
例2:(2009-04-15)程序段:int x=12;double y=3.141593;printf(“%d%8.6f”,x,y);的输出结果是(A)
A)123.141593 B)123.141593 C)12,3.141593 D)123.1415930
【解析】以%8.6f格式输出,即输出的总宽度为8,小数的位数为6。
19.知识点:格式输入函数scanf()
(1)一般形式:scanf(“格式控制字符串”,地址列表);
(2)若格式控制字符串中有非格式字符串,则按原样输入。若格式控制字符串中没有非格式字符作输入数据之间的间隔,则可用空格、Tab、回车作间隔。
例1:(2011-09-16)若有定义:inta,b;,通过语句scanf(“%d;%d”,&a,&b);,能把整数3赋给变量a,5付给变量b的输入数据是
A.3 5 B.3,5 C.3;5 D.35
【解析】scanf格式字符串中两个%d之间带有非格式字符分号,运行时应原样输入。
例1:(2005-04-19)有以下程序
main()
{int m,n,p;
scanf(“m=%dn=%dp=%d”,&m,&n,&p);
printf(“%d%d%d\n”,m,n,p);
}若想从键盘上输入数据,使变量m中的值为123,n中的值为456,p中的值为789,则正确的输入是(A)
A)m=123n=456p=789 B)m=123 n=456 p=789
C)m=123,n=456,p=789 D)123 456 789
【解析】scanf(“m=%dn=%dp=%d”,&m,&n,&p);格式控制字符串中有非格式字符串,则按原样输入,故答案是A。
例2:(2011-03-26)有以下程序段
char name[20];
int num;
scanf("name=%snum=%d",name;&num);
当执行上述程序,并从键盘输入:name=Lili num=1001<回车>后,name的值(A)
A)Lili B)name=Lili C)Lili num= D)name=Lili num=1001
【解析】scanf中格式字符串的非格式字符串原样输入,如其中的‘name=’和‘num=’,所以接受到的name值是后面的Lili,num值为1001。故选A。
(3)在输入字符数据时,若格式控制字符串中无非格式字符,则认为所有输入的字符均为有效字符。空格会被当作字符赋值给变量。
例3:(2009-04-23)有以下程序
#include
main()
{int a1,a2; char c1,c2;
scanf(“%d%c%d%c”,&a1,&c1,&a2,&c2);
printf(“%d,%c,%d,%c”,a1,c1,a2,c2);
}若想通过键盘输入,使得a1的值为12,a2的值为34,c1的值为字符a,c2的值为字符b,程序输出结果是:12,a,34,b则正确的输入格式是(以下_代表空格,
A)12a34b
【解析】空格会被当作字符赋值给变量,故B、D错误;C项中逗号会被当作字符赋值给变量,故C项错误。
(4)格式字符串
l 一般形式:%[*][输入数据宽度][长度]类型
l *表示该输入项,读入后不赋予相应的变量。
l 输入数据宽度:用十进制数指定输入的字符数。
例4:(2010-09-07)有以下程序
#include
main()
{int x,y;
scanf(“%2d%ld”,&x,&y); printf(“%d\n”x+y);
}程序运行时输入:1234567程序的运行结果是 34579 。
【解析】%2d输入的数据宽度为2,x的值为12,y的值为34567,x+y=34579。
例5:(2009-04-16)若有定义语句:double x,y,*px,*py;执行了px=&x;py=&y;之后,正确的输入语句是(C)
A) scanf(“%f%f”,x,y); B)scanf(“%f%f”,&x,&y);
C)scanf(“%lf%le”,px,py); D)scanf(“%lf%lf”,x,y);
【解析】A、D项地址列表,应为&x,&y;x、y为double型,格式控制字符串不是%f%f,故B项错误。
l 当定义的变量类型和scanf中“格式符”类型不一致时(这里只限定在字符型和整型两种类型,其他数据类型不可以。)整型和字符型之间通过ASCALL可以相互转化。
例6:(2011-03-12)有以下程序 (说明:字符0的ASCII码值为48)
main()
{ charc1,c2;
scanf("%d",&c1);
c2=c1+9;
printf("%c%c\n",c1,c2);
}若程序运行时从键盘输入48<回车>,则输出结果为 (09)。
【解析】输入48,则c1=48,c2=48+9,以字符输出c1和c2,则为输出ASCII码为48和57对应的字符,分别为0和9。
20.知识点:字符输出函数putchar()
一般形式:putchar(‘a’);putchar(‘\101’);
21.知识点:字符输入函数getchar()
一般形式:getchar();或ch=getchar();
例1:(2010-03-15)有以下程序
#include
main()
{char a,b,c,d;
scanf(“%c%c”,&a,&b);
c=getchar(); d=getchar();
printf(“%c%c%c%c\n”,a,b,c,d);
}当执行程序时,按下列方式输入数据(从第1列开始,
12
34
则输出结果是(B)
A)1234 B)12 C)12 D)12
3 34
【解析】以%c格式读取一个字符,以getchar()形式也是读取一个字符。空格会被当作字符赋值给变量。所以,a=’1’,b=’2‘,c=’\n’,d=’3‘。
l getchar经常作为while循环条件,判断输入哪一个字符时,循环结束。例如,输入字符串,直到输入‘0’,程序结束,则可写成while( getchar()!='0')
例2:(2011-03-26)有以下程序段
main()
{ …
while( getchar()!='\n');
…
}以下叙述中正确的是(C)
A)此while语句将无限循环
B) getchar()不可以出现在while语句的条件表达式中
C)当执行此while语句时,只有按回车键程序才能继续执行
D)当执行此while语句时,按任意键程序就能继续执行
【解析】while条件表达式getchar()!='\n'只要输入的字符不是回车,就一直执行循环,而循环内是一个空语句,所以按回车键程序才能继续执行,选择C。
第二课 选择结构与循环结构
本课重要知识点:
1.知识点:if语句
l if(表达式),其中表达式可以是任意合法的C语言表达式。
例1:(2011-09-19)下列条件语句中输出结果与其他语句不同的是(D)
A.if(a) printf(“%d\n”,x); else printf(“%d\n”,y);
B.if(a==0) printf(“%d\n”,y); else printf(“%d\n”,x);
C.if(a!=0) printf(“%d\n”,x); else printf(“%d\n”,y);
D.if(a==0) printf(“%d\n”,x); else printf(“%d\n”,y);
【解析】作为if语句的条件,a等价于a!=0,因此 A和C是等价的。
例2:(2011-03-26)if语句的基本形式是:if(表达式)语句,以下关于“表达式”值的叙述中正确的是(D)
A)必须是逻辑值 B)必须是整数值 C)必须是正数 D)可以是任意合法的数值
【解析】表达式不限于关系表达式、逻辑表达式,也可以是任意的数值类型,其中非0为真,0为假。故选D。
l 对于单个if语句,其后跟随的受if控制的只能是1个语句或者是1个复合语句。
例1:(2009-09-17)设有定义:int a=1,b=2,c=3;以下语句中执行效果与其它三个不同的是(C)
A)if(a>b) c=a,a=b,b=c; B)if(a>b){ c=a,a=b,b=c;}
C)if(a>b) c=a;a=b;b=c; D)if(a>b){ c=a;a=b;b=c;}
【解析】对于单个if语句,其后跟随的受if控制的只能是1个语句或者是1个复合语句。故C项,if(a>b)条件成立时,语句c=a;才被执行,而无论if(a>b)条件成立与否,语句a=b;b=c;都会被执行。A、B、D项,只有if(a>b)条件成立时,语句c=a; a=b;b=c; 才被执行。
例2:(2011-03-26)以下程序运行后的输出结果是 200
main()
{ int x=10,y=20,t=0;
if(x==y)t=x;x=y;y=t;
printf("%d %d\n",x,y);
}
【解析】x=10,y=20,所以x==y为false,t=x;不执行,直接执行x=y;y=t;x为20,y为0。注意和if(x==y){t=x;x=y;y=t;}区别。
l 当多个if(表达式)单分支形式并行出现时,其执行顺序是:先判断第一if单分支的条件,如果为真,执行其后面的语句,执行完后,继续向下执行。判断第二个if单分支语句,依次类推。如果第一个if表达式的值为假,则不执行其后的语句,而去判断第二个if单分支条件。
例1:(2011-03-26)有以下程序
main()
{ int x;
scanf("%d",&x);
if(x>15) printf("%d",x-5);
if(x>10) printf("%d",x);
if(x>5) printf("%d\n",x+5);
}若程序运行时从键盘输入12<回车>,则输出结果为 1217
【解析】输入12,比较不大于15所以不执行if(x>15)内的语句;大于10执行printf("%d",x);输出12;大于5执行printf("%d",x+5);输出17。
2.知识点:if语句的嵌套
l 内嵌结构中,else总是与前面最近的且未曾配对的if语句配对,组成一对if-else语句。
例2:(2010-09-18)有以下程序
#include
main()
{int a=1,b=0;
if(!a) b++;
else if(a==0) if(a) b+=2;
else b+=3;
printf(“%d\n”,b);
}程序运行后的输出结果是(A)
A)0 B)1 C) 2 D)3
【解析】else总是与前面最近的且未曾配对的if语句配对,组成一对if-else语句。即else b+=3;
与if(a) b+=2;配对。if(!a)不成立,不执行b++;else if(a==0)不成立,不执行if(a) b+=2;
else b+=3;故直接执行printf(“%d\n”,b);,输出结果为0。
3.知识点:条件表达式
l 一般形式:表达式1?表达式2:表达式3
l 执行过程:表达式1的值为真,条件表达式取表达式2的值;表达式1的值为假,条件表达式取表达式3的值。
例1:(2009-09-19)以下程序段中,与语句:k=a>b?(b>c?1:0):0;功能相同的是(A)
A)if((a>b)&&(b>c)) k=1; B)if((a>b)||(b>c)) k=1;
else k=0; else k=0;
C) if(a<=b) k=0; D) if(a>b)k=1;
else if(b<=c) k=1; else if(b>c) k=1;
else k=0;
【解析】条件运算符的结合性是从右至左。当b>c时,b>c?1:0的值为1,k=a>b?1:0,同时当a>b时,a>b?1:0的值为1,此时k=1。否则k=0。故答案为A。
4.知识点:switch语句
l switch语句的圆括号中的表达式的值必须是整型或字符型,不能为实型。
l case后的表达式可以是求得整型和字符型的常量表达式,但不能含有变量。
l default的位置对程序的执行没有影响。
例1:(2010-09-19)若有定义语句int a,b;double x;则下列选项中没有错误是(C)
A)switch(x%2) B) switch((int)x%2.0)
{case 0:a++;break; {case 0:a++;break;
case 1:b++;break; case 1:b++;break;
default:a++;b++; default:a++;b++;
} }
C)switch((int)x%2) D)switch((int)(x)%2)
{case 0:a++;break; {case 0.0:a++;break;
case 1:b++;break; case 1.0:b++;break;
default:a++;b++; default:a++;b++;
} }
【解析】switch语句的圆括号中的表达式的值必须是整型或字符型,不能为实型。x是double型,x%2不合法,A项错误。(int)x%2.0不合法,B项错误。(int)x%2值为整型,故C项正确。case后面的表达式可以是求得整型量和字符型量的常量表达式,故D项错误。
例2:(2009-09-18)有以下程序
#include
main()
{int c=0,k;
for(k=1;k<3;k++)
switch(k)
{default:c+=k;
case 2:c++;break;
case 4:c+=2;break;
}
printf(“%d\n”,c);
}程序运行后的输出结果是(A)
A)3 B)5 C)7 D)9
【解析】当k=1时,没有匹配的case,执行default语句,c=c+k=0+1=1。继续往下执行case 2后边的语句,c++,c变为2,遇到break语句,于是退出内层switch结构。当k=2时,找到匹配的case 2,执行c++; c变为3,遇到break语句,于是退出内层switch结构。执行外层循环for结构的k++,k变为3,k<3不成立,跳出for语句。最后输出结果为3。
l 当switch语句和循环语句(for、while)时,要注意switch里面的break语句退出的位置。解决这一问题的方法是:首先划分结构,确定循环的语句体包括哪些语句。然后,在继续划分循环体内的语句,如果循环体内的语句只有一条switch语句,其内部出现了break,遇到break,要结束当前switch语句的执行,继续执行下一次循环。
例1:(2011-03-26)有以下程序
main()
{ int s;
scanf("%d",&s);
while(s>0)
{ switch(s)
{case1:printf("%d",s+5);
case2:printf("%d",s+4);break;
case3:printf("%d",s+3);
default:printf("%d",s+1);break;
}
scanf("%d",&s);
}
} 运行时,若输入1 2 3 4 5 0<回车>,则输出结果是(A)
A)6566456 B)66656 C)66666 D)6666656
【解析】while循环s<=0时退出循环,输入1 2 3 4 5 0,只有当输入0时退出循环,switch中当s=1时,执行case 1,case 2,由于case 1后面没有break,会继续执行case 2,遇到break,退出switch;当s=2时,执行case 2,退出switch;当s=3时,执行case 3,default,由于case 3后面没有break,会继续执行default,遇到break,退出switch;当s=4和5时,执行default,退出switch。所以输入1时,输出65;输入2时,输出6;输入3时,输出64;输入4时,输出5;输入5时,输出6。故选择A。
5.知识点:while,do-while,for三种循环结构
例1:(2011-09-20)有以下程序:
#include
main()
{ inta=7;
while(a--);
printf(“%d\n”,a);
}程序运行后的输出结果是 (B)
A.- 1 B.0 C.1 D.7
【解析】此类题一定要注意标点符号的位置,while(a--);该行末尾的分号即为一条空语句,来作为while的循环体。
例1:(2010-09-20)有以下程序
#include
main()
{int a=1,b=2;
while(a<6) {b+=a;a+=2;b%=10;}
printf(“%d,%d\n”,a,b);
}程序运行后的输出结果是(B)
A)5,11 B)7,1 C)7,11 D)6,1
例2:(2011-03)有以下程序段
main()
{ …
while( getchar()!='\n');
…
}以下叙述中正确的是(C)
A)此while语句将无限循环
B) getchar()不可以出现在while语句的条件表达式中
C)当执行此while语句时,只有按回车键程序才能继续执行
D)当执行此while语句时,按任意键程序就能继续执行
【解析】while条件表达式getchar()!='\n'只要输入的字符不是回车,就一直执行循环,而循环内是一个空语句,所以按回车键程序才能继续执行,选择C。
l 循环体部分可以只有一条空语句,不做任何操作。
例3:(2010-09-21)有以下程序
#include
main()
{int y=10;
while(y--);
printf(“y=%d\n”,y);
}程序执行后的输出结果是(B)
A)y=0 B)y=-1 C)y=1 D)while构成无限循环
【解析】while(y--)后面的分号是一个空语句,当y--不等于0时执行空语句,当y—等于0时,执行printf函数输出y值,当y—等于0时退出循环,此时y值变成-1。
l 如果第一次判断表达式的值为0,则循环一次也不执行。即while循环体最少执行0次。
例4:(2011-03)当执行下列程序时,输入1234567890
#include
main()
{char ch;
while((ch=getchar()==’0’)) printf(‘#’);
}
【解析】ch=getchar(),ch第一次读入的值为’1’,故while((ch=getchar()==’0’))不成立,循环一次也不执行。
l while循环与switch结构
例5、(2011-03)有以下程序
main()
{ int s;
scanf("%d",&s);
while(s>0)
{ switch(s)
{case1:printf("%d",s+5);
case2:printf("%d",s+4);break;
case3:printf("%d",s+3);
default:printf("%d",s+1);break;
}
scanf("%d",&s);
}
} 运行时,若输入1 2 3 4 5 0<回车>,则输出结果是(A)
A)6566456 B)66656 C)66666 D)6666656
【解析】:while循环s<=0时退出循环,输入1 2 3 4 5 0,只有当输入0时退出循环,switch中当s=1时,执行case 1,case 2,由于case 1后面没有break,会继续执行case 2,遇到break,退出switch;当s=2时,执行case 2,退出switch;当s=3时,执行case 3,default,由于case 3后面没有break,会继续执行default,遇到break,退出switch;当s=4和5时,执行default,退出switch。所以输入1时,输出65;输入2时,输出6;输入3时,输出64;输入4时,输出5;输入5时,输出6。故选择A。
6.知识点:do-while语句
例1:(2009-09-09)以下程序运行后的输出结果是 5 。
#include
main()
{int a=1,b=7;
do{
b=b/2; a+=b;
}while(b>1);
printf(“%d\n”,a);}
l do-while循环体最少执行1次。
例2:(2007-09)若变量已正确定义,有以下程序段
i=0;
do printf(“%d,”,i); while(i++);
printf(“%d\n”,i); 其输出结果是 (B)
A)0,0 B)0,1 C)1,1 D)程序进入无限循环
【解析】执行do-while循环,输出i的值为0,接着判断循环条件i++,i++的值为0,i的值为1,故答案是B。
7.知识点:for语句
例1:(2011-03)有以下程序
main()
{ char b,c; int i;
b='a'; c='A';
for(i=0;i<6;i++)
{ if(i%2) putchar(i+b);
else putchar(i+c);
}
printf("\n");
} 程序运行后的输出结果是(B)
A)ABCDEF B)AbCdEf C)aBcDeF D)abcdef
【解析】:for循环执行6次,每次判断i能否被2整除,如果不能,则输出i+b,如果可以则输出i+c,注意if(i%2)是求表达式i%2是否为true,即其结果是不是非0。所以i为0时,输出0+A=A,i为1时,输出1+a=b,i为2时,输出2+A=C,i为3时,输出3+a=d,i为4时,输出4+A=E,i为5时,输出5+a=f。故选B。
l 表达式1、表达式2、表达式3可以缺省,但两个分号不能省略。
表达式1省略的情况如下:
例2:(2010-03-21)有以下程序
#include
main()
{int a=1,b=2;
for(;a<8;a++) {b+=a;a+=2;}
printf(“%d,%d\n”,a,b);
}程序运行后的输出结果是(D)
A)9,18 B)8,11 C)7,11 D)10,14
l 表达式1和表达式3也可以是逗号表达式。
例3:(2009-04-20)以下程序段中的变量已正确定义
for(i=0;i<4;i++,i++)
for(k=1;k<3;k++) printf(“*”);程序段的输出结果是 (B)
A)******** B)**** C)** D)*
【解析】外层for循环,表达式3是逗号表达式,即i自加2。.
l for循环与switch结构
例4:(2009-09-29)有以下程序
#include
main()
{int a[]={2,3,5,4},i;
for(i=0;i<4;i++)
switch(i%2)
{case 0:switch(a[i]%2)
{case 0:a[i]++;break;
case 1:a[i]--;
}break;
case 1:a[i]=0;
}
for(i=0;i<4;i++) printf(“%d”,a[i]); printf(”\n”);
}程序运行后的输出结果是(C)
A)3 3 4 4 B) 2 0 5 0 C)3 0 40 C)0 3 0 4
例5、(2011-03)有以下程序段
int i,n;
for(i=0;i<8;i++)
{ n=rand()%5;
switch (n)
{ case1:
case 3:printf("%d\n",n);break;
case 2:
case 4:printf("%d\n",n);continue;
case 0:exit(0);
}
printf("%d\n",n);
} 以下关于程序段执行情况的叙述,正确的是(D)
A)for循环语句固定执行8次
B)当产生的随机数n为4时结束循环操作
C)当产生的随机数n为1和2时不做任何操作
D)当产生的随机数n为0时结束程序运行
【解析】:rand()是随机产生一个整数,rand()%5即随机得到0-4这五个数字,for循环控制随机产生8次,当得到1,3时执行printf("%d\n",n)并退出switch,当得到2,4时执行printf("%d\n",n)并继续循环,当得到0时,exit(0)正常结束程序。所以循环不一定执行8次,故选择D。
l for循环与数组
例6:(2010-09-09)有以下程序
#include
main()
{int i,n[]={0,0,0,0,0};
for(i=1;i<=4;i++)
{n[i]=n[i-1]*3+1; printf(“%d ”,n[i]);}
}程序运行后的输出结果是 1 4 13 40 。
l 注意区 赋值语句和判断语句
例 7:(2011-03)若i和k都是int类型变量,有以下for语句
for(i=0,k=-1;k=1;k++) printf("*****\n");
下面关于语句执行情况的叙述中正确的是 (D)
A)循环体执行两次 B)循环体执行一次
C)循环体一次也不执行 D)构成无限循环
【解析】:for循环的表达式1和表达式3可以是一个简单的表达式也可以是逗号表达式,本题表达式1是一个逗号表达式,i赋值为0,同时k赋值为-1。所以判断表达式2:k=1是k赋值为1,故无限循环,选择D。
8.知识点:循环嵌套
例1:(2010-03-20)有以下程序
#include
main()
{int i,j,m=1;
for(i=1;i<3;i++)
{ for(j=3;j>0;j--)
{if(i*j>3) break;
m*=i*j;
}
}
printf(“m=%d\n”,m);
}程序运行后的输出结果是 (A)
A)m=6 B)m=2 C)m=4 D)m=5
例2:(2011-03)有以下程序
main()
{ int x=1,y=0;
if(!x) y++;
else if(x==0)
if (x) y+=2;
else y+=3;
printf("%d\n",y);
}程序运行后的输出结果是(D)
A)3 B)2 C)1 D) 0
【解析】:if-else的嵌套,注意else总是与前面最近的且未配对的if语句配对组合。if(!x)中x为1,!x为0为false,即if(!x) 后的语句不执行,else if(x==0),x为1也不等于0,也不成立,故else if内的语句也不执行,而if (x) y+=2;else y+=3;均为else if内的语句。所以直接输出y为0,故选D。
9.知识点:break语句
l 功能:跳出整个switch语句;跳出循环体,防止死循环。
l break语句只能出现在switch、while、do-while、for循环中,不能出现在其他地方。
l 作用范围:所在循环体从属的最内层循环,而不是外层的某个循环。
6.知识点:continue语句
l 功能:结束本次循环,接着判断是否继续下一次循环。
l continue语句只能出现在while、do-while、for循环中。
l 作用范围:所在循环体从属的最内层循环,而不是外层的某个循环。
例1:(2009-04-09)以下程序运行后的输出结果是 s=0
#include
main()
{int k=1,s=0;
do{
if((k%2)!=0) continue;
s+=k; k++;
}while(k>10);
printf(“s=%d\n”,s);
}
【解析】k=1,if((k%2)!=0)条件成立,执行continue语句,结束本次循环,判断表达式k>10,值为0,故跳出do-while循环,执行printf(“s=%d\n”,s);则输出结果为s=0。
本课重要知识点:
1.知识点:一维数组的定义
例1:(2010-03-25)下列选项中,能正确定义数组的语句是(D)
A)int num[0…2008]; B)int num[];
C)int N=2008; D)#define N 2008
int num[N]; int num[N];
【解析】数组的长度必须是一个整型常量、整型常量表达式,故A项错误。定义数组时,不能省略数组长度,B项错误。数组的长度不能是变量,C项错误。数组的长度可以是符号常量,D项正确。
例2:(2010-09-28)若要定义一个具有5个元素的整型数组,以下错误的定义语句是(D)
A)int a[5]={0}; B)int b[]={0,0,0,0,0};
C)int c[2+3]; D)int i=5,d[i];
【解析】可以只给数组的前面一部分元素设定初值,A项正确。对全部数组元素赋初值时,可以不指定数组元素的个数,B项正确。数组的长度可以是一个整型常量表达式,C项正确。数组的长度不能是变量,D项错误。
2.知识点:一维数组元素的引用
例1:(2008-09-21)若有定义语句:int m[]={5,4,3,2,1},i=4;则下面对m数组元素的引用中错误的是 (C)
A)m[--i] B)m[2*2] C)m[m[0]] D)m[m[i]]
【解析】m数组元素的引用的下限为0,上限为4。i=4,--i的值为3,A项正确。B项没有越界,正确。m[0]=5,超过上限,已经越界,故C项错误。m[4]=1,没有越界,故D项正确。
例2:(2011-03)以下程序运行后的输出结果是 13715
main()
{ int i,n[5]={0};
for(i=1;i<=4;i++)
{ n[i]==n[i-1]*2+1; printf("%d",n[i]); }
printf("\n");
}
【解析】:n[1]=1,n[2]=1*2+1=3,n[3]=3*2+1=7,n[4]=7*2+1=15
3.知识点:一维数组的初始化
l 顺序列出数组元素的全部初值,例如inta[5]={1,2,3,4,5};
l 只给数组的前面一部分元素设定初值,未赋初值的元素自动取0值。例如,int a[5]={1,2};
l 对全部数组元素赋初值时,可以不指定数组元素的个数。例如,inta[]={1,2,3,4,5};
4.知识点:二维数组的初始化
l 按行分段给二维数组赋初值
l 按行连续赋值
l 对部分元素赋初值,未赋初值的元素自动取0值
l 若对全部元素赋初值,则第一维的长度可以不指定
例1:(2006-04-16)以下数组定义中错误的是(B)
A) int x[][3]={0};
B) intx[2][3]={{1,2},{3,4},{5,6}};
C) int x[][3]={{1,2,3},{4,5,6}};
D) int x[2][3]={1,2,3,4,5,6};
【解析】若对全部元素赋初值,则第一维的长度可以不指定,C项正确。二维数组的初始化可以按行连续赋值,D项正确。C项二维数组的初始化超过第一维度长度,故错误。
5.知识点:二维数组和for语句
例1:(2010-03-09)有以下程序
#include
main()
{int i,j,a[][3]={1,2,3,4,5,6,7,8,9};
for(i=0;i<3;i++)
for(j=i;j<3;j++) printf(“%d”,a[i][j]);
printf(“\n”);
}程序运行后的输出结果是 123569 。
6.知识点:字符串
定义:由“”引起来的,由若干个字符所组成的序列。
字符串的结束标志:’\0’
如字符串“china”,在内存中存储形式是
c |
h |
i |
n |
a |
\0 |
该字符串的长度为5字节,所占的存储空间为6字节。
7.知识点:字符数组的定义及初始化
l 字符数组名是地址常量,不能赋值给数组名。
例1:(2009-04-32)以下选项中正确的语句组是(D)
A)char s[];s=”BOOK!”; B)char *s;s={“BOOK!”};
C)char s[10];s=”BOOK!”; D)char *s;s=”BOOK!”;
【解析】字符数组名是地址常量,不能赋值给数组名,故A、C项错误,D项指针s是个变量,将字符串常量赋值给s,是正确的。B项中给s赋值时不能用花括号将字符串括起来。
例2:(2009-09-31)下面是有关C语言字符数组的描述,其中错误的是(D)
A)不可以用赋值语句给字符数组名赋字符串
B)可以用输入语句把字符串整体输入给字符数组
C)字符数组中的内容不一定是字符串
D)字符数组只能存放字符串
8.知识点:字符数组的输入与输出
例1:(2009-09-13)有以下程序
#include
main()
{char a[20]=”How are you?”,b[20];
scanf(“%s”,b);printf(“%s %s\n”,a,b);
}程序运行时从键盘输入:Howare you?<回车>
则输出结果为How are you? How
【解析】scanf函数输入,以空格作为字符串输入结束的标志,故字符数组b只接收到字符串”How”。
例2:(2011-03)有以下程序
main()
{ char a[30],b[30];
scanf("%s",a);
gets(b);
printf("%s\n%s\n",a,b);
}程序运行时若输入:howare you? I am fine<回车>则输出结果是(B)
A)how are you? B)how
I amfine are you?I am fine
C)how are you? I am fine D)row are you?
【解析】:scanf以空格作为字符串输入结束的标志,而gets(s)不会。所以a得到的是“how”,b得到的是剩下的“are you? I am fine”。故选择B。
例3:(2011-03)有以下程序
main()
{ chars[]="012xy\08s34f4w2";
inti, n=0;
for(i=0;s[i]!=0;i++)
if(s[i]>='0'&&s[i]<='9') n++;
printf("%d\n",n);
} 程序运行后的输出结果是 (B)
A)0 B)3 C)7 D)8
【解析】:for循环读取字符数组s中的字符,当读到0时退出循环,注意0和‘0’的区别,字符‘0’的ASCII码为48,‘\0’的ASCII 码才是0,所以读取的字符为“012xy”中的字符,for循环读取到字符后判断是不是数字字符,如果是n自增1,“012xy”中的数字字符只有三个,所以选择B。
9.知识点:字符串处理函数
例1:(2011-09-32)有以下程序:
#include
#include
main()
{ chara[5][10]={“china”,”beijing”,”you”,”tiananmen”,”welcome”};
int i,j; char t[10];
for(i=0;i<4;i++)
for(j=i+1;j<5;j++)
if(strcmp(a[i],a[j])>0)
{ strcpy(t,a[i]); strcpy(a[i],a[j]); strcpy(a[i],t);}
puts(a[3]);
}程序运行后的输出结果是 (C)
A.beijing B.china C.welcome D.tiananmen
【解析】双层for循环部分是典型的排序方法,通过strcmp比较两个字符串的大小,然后借助t数组作为中转数组,通过strcpy函数完成a[i]和a[j]两个字符串的交换,使a数组按从小到大排序,即{”beijing” , “china” , ”tiananmen”,”welcome”,”you” }
例1:(2010-09-23)有以下程序
#include
#include
main()
{char x[]=”STRING”;
x[0]=0;x[1]=’\0’;x[2]=’0’;
printf(“%d %d\n”,sizeof(x),strlen(x));
}程序运行后的输出结果是(B)
A)6 1 B)7 0 C)6 3 D)7 1
【解析】经过x[0]=0;x[1]=’\0’;x[2]=’0’;后,x[]=”0\00ING”。strlen测字符串的实际长度,不含字符串结束标志’\0’,故strlen(x)为0。sizeof测字符串所占的存储空间,包含字符串结束标志,故sizeof(x)为7。
例2:(2010-09-33)有以下程序
#include
#include
main()
{char a[20]=”ABCD\0EFG\0”,b[]=”IJK”;
strcat(a,b); printf(“%s\n”,a);
}程序运行后的输出结果是(B)
A)ABCDE\0FG\0IJK B)ABCDIJK C)IJK D)EFGIJK
【解析】把字符数组b中的字符串连接到字符数组a中字符串的后面,并删去字符串a后的第一个字符串结束标志’\0’。故输出结果为ABCDIJK。
例3: (2010-09-31)下列选项中,能够满足“若字符串s1等于字符串s2,则执行ST”要求的是 (A)
A)if(strcmp(s2,s1)==0)ST; B)if(s1==s2)ST;
C)if(strcpy(s1,s2)==1)ST; D)if(s1-s2==0)ST;
【解析】若字符串s1等于字符串s2,strcmp(s2,s1)==0,故答案是A。
第四课 指针
本课重要知识点:
1.知识点:指针的概念与指针变量
l 指针就是地址。指针变量是用来存储地址,而一般变量是用来存储数值。
例1.(09-09-26)有如下程序输出结果为 1,2,2,1
#include
main()
{ int m=1,n=2,*p=&m,*q=&n,*r;
r=p ;p=q ;q=r ;
printf(“%d,%d,%d,%d\n”,m,n,*p,*q) ;
}
【解析】p、q为指针,初始化时p指向m,q指向n。执行r=p ;p=q ;q=r ;p和q的值交换,从而p指向n,q指向m。指针的改变不会应用m、n的值,最后输出*p和*q的值分别为n、m的值。
2.知识点:指针的引用
l 指针的引用是通过两个运算符实现“&”和“*”实现的
&是取地址符号,它的一半格式是:&变量名。例如:int i ; &i表示取i的地址。
*是取值运算符,它的一般格式:*指针变量名。例如:inti=10,*p=&i; *p表示取i的值10
例1.(2011-09-25)若定义语句:intyear=2009,*p=&year;,以下不能使变量year中的值增至2010的语句是 (D)
A.*p+=1; B.(*p)++; C.++(*p); D.*p++;
【解析】*和++同级别,按自左向右的结合方向,因此D选项可转变为*(p++),从而只是使指针发生移动,而不能将p所指变量增1
例2.(06—04—24)若有说明语句:double *p,a;则能通过scanf语句正确给输入项读入数据的程序段是 (D)
A)*p=&a; scanf("%lf",p);
B)*p=&a; scanf("%f",p);
C)p=&a; scanf("%lf",*p);
D)p=&a; scanf("%lf",p);
【解析】对于scanf函数,输入数据列表必须是合法地址表达式(可以使地
址常量、指针),A选项、B选项*使用错误。
例3.(09-03-16)若有定义语句 doule x,y,*px,*py;执行了px=&x;py=&y;之后,正确的输入语句是(C)
A) scanf("%f%f",x,y); B) scanf("%f%f"&x,&y);
C)scanf("%f%le",px,py); D) scanf("%lf%lf",x,y);
【解析】A,D选项中的x,y缺少取地址符,B项中&x之前缺少逗号,格式不正确。
3.知识点:指针变量的初始化
l 指针变量在使用前必须要初始化,把一个具体的地址赋给它,否则引用时会出错,如果不指向任何数据就赋“空值”NULL。
l 指针变量两种初始化方法:方法一:int a=2,*p=&a;(定义的同时初始化)
方法二:int a=2,*p;p=&a;(先定义后初始化)
例1.(07—04—29)设已有定义:float x;则以下对指针变量P进行定义且赋初值的语句中正确的是 (D)
A)float *p=1034; B)int *p=(float)x; C)float p=&x; D)float *p=&x;
【解析】可以给一个指针赋值的只能是一个与该指针同类型的指针(或地址值);故A、B选项错误;C选项声明指针出错,P前面的指针说明符*不能省略。
4.知识点:指针的运算
l *p++和(*p)++之间的差别:*p++是地址变化,(*p)++是指针变量所指的数据变化。一个指针变量加一个整数不是简单的数学相加,而是连续移动若干地址。当两个指针指向同一数组时,它们可以比较大小进行减法运算。
例如:int a[10],*p; p=a; p++;表示p移动一个存储单元,p指向a[1],只有当指着指向数组元素时,指针的运动才有意义。
5:知识点:指针与数组
l 指针与一维数组
数组名代表数组的首地址。一维数组中,第一个元素的地址即为该数组的起始地址。建立指针变量与一维数组的联系:
例如: inta[6],*pa; pa=a;或pa=&a[0];
说明:①数组名a代表该数组的首地址,也即a[0]的地址。
② pa=a;或pa=&a[0];使pa保存了数组a的首地址,pa,a,&a[0]都指向一个地址。
③以上操作可等价于 int a[6],*pa=a;
④如果pa=&a[3];表示*pa的值就是a[3]的地址。
注意:数组a是一个地址常量,它永远指向数组的首地址,不能重新赋值。因此 a=&i;或a++都是错误的。
例1.(08—04—23)有以下程序
#include
main()
{int a[]={1,2,3,4),y,*p=&a[3];
--p;y=*p;printf("y=%d\n",y);
} 程序的运行结果是(D)
A)y=0 B)y=l C)y=2 D)y=3
【解析】程序中定义一个一维数组,并初始化,再一定义了一变量和一个指针(将指针指向数组下标为3的一个元素),执行--p;(注意,当指针指一个元素后,指针变量加上“*”时,表示引用的是元素的值,当不加“*“时表示引用的是地址),向前移动一个位置,指向a[2],y=+p;(将p指针指向的值3赋给变量y),输出y的值为3。
例2.(11-03-24)设有定义:double x[10],*p=x;,以下能给数组x下标为6的元素读入数据的正确语句是( C )
A)scanf("%f",&x[6]); B)scanf("%lf",*(x+6));
C)scanf("%lf",p+6); D)scanf("%lf",p[6]);
【解析】数组名是数组的首地址,p=x,指针p指向数组的首地址,要表示数组x下标为6的元素的地址可以有&x[6],x+6,p+6,&p[6],scanf后面的参数列表必须是地址列表,B中*(x+6)D中p[6]都是取数组x下标为6的元素的值,A中格式控制符%f与double类型不匹配,所以选C。
6.知识点:用指针访问数组元素
l 通过指针引用数组元素
例如:int*p,a[5]; p=&a[0];
说明:①指针变量p指向了数组元素a[0],可以使用访问运算符“*”来引用变量a[0];
例:*p=18;等价于a[0]=18;
②*(p+1)表示a[1] p+1表示&a[1]
l 通过数组的首地址引用数组元素
例如:int a[5];
说明:①a是数组名,表示收地址,可以把a当做一个指针常量。
②*a等价与a[0],*(a+1)等价与a[1];a等价于&a[0],a+1等价与&a[1];
l 用带下标的指针变量引用一维数组元素
例如:int*p,a[5]; p=a;
说明:①p[0]表示p指针指向的内存单元,p[1]表示p指向的内存单元
②a[i]的等价引用方法:a[i]、p[i]、*(a+i)、*(p+i)
③a[i]的地址等价引用方法:&a[i]、&p[i]、a+i、p+i
例1.(09-03—29)若有以下定义
int x[10],*pt=x;
则对x数组元素的正确应用是 B
A)*&x[10] B)*(x+3) C)*(pt+10) D)pt+3
【解析】引用数组元素时,注意取地址运算符&与指针运算符t的作用;指针运算符+用来取得指针变量所指存储空间的内容,取地址运算符&用来取得变量的地址值;A选项数组下标越界;B选项中+(x+3)等价于元素X[3];C选项中。(pt+10)等价于x[10],数组下标越界;D选项pt+3是元素x[3]的地址,与&x[3]等价;故正确答案是B。正确答案:B
例1.(2011-09-27)有以下程序
#include
void fun(int *p)
{printf(“%d\n”,p[5]);}
main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};
fun(&a[3]);
}程序运行后的输出结果是 (D)
A.5 B.6 C.8 D.9
【解析】fun函数被调用时将&a[3]通过传递付给了形参指针变量p,此时可用*p或p[0]来表示a[3],因此p[5]亦可表示a[8],所以输出结果为9
7.知识点:指针与二维数组
l 任何一个二维数组均由若干个一维数组组成,a[0]、a[1]和a[2]是一维数组名,数组名代表数组的首地址,因此a[0]就代表数组元素a[0][0]的地址,也即&a[0][0]。
注意:a的值与a[0]相同,但它们的基类型不同,a可以等价于一个二维指针,而a[0]是一维指针。因此 int a[3][4],*p=a;错误
取数组元素a[i][j]的地址的几种方法:&a[i][j];a[i]+j; *(a+i)+j;
l 指针数组的定义方式:
*指针数组名[常量表达式];如:int *p[3];
l 行指针的一般定义形式如下:
类型名(*指针数组名)[常量表达式]; 如:int (*p)[2];
l 指针数组与行指针的区别
1、int *p[3];定义的是指针数组,表示一个数组,含有3个元素p[0]、p[1]、p[2],且这3个元素只能存放整型元素的地址
2、int (*p)[3];定义的是行指针,表示一个指针变量,它仅有一个存储空间,只能存放一个长度为2的一维数组指针。
例1.(06—09—33)若有定义语句:int k[2][3],*pk[3];则以下语句正确的是(B)
A)pk=k; B)pk[0]=&k[1][2]; C)pk=k[0]; D)pk[1]=k;
【解析】题目中定义了一个二维数组和一个指针数组,pk是指针数组名,不能被赋值,指针数组pk中的元素是指针,并且二维数组名是指向一维数组的指针常量,相当于行指针,二者不可转换,所以A、C、D选项均有误,本题答案选B。
例2.(09-09-27) 若有定义语句: int a[4][10],*p,*q[4];且0<=i<4,则错误的赋值是 (A)
A)p=a B)q[i]=a[i] C)p=a[i] D)p=&a[2][1]
【解析】p为基类型为int的指针,指向一个整形数据,也就可以指向一个数组元素,所以D正确。指针数组q的每个数组元素q[i]的基类型也为int,所以p、a[i]、a[i]的基类型一致,选项B、C也是正确的。
8.知识点:指针与函数
例1.(08—04—40)设有定义语句int(*f)(int);,则以下叙述正确的是__B_______。
A)f是基类型为int的指针变量
B)f是指向函数的指针变量,该函数具有一个int类型的形态
C)f是指向int类型一维数组的指针变量
D)f是函数名,该函数的返回值是其类型为int类型的地址
【解析】在c语言中,函数名代表此函数的入口地址,所因此,可以定义一种指向函数的指针来存放函数的入口地址,定义方式是:函数返回值类型(*函数指针名)(参数类型列表);本题答案选B。
9.知识点:指针与字符串
l 可以通过字符指针来处理字符串
例如:char *p="China"或者char *p;p="China";把字符串赋值给指针p,实质是把保存字符串"China"的那段内存的首地址赋值给指针p,使得指针p指向了字符串,这样就可以通过指针来操作字符串了。
【注意】char str[10] ; str="China";是错误的!数组名是地址常量,不能进行赋值操作!
l “三名主义”(考试的重点)
数组名:表示第一个元素的地址。数组名是地址常量名,不能进行赋值和自加(减)等运算。(考了很多次)
函数名:表示该函数的入口地址。
字符串常量名:表示第一个字符的地址。
例11.(2011-09-22)有以下程序(注:字符a的ASCII码值为97)
#include
main()
{ char *s={“abc”};
do
{printf(“%d”,*s%10);++s;}
while(*s);
}程序运行后的输出结果是 (B)
A.abc B.789 C.7890 D.979898
例11.(2011-09-30)若有定义语句:char*s1=”OK”;*s2=”ok”;,以下选项中,能够输出“OK”的语句是 (D)
A.if(strcmp(s1,s2)==0) puts(s1);
B.if(strcmp(s1,s2)!=0) puts(s2);
C.if(strcmp(s1,s2)==1) puts(s1);
D.if(strcmp(s1,s2)!=0) puts(s1);
【解析】strcmp函数作为字符串比较函数,当s1等于s2所指字符串时结果为0,当s1大于s2所指字符串时结果为 >0,当s1小于s2所指字符串时结果为 <0
例11.(07—04—44)有下列程序:
main()
{char ch[]=“uvwxyz”,*pc;
pc=ch;printf(”%c\n”,*(pc+5));
} 程序运行后的输出结果是(A)
A)Z B)0 C)元素ch[5]的地址 D)字符Y的地址
【解析】指针P指向了字符数组ch,*(pc+5)-->ch[5]-->’z’,printf函数要求以%c形式输出,故输出字符Z。
例12.(09-09-37)设有定义:char *c;.以下选项中能够使字符型指针c正确指向一个字符串的是(A)
A)char str[]=”string”; c=str; B)scanf(“%s”,c);
C)c=getchar(); D)*c=”string”;
【解析】选项A为正确用法。先将字符串存于字符数组中,然后将数组名赋给字符指针。选项B为无语法错误,但运行时可能会出现问题。原因是字符指针没有被赋值,是一个不确定的值,指向一个不确定的内存区域,这个区域可能存放有用的指令或数据。在这个不确定的区域重新存放输入的字符串,可能会发生无法预知的错误。选项C错误。getchar()函数输入一个字符给字符型变量,而不应该是字符指针。选项D错误。*c=”string”应该改为c=”string”才是正确的。
第五课 函数
本课重要知识点:
1、知识点:函数的概述
l C源程序是由函数组成的,函数由函数首部与函数体组成,函数体包括声明部分和执行语句部分组成。
l C语言程序可以由多个源程序组成,其中一个源程序文件包含main函数,其他函数可以写在另外的源程序文件中,为单独文件,并且可以单独编译。
例1:(10-03-11)以下叙述正确的是( B )
A)C语言程序是由过程和函数组成的
B)C语言函数可以嵌套调用,例如:fun(fun(x))
C)C语言函数不可以单独编译
D)C语言中除了main函数,其他函数不可以作为单独文件形式存在
【解析】选项A错误,C语言中没有过程的概念;选项B正确,C语言可以嵌套调用(此知识点在后面介绍);选项C错误,C语言中可以对包含一个或多个函数的源程序单独编译;选项D错误,C语言函数可以单独存在。
l C程序的执行总是从main函数开始,完成对其它函数的调用后再返回到main函数,最后由main函数结束整个程序。main 函数可以调用其它函数,而不允许被其它函数调用。一个C源程序必须有,也只能有一个主函数main。
例1:下列叙述中正确的是( C )
A)C语言程序将从源程序中第一个函数开始执行
B)可以在程序中由用户指定任意一个函数作为主函数,程序将从此开始执行
C)C语言规定必须用main作为主函数名,程序将从此开始执行,在此结束
D)main可作为用户标识符,用以命名任意一个函数作为主函数。
l 在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。
例1、下列叙述中正确的是( D )
A)每个C程序文件中都必须要有一个main()函数
B)在C程序中main ()函数的位置是固定的
C)C程序中所有函数之间都可以是固定的
D)在C程序的函数中不能定义另一个函数
【解析】一个C源程序可以由多个C程序文件,但只能有一个main()函数,并不是每个C程序文件都必须要有一个main(),main()函数可以放在任意位置,且不允许被其他函数调用,因此正确答案是D。
2、知识点:函数的定义
例1:以下正确的函数定义形式是:(C)
A)double fun(int x,int y);{} B) double fun(int x ;inty){}
C) double fun(int x,int y){} D) double fun(int x, y);{}
【解析】在函数中对形参的说明,要求对每个形参都必须说明类型,各参数之间用“,间i;le fun(intx,int y); D)”隔开,函数定义后应无“;”。
l 函数返回return语句的一般形式:return 表达式;或return (表达式);
在函数中允许有多个return语句,但每次只能有一个return语句被执行。
例1:(10-03-24)以下关于return语句叙述中正确的是( B)
A)一个自定义函数中必须有一条return语句
B)一个自定义函数中可以根据不同情况设置多条return语句
C)定义void类型的函数中可以有带返回值的return语句
D)没有return语句的自定义函数在执行结束时不能返回到调用处。
【解析】自定义函数中可以没有return语句(如不需要返回值的函数,常见void类型)),可以有多条return语句(如在分支结构中,可以从不同分支中返回到调用程序,常见if..else);定义成void类型的函数,不允许从该函数取得返回值,也不允许使用return语句。没有return语句的函数在执行到函数的最后一条语句后自动返回达到调用处。
Ø 函数值的类型与函数定义中函数的类型保持一致,如不一致,以函数类型为准。
例2:(06-04-23)已定义以下函数
intfun(int *p){return *p;} fun函数返回值是( B )
A)不确定的值 B)一个整数 C)形参P中存放的值 D)形参P的地址值
【解析】函数返回性类型取决于定义函数时函数名称前的类型,fun前是int,表明函数fun执行完毕后返回一个整型数。正确答案:B
Ø return 后的表达式可以是常量、变量、表达式,也可以空。
如:return ; return 0; return a; return (a+b);
3、知识点:形参和实参及函数调用
l 形参出现在函数定义中(即定义函数时函数名后面括号中的参数),实参出现在主调函数中(调用函数时函数名后面括号中的参数)
l 形参在本函数体内都可以使用,离开该函数则不能使用。实参在主调函数中内有效,进入被调函数后,实参变量也不能使用。(注:在进行函数调用时,函数必须有确定的值)
l 实参向形参单向传递数值,不能将形参的值反向的传送给实参。实参和形参在数据上、类型上、顺序上要一致。在函数调用过程中,形参的变化不会改变实参的变化。
例1、(09-09-24)有以下程序
#include
void fun(int p)
{ int d=2; p=d++;printf(“%d”,p); }
main()
{ int a=1;
fun(a); printf(“%d\n”,a);
} 程序运行后的输出结果是( C)
A) 32 B)12 C)21 D)22
【解析】此题考点为函数参数的传递。C语言中函数参数的传递是值传递,是把实参的值传给形参,是单向传递,形参的改变不会影响到实参的值。程序中,把实参a的值传给形参p,p=1,然后p=d++,再次赋值后p=2,输出p的值2。返回到主程序中,输出a的值为1。(形参p的改变不会影响到实参a的值,a的值仍为1).因此答案为C.
l 在传递数值时,形参和实在分别占据不同的存储单元(形参变量只有在被调用时才分配内存单元,调用结束后,即刻释放分配的内存单元)
例1、(07-04-25)若函数调用时的实参为变量时,以下关于函数形参和实参的叙述中正确的是( D)
A)函数的实参和其对应的形参共占同一存储单元
B)形参只是形式上的存在,不占用具体存储单元
C)同名的实参和形参占同一存储单元
D)函数的形参和实参分别占用不同的存储单元
【解析】本题考点是函数的参数定义,在函数中,主调数中里边的参数叫做实参,而被调函数里边的参数叫做形参,当函数传递时,传递的是值,它们占用的不是同一存储单元,而且在传递中,是单向传的,由实参传向形参。
l “传值”与“传址”的区别:传数值的话,形参的变化不会改变实参的变化。传地址的话,形参的变化就有可能改变实参所对应的量。
例1:(10-03-26)有以下程序
#include
void fun(char *c,int d)
{ *c=*c+1; d=d+1;
printf(“%c,%c”,*c,d);
}
main()
{ char b=’a’, a=’A’;
fun(&b,a);
printf((“%c,%c\n”,b,a);
} 程序运行后的输出结果是(A)
A) b,B,b,A B)b,B,B,A C)a,B,B,a D)a,B,a,B
4、知识点:函数调用的一般形式和调用方式
l 函数调用的一般形式为:函数名(实际参数表);
实参可以是常数、变量或其他构造类型数据及表达式,也可以没有(当为无参函数时)
l 函数调用的方式:
(1)函数表达式:函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式运算。例如:z=max(x,y);
(2)函数语句:函数调用的一般形式上加上分号。例如:printf(“%d\n”,a);
(3)函数实参:函数作为另一个函数调用的实际参数出现。例如:printf(“%d”,max(x,y));
l 程序从main函数进入,上往下执行,当碰到函数名后,把值传给调用函数,当程序得到了返回值或调用函数结束,再顺序往下执行,最后到main函数结束。
5、知识点:函数的声明及其位置
l 函数要“先定义后调用”,或“先声明再调用后定义”。函数的声明一定要有函数名、函数返回值类型、函数参数类型,但不一定要有形参的名称。
一般形式为:
类型说明符被调函数名(类型形参,类型形参…);
或 类型说明符被调函数名(类型,类型…);
注意:其末尾“;”不能省
例如:int max(int a,int b); 或 int max(int ,int); 两者功能相同
例1、(06-09-32)若有以下函数首部
int fun(double x[10],int *n)
则下面针对此函数声母语句中正确的是(D)
A)int fun(double x,int *n); B)int fun(double,int);
C)int fun(double*x,int n); D)int fun(double *,int。);
【解析】本题考点是对函数的声明,在函数声明的时候,其格式如下:返回值类型函数名(参数类型[参数名],参数类型[参数名]……)其中,参数名可以不写,但是参数类型一定要写全
l 省去主调函数中对被调函数的函数说明的几种情况:
(1)被调函数的返回值是整型或字符型时(返回值自动按整型处理)
(2)当被调函数的函数定义在主调函数之前时
(3)在所有函数定义之前,在函数外预先说明了各个函数的类型
例2:(10-09-24)有以下程序
#include
int f(int x);
main()
{ int n=1,m;
m=f(f(f(n))); printf(“%d\n”,m);
}
int f(intx)
{ returnx*2;}
程序运行的输出结果( D )
A) 1 B)2 C)4 D)8
【解析】f函数定义在main下面,但在外部进行声明int f(int x);因此在main中可直接调用。
三次调用函数:f(n)=f(1)=2 f(2)=4 f(4)=8 m=f(f(f(n)))=f(f(f(1)))=f(f(2))=f(4)=8
例3:(11-03-12)有以下程序,请在 【12】处填写正确语句,使程序可正常编译运行。
【12】;
main()
{ doublex,y,(*p)();
scanf("%lf%lf",&x,&y);
p=avg;
printf("%f\n",(*p)(x,y));
}
double avg(double a,double b)
{ return((a+b)/2);}
答案:double avg(double a,doubleb);或double avg(double ,double );
【解析】当函数定义在调用之后,调用前必须对函数进行申明,申明的形式和函数定义中的函数头部分相同,最后加分号即可。
6、知识点:函数的嵌套调用
l C语言中不允许作嵌套的函数定义,但是允许在一个函数的断定仪中出现对另一个函数的调用,即嵌套调用。
例1:(06-04-33)有以下程序
intfunl(double a){return a*=a;}
int fun2(double x,double y)
{double a=0,b=0;
a=funl(x);b=funl(y);return (int)(a+b);
}
main()
{double w;w=fun2(1.1,2.0);……}
程序执行后变量w中的值是( C )
A)5.2l B)5 C)5.0 D)0.0
【解析】此题考查函数的嵌套调用。main函数中调用了fun2函数;fun2函数中又调用了如fun1函数w=fun2(1.1,2.0)-->w=(int)(funl(1.1)+funl(2.0))àw=(int)5.21;w值为5,但是w是double类型变量,故将5转换成5.0赋值给变量w
例2、(09-3-24)有以下程序
#include
int f(int x,int y)
{return ((y-x)*x);}
main()
{ int a=3,b=4,c=5,d;
d=f(f(a,b),f(a,c));
printf(“%d\n”,d);
} 程序运行后的输出结果是( B )
A) 10 B)9 C)8 D)7
【解析】程序的main()函数中,定义了4个变量,前3个分别初始化,D用来接收调用函数后返回的值,主函数一共调用了3次f()函数,第一次传递a,b的值,给形参x,y,返回(y-x)*x的值为3,第二次将a,c的值传递给形参x,y,返回(y-x)*x的值为6,接着将f(a,b),f(a,c)的值3、6传递给形参,执行后返回值9,赋值变量d,最后输出结果为9
7、知识点:函数的递归调用
l 函数直接或间接地调用自己称为函数的递归调用。递归调用必须有一个明确的结束递归的条件。在做递归题时可把递归的步骤一步步写下来,不要弄颠倒了。
例1、(04-09-37)在函数调用过程中,如果函数funA调用了函数funB,函数funB又调用了函数funA,则 ( B )
A)称为函数的直接递归调用
B)称为函数的间接递归调用
C)称为函数的循环调用
D)C语言中不允许这样的递归调用
【解析】此题考查函数递归的基本概念。一个函数直接或间接调用自己称为函数的递归调用;若直接调用了自己,则称为直接递归调用,若间接调用了自己则称为间接递归调用;根据间接递归调用的概念可知,本题中的函数调用为间接递归调用。
例2、(09-09-15)
#include
fun(int x)
{ if(x/2>0) fun(x/2);
printf(“%d ”,x);
}
main()
{ fun(6); printf(“\n”);}程序运行后的输出结果是__1 3 6______
【解析】程序的执行过程是先递推、后递归的过程。当x=1时,条件不成立,递推终止。程序执行流程参照示意图。
例3:(10-03-33)有以下程序
#include
int f(int t[],intn);
main()
{ int a[4]={1,2,3,4},s;
s=f(a,4); printf(“%d\n”,s);
}
int f(int t[],int n)
{ if(n>0)return t=[n-1]+f(t,n-1);
elsereturn 0;
}程序运行后的输出结果是( B)
A) 4 B) 10 C)14 D)6
【解析】s=f(a,4)=t[3]+f(a,3)=4+f(a,3)=4+t[2]+f(a,2)=4+3+f(a,2)=7+t[1]+f(a,1)
=7+2+f(a,1)=9+t[0]+f(a,0)=9+1+f(a,0)=10+0=10
例4:(11-03-32)设有如下函数定义
int fun(int k)
{ if(k<1) return 0;
else if(k==1) return 1;
else return fun(k-1)+1;
}若执行调用语句:n=fun(3);,则函数fun总共被调用的次数是( B)
A)2 B)3 C)4 D)5
【解析】递归调用,fun(3)—> fun(2)—> fun(1) ;fun(1)—1—> fun(2)—2—> fun(3)—3—>n;所以fun总共被调用的次数是3,最后n为3。
例5:(11-03-34)有以下程序
int fun (int x,int y)
{ if(x!=y) return ((x+y)/2);
else return (x);
}
main()
{ inta=4,b=5,c=6;
printf("%d\n",fun(2*a,fun(b,c)));
}程序运行后的输出结果是( B)
A)3 B)6 C)8 D)12
【解析】函数递归调用,fun(8,fun(5,6)),其中fun(5,6)因为5!=6, return ((x+y)/2)为5,所以fun(8,fun(5,6))为fun(8,5),8!=5, return ((x+y)/2)为6
8、知识点:局部变量和全局变量
l 在一个函数内部或复合语句内部定义的变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在函数以外是不能使用这些变量的。这称为局部变量,局部变量又称为内部变量。函数的形参也属于局部变量。
l 在函数外部定义的变量,称为全局变量,又称为外部变量。全局变量可以被本文件的其他函数所共用。
例1、(07-09-40)在一个C语言源程序文件中所定义的全局变量,其作用域为(D)
A)所在文件的全部范围 B)所在程序的全部范围
C)所在函数的全部范围 D)由具体定义位置和extem说明来决定范围
【解析】本题考点是全局变量的作用域,全局变量的作用域是,从变量定义开始,一直到程序程结束为止,当然,也可以在其它文件中用这个以定义的全局变是,但是要通过extern来进行声明,本题答案选D。
例2、(09-09-11)有以下程序
#include
int a=5;
void fun(int b)
{ int a=10; a+=b;
printf(“%d”,a)
}
main()
{ int c=20;
fun(c); a+=c;
printf(“%d\n”,a);
}程序运行后的输出结果是____3025____
【解析】全局变量的作用域为定义开始到文件结束。局部变量的作用域为定义其函数内部。当局部变量与全部变量同名时,在局部变量作用域内,全部变量不起作用。
执行函数fun(c): 实参c 将值传给形参b,即b=20,函数内部定义局部变量a起作用,a=10,a+=b a=a+b=10+20=30,输出a的值为30
返回到主函数: a+=c 此时a为全局变量的值 a=a+c=5+20=25 输出a值25
注意格式控制符无空格,所以连续输出
9知识点:变量存储类别(auto变量、register变量、static变量)
Ø 静态变量(static):
(1)在编译时分配存储空间,所占存储单元直到程序结束时才释放,它的值在程序运行过程中一直存在,且变量的初始化只进行一次。
(2)static说明符可以用于全局变量,也可用于局部变量(auto和resgiter不可以定义全局变量)但是,当它说明变量后,只要这个变量还在程序中存在,那么不管用到还是没有用到,它都将会占用内存单元。
例1:(10-09-36)有以下程序:
#include
int f()
{ static int x=1;
x+=1; return x;
}
main()
{ int i,s=1;
for(i=1;i<=5;i++)s+=fun();
printf(“%d\n”,s);
} 程序运行后的输出结果是( B)
A)11 B)21 C)6 D)120
【解析】fun函数被调用了5次,每次调用后的值返回值累加到s上。
第一次:静态局部变量定义有效,x=2,返回值为2。s=s+fun()=1+2=3;从第2次调用开始,静态局部变量的定义相当于不存在,直接使用x的值。
第二次:x=3 s=3+3=6 第三次:x=4 s=6+4=10
第四次:x=5 s=10+5=15 第五次:x=6 s=15+6=21
例2:(11-03-34)有以下程序
int fun()
{ staticint x=1;
x*=2;
return x;
}
main()
{ inti,s=1;
for(i=1;i<=3;i++)s*=fun();
printf("%d\n",s);
}程序运行后的输出结果是(D)
A)0 B)10 C)30 D)64
【解析】静态变量static类型,在函数执行完后空间并不释放,而且只初始化一次。所以第一次调用后,x的值为2,返回后s的值为2,第二次调用后,x的值为2*2=4,返回后s的值为2*4=8,第三次调用后,x的值为4*2=8,返回后s的值为8*8=64,故选D。
Ø 自动变量(auto)
(1)自动变量的存储空间是当程序执行到定义它的函数或语句块时才分配,当函数执行结束后自动释放,变量的值也就不再存在。
(2)局部变量的存储类别默认为auto,可以省略不写,但它不能定义全局变量。
Ø 寄存器变量(register):
例1、(08-04-39)在C语言中,只有在使用时才占用内存单元的变量,其存储类型是( A )。
A)auto和register B)extern和register C)auto和static D)static和register
【解析】auto变量在进入函数体时,系统为其分配存储单元,退出时自动释放;register是建议编译程序将变量的值保存在cpu的寄存器中,而不是占用内存单元;extern可以对全局变量加以说明,扩展其作用域,在整个程序中都有效,所以会一直占用内存单元;static说明符可以用于全局变量,也可用于局部变量,使变量在整个程序执行期间一直占用内存单元,本题答案选A。
例2:(10-09-34)设函数中有整形变量n,为保证其在未赋初值的情况下初值为0,应该选择的存储类别是( C )
A)auto B)register C)static D)auto或register
【解析】对于静态局部变量(static),如在定义时不赋初值的话,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对于自动变量(auto或者缺省不写),如果不赋初值则它的值是一个不正确的值。
10、内部函数与外部函数
l 用static 进行说明的函数称为静态函数,也叫内部函数。静态函数只能被本编译单元体内的函数调用。一般形式:static 类型标识符函数名(形参表)例如:staticint fun(){…}
11、知识点:库函数
l 函数可以分为库函数和用户自定义函数。库函数由C系统提供,用户无须定义,在调用C语言标准库函数时要包含include命令,include命令行以#开头;
例1、(07-04-17)若有代数式 (其中e仅代表自然对数的底数,不是变量),则以下能够正确表示该代数式的C语言表达式是( C)
A)sqrt(abs(nx+ex)) B) sqrt(fbs(pow(n,x)+pow(x,e)))
C)sqrt(fabs(pow(n,x)+exp(x,e))) D)sqrt(fabs(pow(x,n)+exp(x)))
【解析】exp()函数的功能是返回以自然数e为底、函数参数x为幂的指数值ex ;pow(n,x)函数是计算nx ;fabs()函数的功能是返回函数参数的绝对值;sqrt()用于返回函数参数的平方根。所以正确答案为C。
例2:以下说法不正确的是(B)
A)标准库函数按分类在不同的头文件中声明
B)用户可以重新定义标准库函数
C)系统不允许用户重新定义标准库函数
D)用户若需要调用标准库函数,调用前必须使用预编译命令将该函数所在文件包括到用户源文件中
【解析】对每一类库函数,都有相应的头文件名,调用某个库函数时,用户在源程序中须用include命令包含其头文件名。每一类标准库函数是C语言本身提供的,用户不能重新定义标准库函数。
12、知识点:数组与函数
l 数组用作函数参数有两种形式:把数组元素(下标变量)作为实参使用和把数组名作为函数的形参和实参使用。
l 数组元素作函数的实参与普通变量并无区别,所进行的传递是值,形参变量和实参变量占据由编译系统分配的两个不同的内存单元;
l 数组名作为函数参数时,所进行的传递是地址(相当于把实参数组的首地址赋予形参数组名或指针名),形参数组与实参数组为同一数组,共同拥有一段内存单元;
例1:(2011-09-31)以下程序的主函数中调用了在其前面定义的fun函数
#include
main()
{double a[15],k;
k=fun(a);
}则以下选项中错误的fun函数首部是 ( D)
A.double fun(double a[15]) B.double fun(double *a)
C.double fun(double a[]) D.double fun(double a)
【解析】当一维数组名a作为实参时,对应形参有三种表示形式:*a、a[ ]、a[N]( 注:N为定义a数组时的元素个数)
例1:(11-03-11)己知a所指的数组中有N个元素。函数fun的功能是,将下标k(k>0)开始的后续元素全部向前移动一个位置。请填空。
Void fun(int a[N],int k)
{ inti;
for(i=k;i } 答案:i-1 【解析】a[i]的值赋给a[i-1] 例2:(10-09-32)有以下程序 #include #define N 8 void fun(int *x,int i) { *x=*(x+i); } main() { inta[N]={1,2,3,4,5,6,7,8},i; fun(a,2); for(i=0;i { printf(“%d”,a[i]);} printf(“\n”); }程序运行后的输出结果是( C ) A) 1 3 1 3 B)2 2 3 4 C) 3 2 3 4 D) 1 2 3 4 【解析】数组名代表数组首地址,即a[0]的地址。函数调用:fun(a,2) 参数传递后,形参指针x获得数组首地址,即指向a[0],形参变量i=2;*x即为a[0],*(x+2)即a[2],*x=*(x+2)相当于a[0]=a[2],a[0]变为3,a[2]不变。返回到主程序:循环4次,输出a数组前4个元素: 3 2 3 4 例3:(10-09-25)有以下程序 #include void fun(char *s) { while (*s) {if (*s%2==0) printf(“%c”,*s); s++;} } main() { char a[]={“good”}; fun(a);printf(“\n”); }注意:字母a的ASCII码值为97,程序运行后的输出结果是( A ) A) d B)go C)god D)good 【解析】调用fun(a)函数,实参字符数组名a传递给形参字符指针s,使s指向字符串“good”;在函数fun中对字符串进行遍历,如果指针s指向字符ASCII码值是偶数则输出该字符。在字符串“good”中,只有“d”的ASCII码值为偶数 13指针与函数 l 函数指针变量是指向函数的指针变量。 定义的一般形式为: 类型说明符(*指针变量名)(); 例如: int (*pf)(); 调用函数的一般形式:(*指针变量名)(实参表) 例如:z=(*p)(x,y); Ä注: (*指针变量名)中的“()”不能少 例1:(09-09-33)设有以下函数: void fun(int n,char *s){…} 则下面对函数指针的定义和赋值均正确的是( A ) A)void (*pf)(); pf=fun; B)void *pf(); pf=fun; C)void *pf(); *pf=fun; D)void (*pf)(int,char);pf=&fun; 【解析】本题考点为指向函数的指针的用法。函数名代表函数的入口地址,可以赋值给指向函数的指针。指向函数的指针应该定义为void (*pf)().如定义为void *pf(),则表示函数pf返回值为一个基类型为 void的指针。 l 函数指针变量不能进行算术运算。 l 指针型函数是指返回指针值的函数。定义的一般形式为: 类型说明符 *函数名(形参表){…} 例如:int *ap(int x,int y){} 例1:(10-09-11)有以下程序 #include int*f(int *p,int *q) main() { int m=1,n=2,*r=&m; r=f(r,&n) ; printf(”%d\n”,*r) ; } int *f(int *p,int *q) { return(*p>*q) ?p :q ;} 程序运行后的输出结果是______2_____ 【解析】本题中f是个指针型函数,返回值为指针值。如示意图。 主程序中,指针r指向m,函数调用f(r,&n)时,实参传递给形参,形参指针p指向m,指针q指向n,*p的值为m的值1,*q的值为n的值2,所以函数返回值为q,返回给主程序中的指针r,即指针r指向了n,最后输出*r的值为n的值2. 例2:(11-03-29)有以下程序 void fun(char *c) { while(*c) { if(*c>=’a’&&*c<=’z’)*c=*c-(‘a’-‘A’); c++; } } main() { chars[81]; gets(s); fun(s); puts(s): }当执行程序时从键盘上输入Hello Beijing<回车>,则程序的输出结果是( C ) A)hello beijing B)Hello Beijing C)HELLO BEIJING D)hELLO Beijing 【解析】gets(s)将输入的Hello Beijing赋给了字符数组s,调用fun(s),将字符数组s的首地址传给了c,c指向的即为字符数组的首地址,通过指针变量c取得字符数组中的字符判断是不是小写字母,如果是变成大写字母。*c=*c-(‘a’-‘A’)完成小写换大写的功能。故选C。另外注意gets(s)和scanf(“%s”,s);的区别:scanf以空格作为字符串输入结束的标志,而gets(s)不需要
第六课 结构体、链表与共用体
本课重要知识点:
1.知识点:用typedef定义类型
l 功能:为已有数据类型取别名
l 类型定义形式: typedef 旧类型名 新类型名;(例如:typedef double D ; )
注意:
(1) 定义的新名只是原名的一个别名,并不是建立一个新的数据类型;
(2) 用新名和原名定义的对象具有相同的性质和效果。
例1:(2010-09-39)若有以下语句
typedef struct S
{int g; charh;}T;
以下叙述中正确的是 ( B )
A)可用S定义结构体变量
B)可用T定义结构体变量
C)S是struct类型的变量
D)T是struct S类型的变量
【解析】此题中用typedef 说明的新类型名T,与中间部分的结构体类型具有相同的性质和效果
3. 知识点:结构体变量的定义
|
具体形式 |
实例 |
说明 |
形 式 1 |
struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. }; struct 结构体名 变量名表列; |
struct student { char num[20]; char name[20]; char sex; float score[4]; }; struct student stu1,stu2; |
特点:先定义类型,后定义变量 注意:定义变量时,必须以struct student 开头,缺一不可 |
形 式 2 |
struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. }变量名表列; |
struct student { char num[20]; char name[20]; char sex; float score[4]; } stu1,stu2; |
特点:定义类型的同时定义变量 注意:之后再定义同类型变量时,也必须必须以struct student 开头 |
形式3 |
struct { 类型标识符 成员名; 类型标识符 成员名; ……………. }变量名表列; |
struct { char num[20]; char name[20]; char sex; float score[4]; } stu1,stu2; |
特点:定义类型的同时定义变量 注意:此形式省略了结构体名,预示着后续程序中将不再定义该类型变量 |
形式4 |
typedef struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. } STU; STU 变量名表列; |
typedef struct student { char num[20]; char name[20]; char sex; float score[4]; } STU; STU stu1,stu2; |
特点:先定义类型,后定义变量 注意:用STU或struct student定义变量具有同等效果,用STU形式简洁方便 |
例1:(:2009-09-36)下面结构体的定义语句中,错误的是( B )
A)struct ord {int x;int y;int z;}; struct ord a;
B)struct ord {int x;int y;int z;} struct ord a;
C)struct ord {int x;int y;int z;} n;
D)struct {int x;int y;int z;} a;
【解析】遵循先定义类型,再定义该类型变量的原则,类型定义末尾的分号“;”必不可少
2.知识点: 结构体变量各成员的引用
l 引用结构体变量的成员的方法是:结构体变量名.成员名 (例如:stu1.sex)
l 结构体指针变量引用成员的方法是:
形式1:(*指针变量名).成员名 (例如:(*p).num)
形式2: 指针变量名->成员名 (例如:p->num)
l 运算符级别,注意:()和->和 . 同级别,均大于*
设有:
structstudent
{char num;
char name[20];
struct date {int year,mon,day} birth;
float score[4];
};
struct student *p,stu1;
p=&stu1;
成员类型 |
成员 |
操作方式 |
说明 |
普通变量 |
例如:引用成员变量num |
直接赋值:stu1.num=201101; 间接赋值:p->num=201101 输入:scanf(“%d”,& stu1.num); 输出:printf(“%d”,stu1.num); |
|
数组 |
例如:引用成员数组元素score[0] |
赋值:stu1.score[0]=75; 间接赋值:p-> score[0]=75; 输入:scanf(“%f”,& stu1. score[0]); 输出:printf(“%f”,stu1. score[0]); |
|
字符串 |
例如:字符数组成员作为字符串name |
赋值:strcpy(stu1.name,”zhangsan”); 间接赋值:strcpy(p->.name,”zhangsan”); 输入:scanf(“%s”, stu1.name); 输出:printf(“%s”,stu1.name); |
%s作为格式控制时,scanf和printf的输入和输出项均为地址 |
结构体嵌套 |
例如:引用内嵌结构体变量birth的成员year |
赋值:stu1.birth.year=1989; 间接赋值:p-> birth.year=1989; 输入:scanf(“%d”,& stu1. birth.year) 输出:printf(“%d”,stu1. birth.year) |
|
例1:(2009-9-12)设有定义
struct person
{ int ID;char name[12];} p;
请将scanf("%d", );语句补充完整,使其能够为结构体变量p的成员ID正确读入数据。
【解析】此题答案是 &p.ID ,即在成员ID前缀 p. 表示其从属于变量p,操作方式与普通变量和数组没什么不同,只需要在引用时前面标明属于哪个结构体变量。
例2:(2010-03-38)有以下定义和语句
struct workers
{ int num;
char name[20];
char c;
srruct
{int day;int month;int year;} s;
};
struct workers w,*pw;
pw=&w
能给w中year成员赋1980的语句是 ( D )
A)*pw.year=1980; B)w.year=1980;
C)pw->year=1980; D)w.s.year=1980;
【解析】引用w的内嵌结构体变量s的成员year,应逐级递进。具体方法参考前面表格。
例3:(2011-03-36)设有定义:struct {char mark[12];intnum1;double num2;} t1,t2;,若变量均已正确赋初值,则以下语句中错误的是(C)
A)t1=t2; B)t2.num1=t1.num1; C)t2.mark=t1.mark; D)t2.num2=t1.num2;
【解析】结构体以及结构体成员的赋值,需要类型一致,所有选项都满足,但是mark是结构体中的字符数组的数组名,其数组的首地址,是一个指针常量,只能在初始化的时候赋值,故C错误。
例4:(2011-03-37)有以下程序
struct ord
{ int x,y;}dt[2]={1,2,3,4};
main()
{
struct ord *p=dt;
printf("%d,",++(p->x));printf("%d\n",++(p->y));
}程序运行后的输出结果是(D)
A)1,2 B)4,1 C)3,4 D)2,3
【解析】dt是一个结构体类型的数组,其有两个结构体元素,p是结构体类型指针,其指向dt即指向结构体数组的首地址,p->x和p->y分别是结构体数组第一个元素的x成员和y成员的值,++在前则是先自增1再参与运算,所以输出的是1+1=2,和2+1=3,故选D。
例5:(2011-03-38)有以下程序
struct S
{ int a,b;}data[2]={10,100,20,200};
main()
{ structS p=data[1];
printf("%d\n",++(p.a));
}程序运行后的输出结果是(D)
A)10 B)11 C)20 D)21
【解析】结构体变量p赋值为结构体数组第二个元素的值,即p.a=20,p.b=200;所以输出++(p.a)为21,故选D。
3.知识点: 结构体变量与函数调用
l 将一个结构体变量的值传递给另一个函数,有3个方法:
(1)用结构体变量的成员作参数。例如,用stu[1].num作实参,将值传递给形参。用法和用普通变量作实参是一样的,属于“单向值传递”方式。应当注意实参与形参的类型应保持一致。
(2)用结构体变量作实参。 对应形参也是同类型结构体变量,也属于“单向值传递”方式。
(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组元素)的地址传给形参。属于“地址传递”方式,应注意在被调用函数中是否对该地址的值有影响。
例1:(2009-09-14)有以下程序运行后的输出结果是 16
typedef struct
{ int num;double s;} REC;
void fun1(REC x)
{ x.num=23;x.s=88.5; }
main()
{ REC a={16,90.0};
fun1(a);
printf("%d\n",a.num);
}
【解析】main函数中的fun1(a); 是将a的值单向传递给了形参x,相当于赋值给了x,因此x的值的变化不会影响到a
例2:(2009-09-38)有以下程序
struct A
{ int a;char b[10];double c;};
struct A f(struct A t);
main()
{ struct A a={1001,"ZhangDa",1098.0};
a=f(a); printf("%d,%s,%6.1f\n",a.a,a.b,a.c);
}
struct A f(struct A t)
{ t.a=1002;strcpy(t.b,"ChangRong");t.c=1202.0;return t;}
程序运行后的输出结果是 ( D )
A)1001,ZhangDa,1098.0
B)1002,ZhangDa,1202.0
C)1001,ChangRong,1098.0
D)1002,ChangRong,1202.0
【解析】注意在f函数中的t.a=1002;strcpy(t.b,"ChangRong");t.c=1202.0; 这三条语句。
4.知识点:链表
l 当一个结构体中有一个或多个成员的基类型就是本结构体类型时,通常把这种结构体称为可以“引用自身的结构体”,也称为“链表结构”
例如:
struct link
{ char ch;
Struct link *p;
}a;
在此,p是一个可以指向struct link类型变量的指针成员,因此,a.p=&a是合法的表达式,由此构成的存储结构如图所示。
l 对链表进行的操作通常有以下四种:
1.建立带有头结点的单向链表
2.顺序访问单向链表各结点数据域的值(即遍历链表)
struct std
{
int data; /*数据域*/
struct std * next; /*指针域*/
};
…建立头结点和数个节点,即建立以下链表
遍历链表:
p=head;
while(p!=0)
{
printf("%4d",p->data);
p=p->next;
}
}
3.删除单向链表中的某个结点
删除q指向的节点:
p->next=q->next;或者p->next=r;
free(p);
4.向单向链表中插入结点
将r指向的节点插入p、q所指的两个结点之间:
r->next=q; 或者r->next=p->next;
p->next=r;
例1:(2011-09-37)在以下程序
#include
main()
{struct node{int n;struct node *next;}*p;
struct node x[3]={{2,x+1},{4,x+2},{6,NULL}};
p=x;
printf(“%d,”,p->n);
printf(“%d\n”,p->next->n);
}程序运行后的输出结果是 (B)
A.2,3 B.2,4 C.3,4 D.4,6
【解析】通过赋值语句p=x,即p=&x[0],使p指向了x[0],因此p->n等价于x[0].n,输出2;p->next等价于x[0].next,即x+1或表示为&x[1],p->next->n也可表示为x[1].n,输出4
例1:(2009-03-15)以下程序把三个NODETYPE型的变量链接成一个简单的链表,并在while循环中输出链表结点数据域中的数据,请填空
#include
struct node
{int data; struct node *next;};
typedef struct node NODETYPE;
main( )
{NODETYPE a,b,c,*h,*p;
a.data=10;b.data=20;c.data=30;h=&a;
b.next=&b;b.next=&c;c.next=’\0’;
p=h;
while(p){printf(“%d”,p->data); p=p->next ;}
}
【解析】while就是用来遍历链表的,为了能遍历每个结点,每执行一次循环,就要使变量p指向下一个结点,所以空白处应填p=p->next
5.知识点:共用体类型定义
l 共用体是一种构造数据类型(遵循先定义类型,再定义该类型变量的原则)
l 用途:使几个不同类型的变量共占一段内存(相互覆盖)
l 与结构体结构体与共用体
1.区别: 存储方式不同,
结构体变量占用的内存单元,是其所有成员占内存单元的总和,而共用体变量是其所有成员中占用空间最大的成员的内存单元
2.联系: 类型定义、变量定义、成员引用等操作方式相同,两种类型可相互嵌套
例1.(06-04—41)有以下程序
main()
{union
{char ch [2];
int d;
}s;
s.d=0x4321;
printf(“%x,%x\n”,s.ch[0],s.ch[1]);
} 在16位编译系统上,程序执行后的输出结果是___ A __
A)21,43 B)43,21 C)43,00 D)21,00
【解析】此题考查整形数据在内存中存放形式以及共用体内存分配。对于共用体而言,字符数组ch与整型变量d共用2个字节的存储空问;存储器存储数据原则是:低地址存放低字节,高地址存放高字节;于是0x4321中2l存放在低字节中,43存放在高字节中,故输出时s.ch[0]输出21,s.ch[1]输出43。
第七课 编译预处理、文件
本课重要知识点:
1.知识点:main()函数的参数
l 定义形式:main(int argc,char *argv[])
{…
}
l int argc是命令行中的字符串数,char *argv[]是指向字符串的指针数组,系统使用空格把各个字符串隔开。
2.知识点:不带参数的宏定义
l 一般形式:#define 宏名 字符串(或数值)
即用字符串或数值取代宏名。
l 宏名一般采用大写字母表示,以与变量名区别,也可用小写字母。
l 宏定义不是C语句,不必在行末加分号。
例1:(2009-04-36)有以下程序
#include
#define PT 3.5;
#define S(x) PT*x*x;
main()
{int a=l,b=2;printf("%4.1f\n",S(a+b));}
程序运行后输出的结果是(D)
A)14.0 B)31.5 C)7.5 D)程序有错无输出结果
【解析】此题考查宏的定义形式。由于宏定义并不是语句,故#define后面不能有分号,故该程序有错无法输出结果,所以,正确答案:D。
例2:(2011-03-30)以下函数的功能是:通过键盘输入数据,为数组中的所有元素赋值。
#define N 10
void fun(int x[N])
{ inti=0;
while(i }在程序中下划线处应填入的是 A)x+i B)&x[i+1] C)x+(i++) D)&x[++i] 答案:C 【解析】要求给每个元素赋值,while循环的变量i必须不断增加,所以A、B显然不行,i++是先参与运算在自增1,++i是先自增1再参与运算,所以D会出现x[0]未赋值的情况,故选C。 l 对程序中用“”括起来的字符串内的字符,即使与宏名相同,也不进行置换。 l 宏定义可以嵌套使用,例如: #define R 3.0 #define PI 3.14159 #define L L*PI*R 3.知识点:带参数的宏定义 l 一般形式:#define 宏名(参数表) 字符串 l 带参数的宏不占运行时间,只占编译时间;只是简单、机械字符替换;宏名无类型。 l 要注意有括号和没括号的区别 例1:(2009-09-35)有以下程序 #include #define f(x) x*x*x main() {int a=3,s,t; s=f(a+1); t=f((a+1)); printf(“%d,%d\n”,s,t); }程序运行后的输出结果是(A) A)10,64 B)10,10 C)64,10 D)64,64 【解析】本题考点为带参数的宏定义,宏定义中的参数没有类型,仅为字符序列,不能当作表达式运算。宏展开时,把实参字符串原样写在替换文本中。s=f(a+1)=a+1*a1*a+1=10;t=f((a+1))= (a+1)* (a+1)* (a+1)=64 例2:(2011-03-35)有以下程序 #define S(x) 4*(x)*x+1 main() { intk=5,j=2; printf("%d\n",S(k+j)); }程序运行后的输出结果是(B) A)197 B)143 C)33 D)28 【解析】#define宏定义,只是机械简单的置换S(k+j)=S(5+2)=4*(5+2)*5+2+1=143 4.知识点:文件包含 l 一般形式:#include <文件名>或者#include “文件名” l < >与” ”的区别:<>即系统到存放C库函数头文件的目录中寻找要包含的文件;” ”即系统先在用户当前目录中寻找,若找不到,再到存放C库函数头文件的目录中寻找。 l 文件包含可以嵌套。 l 凡是以“#”开头的行都是预处理命令行。 5.知识点:calloc()函数 l 函数原型:void *calloc(unsigned n,unsigned size); l 功能:分配n个数据项的内存连续空间,每个数据项的大小为size 6.知识点:free()函数 l 函数原型:void free(void *p); l 功能:释放p所指的内存区 7.知识点:malloc()函数 l 函数原型:void *malloc(unsigned size); l 功能:分配size字节的存储区 例1:(2011-03-14)以下程序运行后的输出结果是 emoclew 。 main() { char *p; int i; p=(char *)malloc(sizeof(char)*20); strcpy(p,"welcome"); for(i=6;i>=0;i--) putchar(*(p+i)); printf("\n"); free(p); } 【解析】(char*)malloc(sizeof(char)*20)申请一个20个字符大小的空间,首地址赋给字符指针变量p,strcpy(p,"welcome");将字符串"welcome"赋值给p所指向的空间,for循环实现从后往前输出这个字符串,free(p)为释放申请的空间。 8.知识点:文件的概念和文件指针 l 在C程序中文件可以用顺序方式存取,可以用随机方式存取。 l C程序把文件分为ASCII文件(文本文件)和二进制文件。 例1:(2009-09-40)下列关于C语言文件的叙述中正确的是(C) A)文件由一系列数据依次排列组成,只能构成二进制文件 B)文件由结构序列组成,可以构成二进制文件或文本文件 C)文件由数据序列组成,可以构成二进制文件或文本文件 D)文件由字符序列组成,其类型只能是文本文件 【解析】本题考点为文件的基本概念。正确答案为C。C语言中根据数据的组织形式,分为二进制文件和ASCII码文件。一个C文件时一个字节序列或者二进制序列,而不是一个记录(结构)序列。 l 文件类型指针:FILE *fp;fp是一个指向FILE类型结构体的指针变量,通过文件指针变量找到与它相关的文件。 例2:(2010-09-15)以下程序打开新文件f.txt,并调用字符输出函数将a数组中的字符写入其中,请填空。 #include main() { FILE *fp; char a[5]={‘1’,’2’,’3’,’4’,’5’},i; fp=fopen(“f.txt”,”w”); for(i=0;i<5;i++)fputc(a[i],fp); fclose(fp); } 9.知识点:fopen()函数和fclose()函数 (1)fopen函数 l 调用方式:fp=fopen(“file1”,”r”); l 使用文件方式:如”r”只读打开一个文本文;”w”只写打开或建立一个文本文件;”a”追加打开一个文本文件,在文件末尾添加数据。 例1:(2011-03-40)设fp已定义,执行语句fp=fopen("file","w");后,以下针对文本文件file操作叙述的选项中正确的是(B) A)写操作结束后可以从头开始读 B)只能写不能读 C)可以在原有内容后追加写 D)可以随意读和写 【解析】文件打开方式,‘w’只能向该文件写入,如打开的文件不存在则以指定的文件名建立文件,如存在,则先删除再重建一个文件。故选B。 l 若不能实现打开任务,fopen函数将带回一个空指针值NULL。 例1:(2009-04-13)以下程序用来判断指定文件是否能正常打开,请填空。 #include main() {FILE *fp; if(((fp=fopen(“test.txt”,”r”))== NULL )) printf(“未能打开文件!\n); else printf(“文件打开成功!\n”); } 【解析】考查文件打开操作。打开文件使用fopen函数,正常打开时返回指向该文件的文件指针,否则返回值为NULL;题目中当if条件表达式成立时,输出“未能打开文件!”,故fopen函数返回值为NULL。正确答案:NULL。 (2)fclose()函数 l 调用方式:fclose(fp); l 顺利完成关闭操作,返回值为0,否则返回EOF(-1)。 10.知识点:fputc()函数和fgetc()函数 l fgetc()函数的调用形式:ch=fgetc(fp);从打开的文件fp中读取一个字符。 l fputc()函数的调用形式:fputc(ch,fp);将字符输出到fp所指向的文件中去。 11.知识点:fread()函数和fwrite()函数 l fread()函数的调用形式:fread(buffer,size,count,fp);其中buffer是一个指针,size是每个数据块的字节数,count是每次读入数据块的个数,fp是文件指针。 例1:structstud {char name[10]; int num; }stu[40]; 假设学生的数据已存放在磁盘文件中,如何读入40个学生的数据? for(i=0;i<40;i++) fread( &stu[i] , sizeof(struct stur) ,1,fp); l fwrite()函数的调用形式:fread(buffer,size,count,fp);其中buffer是输出数据的首地址。 12.知识点:fscanf()函数和fprintf()函数 l fscanf(文件指针,格式控制字符串,输入列表); l fprintf(文件指针,格式控制字符串,输出列表); 例1:(2011-09-40)有以下程序 #include main() {FILE *fp; int k,n,i,a[6]={1,2,3,4,5,6}; fp=fopen(“d2.dat”,”w”); for(i=0;i<6;i++)fprintf(fp,”%d\n”,a[i]); fclose(fp); fp=fopen(“d2.dat”,”r”); for(i=0;i<3;i++) fscanf(fp,”%d%d”,&k,&n); fclose(fp); printf(“%d,%d\n”,k,n); }程序运行后的输出结果是 (C) A.1,2 B.3,4 C.5,6 D.123,456 【解析】第一次fp=fopen(“d2.dat”,”w”);以写方式打开,通过循环将a数组全部写入文件中,并且每行写一个;第二次fp=fopen(“d2.dat”,”r”); 以写方式打开,然后通过循环每次读取两个数字给k和n,第三次k和n分别得到5和6 例1:(2009-04-40)有以下程序 #include main() {FILE *f; f=fopen(“filea.txt”,”w”); fprintf(f,”abc”); fclose(f); }若文本文件filea.txt中原有内容为:hello,则运行以上程序后,文件filea.txt的内容为(C) A)helloabc B)abclo C)abc D)abchello 【解析】程序中定义了一个文件指针,然后用fopen()函数,以写的方式打开文件“filea.txt”,并让指针f指向它,执着调用fprintf()函数,将“abc”写到指针所指向的文件中。由于filea.txt里原来的内容”hello”被”abc”覆盖掉,所以文件“filea.txt”里,最后的内容为”abc”,本题答案选C。 13.知识点:fgets()函数和fputs()函数 l fgets(str,n,fp);从fp指向的文件输入n-1个字符,在最后加一个’\0’,得到字符串共有n个字符,把它们放到字符数组str中。 l fputs(“China”,fp);把字符串”China”输出到fp指向的文件,字符串末尾’\0’不输出。 (2010-03-40)有以下程序 #include main() {FILE *fp;char str[10]; fp=fopen(“myfile.dat”,”w”); fputs(“abc”,fp);fclose(fp); fp=fopen(“myfile,data”,”a+”); fprintf(fp,”%d”,28); rewind(fp); fscanf(fp,”%s”,str);puts(str); fclose(fp); }程序运行后的输出结果是(C) A)abc B)28c C)abc28 D)因类型不一致而出错 【解析】以“a+”方式打开一个已存在的文件,原有文件内容不被删除,位置指针移到文件末尾,可作添加和读操作。fputs(“abc”,fp);把字符串”abc”输出到fp指向的文件。 14.知识点:rewind()函数 l 调用形式:rewind(fp); l 功能:使位置指针重新返回文件的开头。 15.知识点:fseek()函数 l 功能:改变文件的位置指针 l 调用形式:fseek(fp,100L,0);将位置指针移到离文件头100个字节处。 l 文件首 SEEK_SET 0 文件当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2 16.知识点:ftell()函数 l ftell(fp); l 功能:得到流式文件中的当前位置。 17.知识点:feof()函数 l feof(fp); l 判断文件是否结束,结束,返回值为1,否则为0。 例1(2011-03-15)以下程序运行后的输出结果是 【15】 。 main() { FILE *fp; int x[6]={1,2,3,4,5,6},i; fp=fopen("test.dat","wb"); fwrite(x,sizeof(int),3,fp); rewind(fp); fread(x,sizeof(int),3,fp); for(i=0;i<6;i++)printf("%d",x[i]); printf("\n"); fclose(fp); } 答案:123456 【解析】fwrite(x,sizeof(int),3,fp);将数组内的前三个元素即1,2,3输出到文件中去,rewind(fp);文件回到开头,fread(x,sizeof(int),3,fp);将文件的内容读出并存到x数组的前三个元素中,把1,2,3写到数组的前三个元素中去,所有数组中的元素值均没变。