全国计算机二级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]