全国计算机二级C语言常考题型专题讲座字符串长度的计算方法提示:(1)计算字符串长度时关键是要注意辨认转义字符;(2)一个转义字符总是以反斜杠开始,再加一个其他字符组成。所以,遇到反斜杠时要特别注意!!!
1、不带转义字符的字符串
如:“abc!x=/”,其长度为 7
2、带转义字符的字符串
(1) 字符串“abc\n”:其中的'\n'为转义字符(换行符),计算字符串长度时只能计作一个字符,所以该字符串的长度为4(而不是5)
(2) 字符串“abc\n\\\'\"":其中有4个转义字符:'\n'(换行符)、'\\'(反斜杠)、'\''(单引号)、'\"'(双引号),所以该字符串的长度为7(而不是11)。
(3) 字符串“abc\0xyz”:其中有一个转义字符'\0',它是字符串结束符,所以,当用函数strlen来测试该字符串的长度时,结果应该为3(而不是7)。
(4) 字符串“abc\\0xy”:其中有一个转义字符'\\'(反斜杠),这样,后面的字符串“0xy”照样计算,所以,该字符串的长度为7(而不是将第二个反斜杠与其后的0结合为一个转义字符'\0',若那样的话,第一个反斜杠将无法处理,因为一个转义字符总是由反斜杠加其他字符组成的,单独的一个反斜杠不能作为任何合法的字符)。
(5) 若将字符串“abc\\0xy”改为“abc\\\0xy”:则其中有二个转义字符'\\'(反斜杠)和'\0'(字符串结束符),这时,当用函数strlen来测试该字符串的长度时,结果应该为4(而不是7)。
(6) 若将字符串“abc\\\0xy”改为“abc\\\061xy”:则其中有二个转义字符'\\'(反斜杠)和'\061'(ASCII码值等于061的字符,也即数字字符'1'),这时,当用函数strlen来测试该字符串的长度时,结果应该为7(而不是4或9)。所以,当遇到转义字符'\0'时,还要看其后面是否还有数字,若有,则应将后面的数字(一至二位)与前面的'\0'相结合作为一个字符计入整个字符串的长度。
若用printf(“abc\\\061xy”);输出,则输出结果为:abc\1xy
例题一:请选出以下语句的输出结果( )
printf("%d\n",strlen("\t\"\065\xff\n"));
(A) 5 (B) 14 (C) 8 (D) 输出项不合法,无正常输出正确答案是(A):字符串中包含的5个字符是:'\t'(跳格符)、'\"'(双引号)、'\065'(ASCII值为八进制065,也即十进制为51的字符)、'\xff'(ASCII值为十六进制ff,也即十进制为255的字符)、'\n'(换行符)。
例题二:若有以下程序段:
char str[]="ab\n\012\\\"";
printf("%d",strlen(str));
上面程序段的输出结果是
A) 3 B) 4 C) 6  D) 12
正确答案是(C):字符串中包含的6个字符是:'a'、'b'、'\n'、'\012'、'\\'和'\"'。
整数除法的注意事项整数除法的要领:
(1)两个整数相除的结果也应该是一个整数。
(2)若两个整数相除不能除尽,则最后结果应该进行“取整”转换(注意不是“四舍五入”)。
例题一:
int x;
x=3/2;
则x的值是1,而不是2,更不是1.5
例题二:
float x;
x=3/2;
虽然变量x是float型,但x的值并不为1.5,而应该为1.0。x=3/2的运算过程如下:
(1)由于运算符“/”的优先级高于运算符“=”,所以先计算3/2,又由于3和2都为整数,所以3/2的结果也应该是整数1。
(2)再进行赋值(“=”)运算:进行赋值前,先将1转换为1.0,然后再赋值给变量x。所以x的值是1.0。
例题三:若已定义x和y为double类型,则表达式:x=1,y=x+3/2的值是(  )。
(A) 1 (B) 2  (C) 2.0 (D) 2.5
答案应该(C).
逗号表达式逗号表达式的形式如下:
表达式1,表达式2,表达式3,......,表达式n
逗号表达式的要领:
(1) 逗号表达式的运算过程为:从左往右逐个计算表达式。
(2) 逗号表达式作为一个整体,它的值为最后一个表达式(也即表达式n)的值。
(3) 逗号运算符的优先级别在所有运算符中最低。
例题1:若已定义x和y为double类型,则表达式:x=1,y=x+3/2的值是
 A) 1  B) 2 C) 2.0 D) 2.5
分析:该表达式是一个逗号表达式,所以先运算x=1,结果变量x中的值为1.0,然后运算y=x+3/2,其结果是变量y中的值为2.0(这个运算过程可参阅本专题的“整数除法的注意事项”),注意此时表达式y=x+3/2的值即等于变量y的值为2.0。最后,整个逗号表达式的值应该等于最后一个表达式的值2.0,所以,正确答案是C)。
注:该题曾在1998年4月和2000年9月的二级C考试中两次出现过。
例题2:若t为double类型,表达式t=1,t+5,t++的值是
 A) 1 B) 6.0 C) 2.0 D) 1.0
分析:该题的表达式也是一逗号表达式,运算过程同例题1。需要注意的是,其中的第二个表达式(t+5)对整个表达式的运算结果不产生任何影响,因为它没有改变变量x的值(x的值仍为1.0),最后一个表达式(t++)的值为变量x进行自增运算前的值1.0,所以整个表达式的值也为1.0。
注:这是1998年4月二级C考试中的一道选择题。
例题3:有如下函数调用语句
 func(rec1,rec2+rec3,(rec4,rec5));
 该函数调用语句中,含有的实参个数是
A)3  B)4 C)5 D)有语法错误
分析:C语言规定,函数调用时实参与实参之间是用逗号隔开的,所以,本题的函数调用语句中包含3个实参,其中第一个实参是rec1,第二个实参是rec2+rec3,第三个实参是(rec4,rec5),这里的第三个实参就是一个逗号表达式,根据逗号表达式的运算规则,第三个实参的值应该等于rec5的值。
注:这是2000年9月二级C考试中的一道选择题。
例题4:有如下函数调用语句
 fun(a+b,(x,y),fun(n+k,d,(a,b)));
 在此函数调用语句中实参的个数是
A)3  B)4 C)5 D)6
正确答案应该是A)。
注:这是1997年9月二级C考试中的一道选择题。
指针与一维数组指针与一维数组是二级C必考题型,有时一次考试中会出现2到3题相关的题目,因此,掌握这一题型的解答技巧是十分重要的。
知识要领:
一般情况下,总是先定义一个一维数组和一个指针变量,如:
int a[]={1,2,3,4,5},*p;
然后将数组a的首地址赋值给指针变量p,是指针p指向数组a的首地址:
p=a;
这样,就完成了数组与指针之间指向关系的建立。这是该类题目在提出问题前必须做的一件事,也是考生解答问题的前提条件。
注意:数组a的首地址有两种表示方法,一是直接用数组名a表示,另一种是用数组的第一个元素a[0]的地址&a[0]表示,这两种表示法是完全等价的,因此,上述表达式 p=a 也可写成 p=&a[0]。
通过语句 p=a;在数组与指针之间建立了指向关系之后,则必须明白以下两组等价关系第一组等价关系:以下4种表示法是等价的,它们均表示下标为i的数组元素a[i](本例子中,i的取值范围为0到4):
 a[i], p[i], *(a+i), *(p+i)
第二组等价关系:以下4种表示法也是等价的,它们均表示下标为i的数组元素a[i]的地址值:
 &a[i], &p[i], a+i, p+i
可以发现,数组名a和指针p在使用时是可以相互替代的,也即凡使用a的地方均可以p替代,反之也然。(前提条件是首先有 p=a;语句。)
注意:a是一常量,它的值不可改变,而p是变量,它的值是可以改变的,这是它们之间的唯一区别。
明白以上等价关系后,即可以解答大部分此类题目了。
例题一:若有以下定义和语句,则通过指针p引用值为38的数组元素的表达式是
int w[10]={23,54,10,33,47,98,72,80,61},*p;
p=w;
分析:这是1998年4月的一道填空题。根据前面讲的等价关系,值为38的数组元素可用4种方法表示:w[5],p[5],*(w+5)和*(p+5),其中p[5]和*(p+5)符合题目中关于“通过指针p引用”的要求,因此,该题可以有这两种填法。
例题二:若有以下定义和语句:
int a[10]={1,2,3,4,5,6,7,8,9,10},*p=a;
则不能表示a数组元素的表达式是
A) *p B) a[10]  C) *a  D)a[p-a]
分析:这是1998年4月的一道选择题。选项A)和C)可以该写为:*(p+0)和*(a+0),所以它们均表示数组元素a[0]。选项D)的下标为p-a,由于p和a均指向数组的首地址,它们的地址值是相同的,所以p-a的值为0,所以a[p-a]也表示a[0]。选项B)的下标10超出了数组所规定的上限9,所以,a[10]不能表示a数组的一个元素。
例题三:若有以下定义和语句,则使指针p指向值为36的数组元素的表达式是
int a[10]={19,23,44,17,37,28,49,36},*p;
p=a;
分析:这是1997年9月的一道填空题,与例题一完全类似。正确答案是*(p+7)。
例题四:若有说明:double *p,a;则能通过scanf语句正确给输入项读入数据的程序段是
A) *p=&a;scanf("%lf",p);
B) p=(double *)malloc(8);scanf("%f",p);
C) p=&a;scanf("%lf",a);
D) p=&a;scanf("%le",p);
分析:这是1997年9月的一道选择题。它是关于指针与单个变量之间关系的题目。
(1)要使指针p指向变量a,则必须用语句p=&a;这样以后,也有两个等价关系:
 *p等价于a;p等价于&a。
前者是关于变量a的数值的等价关系,后者是关于变量a的地址值的等价关系。
(2)选项A)中的语句*p=&a;显然是错误的。选项B)在程序运行到scanf语句时将出错。选项C)的scanf语句中的a前面少了一个取地址符&。选项D)相当于scanf("%le",&a);因此是正确的。
例题五:若有以下定义:
int a[10]={1,2,3,4,5,6,7,8,9,10},*p=a;
则值为3的表达式是
A) p+=2,*(p++) B) p+=2,*++p
C) p+=3,*p++  D)p+=2,++*p
分析:这是1998年4月的一道选择题,它还涉及到指针的移动以及运算符++和*之间的优先级问题。
(1)首先确定,值为3的数组元素是a[2],因此也可用p[2],*(a+2)和*(p+2)表示。
(2)题目的4个选项中没有现成答案,所以再考虑其它途径。注意4个表达式均为逗号表达式,它们的值应该分别等于各自最后一个表达式的值(关于逗号表达式,可参阅本站“逗号表达式”专题)。
(3)再看表达式p+=2的作用。在进行这一运算之前,指针p指向数组元素a[0],表达式p+=2使指针p向后移动了2个存储单元,也即,运算后指针p指向了数组元素a[2],同样,经过p+=3运算后,指针p将指向数组元素a[3]。
(4)现在看选项A),先经p+=2运算,使p指向a[2],然后通过指针运算符*引用表达式p++所指向的元素,我们知道,表达式p++的值就是p的值,所以*(p++)的值就等于*p的值,也即a[2]的值3,它正符合题目要求,因此,A)是正确答案。
B)表达式的值应该为4(先使p指向a[3],后通过p取值),C)表达式的值应该为4(先使p指向a[3],再通过p取值),D)表达式的值也为4(先使p指向a[2],再通过p取值,最后自增1)。
表达式运算问题之双目运算
1,双目运算概念
双目运算由双目运算符和参与运算的运算量构成。所谓双目运算符是指该运算符的左右两侧都必须有运算量。
常见的双目运算符有:+、-、*、/、%等。诸如x+y、x/y、x*y等运算均为双目运算。
2,双目运算的要点
遇到双目运算,主要注意数据类型问题。具体有以下几点:
(1) C语言要求:参与双目运算的两个运算量的类型必须一致;
(2) 双目运算的结果的类型必须与运算量的类型一致;
(3) 如果参与双目运算的两个运算量类型不一致,系统将自动把其中的一个进行类型转换,使两个运算量的类型一致后再进行运算。 自动转换的规则是:按“向高看齐”的原则进行转换。在几个基本的数据类型中,由高到低的排列顺序为:double,int,char。
比较:赋值运算中的类型转换
在赋值运算中,若遇到赋值号两侧的数据类型不一致,则也存在自动类型转换的问题,不过,它的转换规则与双目运算符的转换规则有所不同,它是按“向左看齐”的原则进行转换的,也即,是将赋值号右侧的量先转换为左侧的类型,然后再进行赋值。如有 int x; x=1.9; 则先将1.9转换为int型,变为1后再赋值给x。再如,double y; y=2; 则先将2转换为2.0,然后再赋值给y,结果y的值为2.0。
举例说明:
(1) 表达式 3+2 中,3和2类型一致(都是整型),符合双目运算的类型一致要求,所以直接运算,结果为5,也是整型。
(2) 表达式 3/2 中,3和2类型一致(都是整型),符合双目运算的类型一致要求,所以直接运算,但要注意,由于两个运算量都是整型,所以运算结果也必须是整型,3除以2的整数部分为1,所以3/2的结果是1,而不是2,更不是1.5,这是整数除法中特别要注意的地方。
又如19/5的整数部分是3,尽管其小数部分为0.8(超过了0.5),但19/5的结果仍然应该等于其整数部分的值3,而不能进行四舍五入变为4。
(3) 表达式 1.0+3 中,量个运算量的类型不一致,所以不能直接进行加法运算,必须先将整数3转换为double型常量3.0(注意,C中实数常量均为double型,而不是float型!),使表达式变为 1.0+3.0,然后才能进行加法运算,运算结果为4.0(不能写成整型4)。
又如,表达式 1.0+3/2 中,由于/运算符的优先级比+高,所以先运算3/2,刚才已经讲过,3/2的值应该为1,于是整个表达式变为 1.0+1(注意不要因为前面有一个1.0而把3/2的结果当作为1.5!),然后再将1作类型转换,变为1.0,最后再运算1.0+1.0,结果为2.0。
上述例子中的运算量均为常量,遇到变量时运算方法是一样的!
3,双目运算实例这是2000年4月二级C考试中的一道选择题:
下列程序的输出结果是
A) 3 B) 3.2 C) 0 D) 3.07
main()
{ double d=3.2; int x,y;
 x=1.2; y=(x+3.8)/5.0;
 printf("%d \n",d*y);
}  
本题中,程序先执行语句 x=1.2;,根据赋值运算的类型转换规则,先将double型的常量1.2转换为int型,即取整为1,然后将1赋值给变量x。接下来执行语句y=(x+3.8)/5.0;根据运算符的优先级,先计算小括号内,再计算除法,最后执行赋值运算。小括号内的运算过程:先将整型变量x的值1转换为double型1.0,然后与3.8进行加法运算,得到中间结果4.8。接着进行除法运算4.8/5.0,其结果小于1.0,这里没有必要计算出精确值,因为接着进行赋值运算,赋值号左边的变量y的类型为整型,于是对这个小于1.0的中间结果进行取整,结果为0,于是变量y的值为0。因此该题的输出结果应该是0。