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