计算机二级【C语言】-复习使用

            文章目录

第一章 C语言概述

1.1 C语言基础知识(1-23题)

  1. 任何算法都能转换成计算机高级语言的程序,并在有限时间内运行完毕。(✘)
    【解析】算法转化为机器语言。

  2. C语言语句必须以分号;结束。(✔)

  3. 用于任何一种计算机高级语言都可以把算法转换为程序。(✔)

  4. 计算机可以直接执行由任意高级语言编写的程序。(✘)
    【解析】计算机只能识别机器语言,不能直接识别由高级语言编写的程序。

  5. 每个后缀为.C的C语言源程序都可以单独进行编译。(✔)

  6. 流程图是描述算法很好的工具,基本图形的功能如图所示:
    请添加图片描述

  7. 文字叙述、程序语句、伪代码和流程图、E-R图都能用于描述算法。(✘)
    【解析】E-R是实体联系模型,不能用于描述算法。

  8. 只要程序包含了三种基本结构中的任意一种,就是结构化程序。(✘)
    【解析】结构化程序设计是以模块化设计为中心,将待开发的软件系统划分为若干个相互独立的模块,在设计其中一个模块时,不会受到其它模块的牵连,因而可将原来较为复杂的问题化简为一系列简单模块的设计,而不是说包含了三种基本结构就是结构化程序。

  9. C编译程序把文件后缀为.c的源程序文件编译成文件后缀为.obj的二进制文件。(✔)

  10. 链接将一个或多个目标文件与程序用到的库文件连接起来,形成一个可以在操作系统直接运行的执行程序.exe.(✔)

  11. 程序模块化可以提高程序运行的效率。(✘)
    【解析】模块化程序的优点:(1)易于维护和复用,可以提高程序编制的效率;(2)易于分工合作;(3)易于模块化调试测试。
    模块化程序的副作用:(1)可能会降低程序运行效率;(2)设计的前期工作需要多花费时间。

  12. C语言中的每条可执行语句和非执行语句最终都将被转换成二进制的机器指令。(✘)
    【解析】C语言中的非执行语句不会被编译,不会生成二进制的机器指令。

  13. c语言提供了定义函数和子程序的功能。(✘)
    【解析】C语言没有子程序的概念,C语言有函数的概念,它就相当于一个子程序。

  14. —个程序要被称为结构化程序,则只能包含循环结构、选择结构、顺序结构。(✔)

  15. 对于只包含表达式语句的程序段,执行顺序与书写顺序一致。(✔)

  16. C程序的执行一定是从主函数开始,从主函数结束。(✘)
    【解析】C语言程序的执行是从main()函数开始的,但不一定在main()函数结束,在任何其他地方可以调用exit()函数结束程序的运行。

  17. 每个C源文件都应当有一个主函数。(✘)
    【解析】每个c语言程序都有且只有一个主函数。

  18. 在C程序的函数中不能定义另一个函数。(✔)
    【解析】在C程序的函数中不能定义另一个函数,可以声明或调用另一个函数。

  19. 一条C语句对应转换成一条机器指令。(✘)
    【解析】一个C语句经过编译后产生若干条机器指令,而不是对应转换成一条机器指令。

  20. C语言没有子程序的概念。(✔)

  21. c语言程序运行时可以从键盘上读入用户输入的字符或数据,并依此改变程序的运行步骤。(✔)

  22. 程序设计的步骤顺序为确定数据结构、确定算法、编码、在计算机上调试程序、整理并写出文档资料。(✔)

  23. C语言程序由语句构成。(✘)
    【解析】人们把可以连续执行一条指令的集合成为“程序”。

1.2 常量、变量和数据类型(24-73题)

  1. 并非能用文本符号显示的字符都可以用作C语言的标识符。(✔)

  2. 实型常量必须用带小数点的数或带指数的数表示。(✔)

  3. 算术运算符的优先级高于赋值运算符。(✔)

  4. 符号常量是指在程序中通过宏定义用一个符号名来代表一个常量。(✔)
    【解析】定义符号常量的好处是,如果在程序中多处使用了同一个常量,当需要对该常量修改时,只需要在定义处修改一处即可。
    例如:#define 名字 替换文本
    #define PI 3.1415926

  5. 有一类符号,它们或者在键盘上找不到对应的一个键(当然可以用特殊方式输入),或者当按键以后不能显示键面上的字符。其实,这类字符是为控制作用而设计的,故称为控制字符
    在C语言中,构成字符常量的控制字符必须用转义字符表示。转义字符是一种以“\”开头的字符。例如退格符用’\b’表示,换行符用’\n’表示。转义字符中的’'表示它后面的字符已失去它原来的含义,转变成另外的特定含义。反斜杠与其后面的字符一起构成一个特定的字符。
    在这里插入图片描述

  6. C语言的标识符分为3类关键字、预定义标识符和用户标识符。常量不属于标识符。(✔)

  7. c语言中的注释不可以夹在变量名或关键字的中间。(✔)

  8. 字符变量char c = '\101’被分配一个字符的内存空间。(✔)

  9. 在VC环境下,double型数据在内存中占8个字节,float型数据占4个字节,int型数据占4个字节,char型数据占1个字节。(✔)

  10. 只能在函数体内定义变量,其他地方不允许定义变量。(✘)
    【解析】变量可以定义在函数体外也可以定义在函数体内。

  11. 常量的类型不能从字面形式上区分,需要根据类型名来决定。(✘)
    【解析】常量的类型可以从字面形式上区分.比如1为整型常量,1.0为实型常量,a为字符型常量。

  12. 预定义的标识符是C语言关键字的一种,不能另作它用。(✘)
    【解析】预定义的标识符不是c语言的关键字

  13. 整型变量可以分为int型、short型、long型和unsigned型四种。(✔)

  14. '\0’表示字符0。(✘)
    【解析】 '\0’表示结束。

  15. '\ " '是非法的。(✘)
    【解析】 '\ " '是双引号符。

  16. 字符常量可以参与任何整数运算。(✔)

  17. 若有定义语句:char a=‘\82’,则变量a说明不合法。(✔)
    【解析】定义语句: char a=‘\82’.定义字符变量a,‘\82’转义字符错误,八进制转义字符是由反斜杠’‘和随后的1~3个八进制数字构成的字符序列,’\82’超过八进制数表示范围。'\xhh’x开头的1~2位十六进制数字代表一个ASCII码字符,这里没有x,说明a不合法。

  18. 关键字可用作用户标识符,但失去原有含义。(✘)
    【解析】关键字不可用作用户标识符。

  19. 预定义标识符可用作用户标识符,但失去原有含义。(✔)
    【解析】预定义标识符具有见字明义的特点,如函数“格式输出”(英语全称加缩写:printf)、“格式输入”(英语全称加缩写:scanf)、sin、isalnum等等。预定义标识符可以作为用户标识符使用,只是这样会失去系统规定的原意,使用不当还会使程序出错。

  20. C语言中十六进制常量以0x开头,转义字符中十六进制以’\x开头。(✔)

  21. 实型常量中e的前后必须均有数据,且其后必须为整数。(✔)

  22. 定义符号常量必须用类型名来设定常量的类型。(✘)
    【解析】在C语言的预编译处理中,可以用符号名代表一个常量,定义时不必指定常量类型。

  23. 常量是在程序运行过程中值不能被改变的量。(✔)

  24. 经常被使用的变量可以定义成常量。(✘)
    【解析】C语言中,常量是指在程序运行过程中其值不能被改变的量。变量是指运行过程中其值可以改变的量,二者不能混淆。

  25. 符号常量是指在程序中通过宏定义用一个符号名来代表一个常量。(✔)
    【解析】在C语言中,可以用一个标识符来代表一个常量称为符号常量。这个标识符必须在程序中进行特别的"指定",并符合标识符的命名规则。用作符号常量的标识符通常采用大写字母表示,在主函数中其值不能再被定义。

  26. 可以用&A取得符号常量A所占内存的首地址。(✘)
    【解析】&是C语言的取地址运算符,只能对变量取地址运算,不能对常量进行取地址运算。

  27. 常量的类型不能从字面形式上区分,需要根据类型名来决定。(✘)
    【解析】常量的类型可以从字面形式上区分。比如1为整型常量,1.0为实型常量,a为字符型常量。

  28. 整数类型表示的自然数是准确无误差的。(✔)

  29. 不能用sizeof求数值型常量和符号常量所占内存的大小。(✘)
    【解析】 sizeof用来获取类型或数据对象的长度,其操作数可以是系统提供的数据类型,可以是用户自定义,也可以是各种常量和表达式。

  30. 若有说明语句: char c = '\72 ';则变量c中存放的是1个字符。(✔)
    【解析】用一对单引号括起来的单个字符为字符常量,以" \ "开头的转义字符也是字符常量。 " \ "后可以为某些单个字符也可以为八进制或十六进制数字,故c中存放的是一个字符。

 int scanf;
 float case; 

两行语句定义都合法。(✘).

【解析】scanf为库函数名,属于预定义标识符,可以被用户重定义,所以第一行语句合法。case为关键字,是选择结构switch语句中的关键字,不可被用户重定义,所以第二行语句不合法。

  1. auto ,sizeof,unsigned是C语言的关键字。(✔)

  2. -018不符合C语言整形常量。(✔)
    【解析】0表示为八进制,而且只有十进制数可以是负数,而八进制和十六进制数只能是整数。

  3. 2E3是整型。(✘)
    【解析】2E3是实型常量的指数形式。

  4. 若用户标识符的命名与预定义标识符相同,命名无效。(✘)
    【解析】预定义标识符可以作为用户标识符,原来的预定义标识符将会被用户标识符覆盖,预定义标识符的原意失效;用户标识符与预定义标识符同名时,可能会导致运行错误。

  5. char c = " hello! " 定义中有语法错误。(✔)
    【解析】c是字符变量," hello! " 是字符串,字符串不能赋给字符变量,定义中有语法错误。

  6. '\0123321'是不合法的常量数据。(✔)
    【解析】'\0123321 ’ 是字符串常量,应该使用双引号括起来。

  7. 方括号数组说明符中不能使用带有运算符的表达式。(✘)
    【解析】在定义数组时,数组的方括号说明符中必须是常量表达式,但在引用数组元素时,可以是任何合法的表达式,但表达式的值必须是数组下标范围内的整数,假设数组长度为N,那么数组合法下标为0~N-1。

  8. char c1 = ‘A’,c2,*c3;是合法的变量定义语句。(✔)
    【解析】表示定义字符变量c1,初值为’A’,定义字符变量c2和字符指针c3。

  9. 0.3L是错误的,L只能修饰整数。(✔)

  10. 转义字符 '\ t '表示Tab键, '\ n '表示回车换行, '\ r '表示回车符。(✔)

  11. getch是库函数名,不是合法的用户标识符。(✔)

  12. " "是空的字符串, ’ '是空字符NULL。(✘)
    【解析】C语言中, " " 是长度为0的字符串,它包含字符串结束标志符 ’ \0 ',所以不是空字符串。

  13. "\n"和 ’ \n ’ 都是回车字符。(✘)
    【解析】’ \n ’ 是回车字符,“\n"是字符串,它还包括字符串结束标志符 '\0 '。

  14. 字符 '3 '的ASCII码值是51, '0 '的ASCII码值是48, '\0 '的ASCII码值是0。(✔)

  15. 实型变量不能存放实数。(✘)
    【解析】整型变量可以存放实数,但是由于整型数值的数值范围比实数小,所以在存放较大实数时,会有误差。

  16. 若有定义int a=3.5; 语句的作用是将数值3.5存入变量a。(✘)
    【解析】变量a为整型,不能存放数值3.5。

  17. 标识符的长度不能任意长,最多只能包含16个字符 。(✘)
    【解析】不同c语言规定标识符的有效长度可能会不同,但没有限制最大长度。

  18. 实型变量可以精确存放整数 。(✔)

  19. 方括号数组说明符中不能使用带有运算符的表达式。(✘)
    【解析】在定义数组时,数组的方括号说明符中必须是常量表达式,但在引用数组元素时,可以是任何合法的表达式,但表达式的值必须是数组下标范围内的整数,假设数组长度为N,那么数组合法下标为O~N-1。

第二章 运算符与表达式

2.1 C语言运算符简介(74-79题)

  1. C程序书写格式自由,一个语句可以写在多行上。(✔)

  2. 设有定义:int x=11,y=12,z=0;     (z=x,y)    z=(x,y)    (z,x,y) 的值都等于12。(✔)
    【解析】逗号表达式的计算过程是从左到右逐个求每个表达式的值,取最右边一个表达式的值作为该逗号表达式的值。

#include <stdio.h>
main()
{ int a=0,b=0,c=O;
c=(a+=++b, b+=4);
printf("%d,%d,%d\n",a,b,c);
}

则程序的输出结果是1,5,5(✔)
【解析】逗号运算符的结合性从左到右,因此逗号表达式将从左到右进行计算,且逗号运算符的优先级最低。先计算a+=++b结果a为1,b为1.然后计算b+=4,b的值为5;逗号表达式的值为其中最后一个表达式的值,所以将5赋给变量c,即a为1,b为5,c为5。

#include <stdio.h>
main()
{ int a=0,b=0,c=O;
c=(a-=++a),(a+=b,b+=4);
printf("%d,%d,%d\n",a,b,c);
}

则程序的输出结果是1,4,4(✘)
【解析】逗号运算符的结合性从左到右,因此逗号表达式将从左到右进行计算。且逗号运算符的优先级最低,所以先计算第一个表达式c=(a-=++a)。其中++的优先级高于复合赋值运算符-=,所以c=(a-=++a)等价于c=(=a-(++a),先执行++a,a自增1后再赋值,所以a的值为1,赋值运算符从右往左计算,接着执行a=a-1,即a=1-1, a的值为0,并将0赋给变量c,c的值也为0。第二个表达式(a+=b,b+=4),先执行a+=b也就是a=a+b=0+0=0,即a的值为0;然后执行b+=4也就是b=b+4=0+4=4,即b的值为4。所以打印输出a,b,c的值结果为0,4,0。

  1. <>不是C语言程序运算符。(✔)

  2. %的运算对象必须是整型数。(✔)

2.2 算术运算符和算数表达式(80-99题)

int y;
y = rand()%30+1;

y的取值范围是1≤y≤30或0<y≤30(✔)
【解析】rand()产生随机整数,任何整数对30求余得到的整数范围为0~29,则y的取值范围为1≤y≤30或者说0<y≤30。

  1. 若有定义: double x;,则表达式:x=0,x+10,x++的值是10。(✘)
    【解析】前置自增运算:++k表示先自加,后运算。后置自增运算:k++表示先运算,后自加。因此,表达式x=0,x+10,x++的计算过程为首先赋值x=0,然后将x加10,但是并不对x进行赋值,最后计算x++,并根据后置自增运算的计算结果,即为x=0.0。

  2. (k>0) && (k%2!=1)(k>0) && (k%2=0)都能描述k是大于0的偶数。(✘)
    【解析】判断k大于0表达式为k>0,k是偶数表达式为k%2==0k%2!=1, 两个表达式必须都成立,表达式为(k>0)&&(k%2==0)(k>0)&&(k%2!1)

  3. C语言逻辑运算的结果是0和任意非0值。(✘)
    【解析】由逻辑运算符和运算对象组成的表达式称为逻辑表达式,逻辑运算的对象可以是C语言中任意合法的表达式,逻辑表达式的运算结果或者为1(“真”),或者为0(“假”)
    逻辑运算符有||、&&、|、&

  4. c语言关系运算的值只有0和1两种可能。(✔)
    【解析】由关系运算符构成的表达式,称为关系表达式,关系运算的值为“逻辑值”,只有整数0或整数1。
    关系运算符有==、>、<、<=、>=、!=

  5. 运算符[ ]内的数据类型只能是int、char型。(✔)
    【解析】运算符[ ]中必须是整型数,另外char类型可以作为整数。

  6. 复合运算:a*=b+ch是将变量b、ch之和与a相乘,结果再给a赋值。(✔)

  7. 因为double型比int型占内存多,因此将int型数据存入double型变量时,系统无需进行类型转换。(✘)
    【解析】参与运算的数据,只要类型不一致,就会发生数据类型的转换。
    C语言中的数据类型转换一般分为两种,自动转换强制转换
    自动转换遵循以下规则:转换按数据长度增加的方向进行,以保证精度不降低。
    如 int 型和 long 型运算时,先把 int 型转成 long 型后再进行运算。浮点运算都是以双精度进行的,即使仅含 float 单精度量运算的表达式,也要先转换成double型,再作运算。char 型和 short 型参与运算时,必须先转换成 int 型。

  8. int a = b = 0;语句是正确的。(✘)
    【解析】语句中b变量还没有定义不能直接用于给a变量赋值。

  9. 若有以下程序段

double x=5.16894;
printf("%f\n",(int)(x*1000+0.5)/(double)1000);

则程序段的输出结果是5.169000。(✔)
【解析】 %f的输出格式是以带小数点的数学形式输出浮点数。首先计算x* 1000,结果为5168.94然后+0.5,结果为5169.44,然后进行强制类型转换转换成整型为5169然后除以双精度数据1000,结果也为双精度数据5.169输出时按照%f的格式输出,所以输出结果为5.169000。
%f用来输出实数,以小数形式输出,默认情况下保留小数点6位。

 #include <stdio.h>
main(){
int a=0,b=0,c=0,d=0;
(a++ && b++) ? c++:d++;
printf("%d %d %d %d\n",a,b,c,d);
}

程序的运行结果是1,0,0,1。(✔)
【解析】三目运算符的定义
对于a ? b: c,先计算条件a,然后进行判断。如果a的值为true,计算b的值,运算结果为b的值;否则,计算c的值,运算结果为c的值。一个条件表达式绝不会既计算x,又计算y。条件运算符是右结合的,也就是说,从右向左分组计算。例如,a ? b : c ? d : e将按a ? b : (c ? d : e)执行。

  1. 若在程序中变量均已定义 int 类型,且赋大于1的值。则下列选项中能正确表示代数式1/abc的表达式是 ( A
    A、1.0 / a / b / c
    B、1 / (a * b * c)
    C、1.0 / a * b * c
    D、1/ a / b / ( double ) c
    【解析】 由于abc均大于1,所以表达式1/abc小于1,需要用浮点类型表示。若要计算表达式值,需要使其自动转化成浮点类型,所以A选项正确。
    B选项由于变量与常量均为整型,不会自动转换为浮点类型,B选项错误。
    C选项表示表达式bc/a,故错误。
    D选项,由于算数运算法结合性自左向右,先计算1/a,结果为0,之后的计算无论是否转换数据类型结果均为0,D选项错误。

  2. 5.3. 都是浮点数,省略了后面的0。(✔)

  3. double x=1.5是实型变量,不可以做自增1运算。(✘)
    【解析】C语言中自增自减运算符的运算对象可以是整型、实型、字符型、枚举型,作用就是对运算数进行自增1或自减1。

  4. x的平方是pow(x,2)。(✔)

  5. 若有定义:double a=22;int i=0,k=18; 则i=a%11;不符合C语言规定。(✔)
    【解析】取余运算符"%",二元运算符,具有左结合性,参与运算的量均为整型。a变量是double实型,所以不符合C语言规定。

  6. double a=0.0; b=1.1;这个语句是正确的。(✘)
    【解析】a=0.0后面应该是逗号,不能是分号。

  7. 能够正确利用随机函数rand(),产生一个英文字母的表达式是 rand()%2==0?rand()%26+'A':rand()%26+'a'。(✔)

  8. scanfprintf 是C语言提供的输入和输出语句。(✘)
    【解析】scanf 和 printf 是C语言提供的输入和输出函数。

  9. 由print输出的数据都隐含左对齐。(✘)
    【解析】由print输出的数据都隐含右对齐。

2.3 赋值运算符和赋值表达式(100-103题)

  1. 赋值语句是一种执行语句,必须放在函数的可执行部分。(✔)

  2. a是实型变量,a=10在C语言中是允许的,因此可以说:实型变量中可以存放整型数。(✘)
    【解析】a是实型变量,a=10在C语言中是允许的,但是实型变量中不可以存放整型数。

  3. 由 printf 输出的数据的实际精度是由格式控制中的域宽和小数的域宽来完全决定的。(✘)
    【解析】print输出数据所占的宽度由系统决定。

  4. 当x = 7 ,y = 12时,表达式y%=x-x%5的值为3。(✘)
    【解析】-(减号)的优先级大于%大于%=

2.4 位运算(104-114题)

#include <stdio h>
main()
{
unsigned char a=8,c;
c=a>>3;
print("%d\n",c);
}

程序运行后的输出结果是1。(✔)
【解析】无符号整型变量的值为8,二进制表示为00001000,右移3位变成00000001,即十进制的1,所以输出1。

#inchude <stdio.h>
main()
{
unsigned char a=2, b=4,c=5,d;
d=a|b; d&=c;
printf("%d\n",d);
}

程序运行后的输出结果是4。(✔)
【解析】 & 按位与,如果两个相应的二进制位都为1,则该位的结果值为1,否则为0,| 则为按位或,两个相应的二进制位中只要有一个为1,该位的结果值为1。

  1. 异或(^)规则:相同为0,不同为1。

  2. 按位取反(~)规则:0变1 , 1变0。
    所有正整数的按位取反是其本身+1的负数。
    所有负整数的按位取反是其本身+1的绝对值。
    零的按位取反是-1 (0在数学界既不是正数也不负数)。

  3. 位运算的对象只能是整型或字符型数据。(✔)

  4. 位运算符都需要两个操作数。(✘)
    【解析】按位取反~只需要一个操作数。

  5. 左移运算的结果总是原操作数据2倍。(✘)
    【解析】左移一位是原操作数的2倍 ,其他情况不是,比如左移两位就是原操作数的4倍。

  6. 右移运算时,高位总是补0。(✘)
    【解析】右移运算时,高位在某些情况下不是补0

  7. 双或运算 ||:一旦左边是true,右边就不参与运算了。8||3=1
    双与运算&&:一旦左边是false,右边就不参与运算了。
    或运算 | :不管左边是true还是false,右边都参与运算。
    或运算 & :不管左边是true还是false,右边都参与运算。

  8. 13>>1,二进制结果为0110。
    >>把操作数的二进制码右位移指定位数,左边空出来的位以原来的符号位填充。原来是负数就填充1,原来是正数就填充0。符号位不变。

#inchude <stdio.h>
main()
{
int a=2, b;
b=(a>>=1)+4;
printf("%d,%d\n",a,b);
}

程序运行后的输出结果是2,5。(✘)
【解析】 a>>=1等价于a=a>>1,即a右移一位,则a=1,b=(a>>1)+4=1+4=5,因此,打印a、b的值分别为1,5。

第三章 基本语句

3.1 字符的输入输出(115-117题)

  1. gets函数用于从终端读入字符串。getchar函数用于从终端读入字符。
    puts函数用于从终端输入字符串。getchar函数用于从终端输入字符。(✔)
    【解析】
    puts函数(字符串输出函数)一般形式:puts(字符数组)
    gets函数(字符串输入函数)一般形式:gets(字符数组)

#include <stdio h>
main(
char c1,c2,c3,c4,c5,c6;
scanf("%c%c%c%c",&c1,&c2,&c3,&c4);
c5=getchar();
c6=getchar();
putchar(c1);
putchar(c2);
printf("%c%c\n",c5,c6);

程序运行后,若从键盘输入(从第1列开始)
123<回车>
45678<回车>

程序运行的结果是1245(✔)
【解析】scanf 按照格式字符进行输入,所以123与回车的值分别送入了c1、c2、 c3、 c4变量的存储空间。getchar()函数的功能是从键盘输入的字符串中读入一个字符,所以4送入了变量c5的存储空间,5送入了变量c6的存储空间。所以打印时结果为1245。

  1. ASCLL代码对照表请添加图片描述

3.2 数据格式的输入输出(118-143题)

  1. scanf(“%s”,s)表示输入一个字符串,遇到空格会结束输入。所以当字符串内带有空格时,不能使用此语句。(✔)

  2. 在scanf函数的格式字符前既可以加入正整数指定输入数据所占的宽度,也可以对实数指定小数位的宽度。(✘)
    【解析】在scanf()函数的格式字符前可以加入一个正整数指定输入数据所占的宽度,但不可以对实数指定小数位的宽度。

  3. case是C语言中的关键字,不能作为变量名。(✔)

  4. 空语句就是程序中的空行。(✘)
    【解析】C语言中的语句必须以分号“;”结尾,所以空语句表示为分号“;”,不是空行。

  5. 复合语句也被称为语句块,它至少要包含两条语句。(✘)
    【解析】符合语句可以由任意多条语句构成,也可以一条没有。

#include <stdio.h>
main()
int a=2,c=5;
printf("a=%%d,b=%%d\n", a,c );

程序的输出结果是a=%d,c=%d(✔)
【解析】%%是输出%号,所以%%d,输出为%d两个普通字符,而不是格式控制符"%d"的含义

  1. 以下能正确输出字符a的语句是(A
    A.print(“%s”, “a”);
    B.print(“%s”, ‘a’);
    C.print(“%c”, “a”);
    D.print(“%d”,‘a’);
    【解析】“格式控制串"用来指定每个输出项的输出格式,%s对应字符串,%c对应字符,%d对应整型。双引号里面的内容为字符串"a”,单引号里面的内容为字符’a’, A选项正确。

  2. 以下语句的输出结果是5。(✔)

printf("%d\n", strlen("\t\"\065\xff\n"));

【解析】由一双引号括起来的一串字符为字符串。字符常量是用一对单引号括起来的单个字符,还有一些特殊字符常量,即以 ’ \ ‘开头的转义字符。 ’ \ ‘后可以为某些单个字符也可以为八进制或十六进制数字,’\t’      ’ \ " ’     ‘\065’    '\xff    ‘\n’ 共5个字符。

  1. 第13题:设有定义: double x=2.12;, 以下不能完整输出变量x值的语句是(A)
    A.printf(“x=%5.0f\n”,x);
    B.print(“x=%f\n”,x);
    C.print(“x=%lf\n”,x);
    D.printf(“x=%0.5f\n”,x);
    【解析】float类型变量有效位数为6 - 7位,double类型变量有效位数为15 - 16位。print函数控制字符%f输出float类型,%lf 输出double类型。
    对于float或double型数据,在指定数据输出宽度的同时,也可以指定小数位的位数,格式为 %m.nf,表示数据输出总的宽度为m位(包括小数点),其中小数部分占n位。当数据的小数位多于指定宽度n时,截去右边多余的小数,并对截去的第一位小数做四舍五入处理;而当数据的小数位少于指定宽度n时,在小数的右边补零;当m小于有效位数时,整数部分输出所有有效数字并且自动对齐,小数部分按照n指定位数输出。
    函数printf()中,%md,指输出带符号的十进制整数,给定最小宽度为m位,不足m位左端补空格,超过m位按实际位数输出, %nf表示以小数形式输出实数,小数占n位。

    A选项按照float格式输出数据,宽度为5位,保留小数0位,输出为2,不能完整输出x,选择A选项。B选项按照float格式输出数据,输出为2.120000。C选项按照double格式输出数据,输出为2.120000. D选项按照float格式输出数据,保留小数位数为5,输出为2.12000。

  2. 若有定义: int a=1234, b=-5678;用语句printf(“%±6d%±6d”,a,b);输出,则输出结果是+-1234+-5678 (最前面和最后均无空格)。(✘)
    【解析】print函数参数包括格式控制字符串和输出参数,其中格式控制字符串中除了格式控制字符外,其他字符原样输出,本题中,在%和格式字符d之间,+号表示输出的数字带正负号,-号表示输出数据向左对齐,6表示表示输出宽度,如果输出数据的宽度不够6,那么左对齐,右边补空格,所以本题输出+1234 -5678,中间一个空格,最后一个空格

  3. 若有定义int a=1234, b=-5678;用语句printf(“%+06d%+06d” ,a,b);输出,输出结果是+01234-05678。(✔)
    【解析】 在print函数中,如果输出时,每一个数前面带有正负号,则通过格式控制符“%+”来实现。格式控制符“%+06d"表示带正负号输出的数据一共为6位。a=1234, b=-5678加正负号后为5位,在左侧补0满足6位。

  4. 有说明语句:int a,b;,如果输入111222333,使得a的值为111,b的值为333,则scanf("%3d%*3d%3d", &a, &b);是正确的语句。(✔)
    【解析】要是a的值为111, b的值为333,必须在读入时指定a的读入宽度为3,b的读入宽度为3,且a和b的控制字符之间必须额外增加%*控制符,用于跳过中间的三位输入数字。

  5. 设有定义:int a; float b; ,执行scanf(“%2d%f” ,&a,&b);语句时,若从键盘输入
    876 543.0<回车>则a和b的值分别是876和543.0。(✘)
    【解析】 函数scanf()中,%md,在格式字符前加入一个整数可以指定输入数据所占的宽度,所以赋值时会将87赋给变量a,把6.0赋给float型变量b,所以a和b的值分别为87和6.0

  6. 当用scam从键盘输入数据时,每行数据在没按下回车键(Ente键)前,可以任意修改。(✔)

  7. 空语句就是指程序中的空行。(✘)
    【解析】C语言中空语句表示为";”,不是空行。

  8. 复合语句也被称为语句块,它至少要包含两条语句。(✘)
    【解析】复合语句可以由任意多条语句构成,可以是一条语句也可以没有。

#include <stdio.h>
main()
int a=2, c=5;
printf( "a=%%d,b=%%d\n", a,c );

程序的输出结果是a=%2,c=%5(✘)
【解析】C语言中用”%%”打印输出字符”%”,所以%%d输出为%d两个普通字符,而不是格式控制符“%d"的含义。所以都打印结果为a=%d,c=%d

  1. scanf(“Input:%d%d”. ,&a,&b);, 格式串中允许加入格式符以外的字符串。(✔)
    【解析】在使用scanf函数时,如果除了格式说明字符和附加格式字符外,还有其他字符,则在输入数据时要求按一一对应的位置原样输入这些字符。

  2. scanf(“%d%d%f” ,&a,&b); 多余的格式符%f完全不起作用。(✘)
    【解析】A选项中%f是起作用的,程序从键盘正确的读入前两个数据并且保存在指定的地址,读入第三个数据后,将其放入缓冲区,然后寻找应该存放的地址,因为没有找到,程序会发生错误而中断。

  3. '\a’不是合法C语言转义字符。(✘)
    【解析】C语言中, ‘\a’表示响铃,’\b’表示退格, '\r’表示回车不换行, '\c’不是合法C语言转义字符。

  4. 若有定义float a=12.3f; double b=456.78; 若想用printf函数输出a和b的值,只能用%f输出a,用%lf输出b。(✘)
    【解析】C语言中,%f是格式字符,表示以带小数点的数字形式输出浮点数,它既可以输出单精度数,也可以输出双精度数,所以既可以用%输出a,也可以用%输出b

int k=0;
k=printf("OK\n");

则以下叙述中正确的是( C )。
A、printf必须作为独立语句出现
B、变量k得到的是输出的可见字符个数2
C、变量k得到的是输出字符的总个数3
D、变量k仍保持初值0
【解析】printf()函数的原型如下:
extern int printf(const char *format…);
它是有返回值的,返回值是打印出来的字符个数,题意中的字符串"OK\n"输出3个字符,所以k的值为3,本题答案为C。

  1. short类型,使用%hd。(✔)

  2. 若有定义和读入语句: .

short a;
scanf("%hd", &a);

则以下数据能被正确输入给变量a的是( C )
A.45678        B.32768        C.32767        D.-32769
【解析】短整型short int的取值范围为: -32768~32767之间。 选项A、B和D输入是的数据超出范围。选项C正确。

  1. 以下选项中错误的是( A )
    A、printf(“%s\n”, ‘s’);
    B、printf(“%d %c\n”, ‘s’,‘s’);
    C、printf(“%c\n”,‘s’ - 32);
    D、printf(“%c\n”, 65);
    【解析】%d可以作为输出字符和整型类型的格式,%c作为输出字符类型的格式,%s作为输出字符串类型的格式,选项A,’ s’是字符,不能用%s格式来输出。故答案为A选项。

  2. 设有定义: double x;,以下选项中不能将输入数据3.14读入赋给变量x的是
    A、scanf(“%4.2f” ,&x);
    B、scanf(“%lf” ,&x);
    C、scanf(“%le” ,&x);
    D、scanf(“%4lf” ,&x);
    【解析】scanf()函数格式字符串的一般形式为: %[*]输入数据宽度][长度类型]。输入数据宽度必须是十进制的整数,它没有精度控制。
    %4.2f是错误的,不能企图用此语句输入小数点为2位的实数,选项A错误;
    scanf()函数的长度格式符为和h, %1f表示用小数形式输入双精度浮点数,选项B正确;
    %le表示用指数形式输入双精度浮点数,满足条件,选项C正确;
    %4lf表示用小数形式输入宽度为4的双精度浮点数,选项D正确。

第四章 选择结构

4.1 关系运算符和关系表达式(144题)

  1. 分支结构是根据算术表达式的结果来判断流程走向的。(✘)
    【解析】分支结构的流程走向是根据表达式的值,并不仅仅是算数表达式的值。

4.2 逻辑运算符和逻辑表达式(145-149题)

  1. (a== !0)与(!a== 0 )的逻辑值等价。(✘)
    【解析】表达式 !a == 0中,! 的优先级高于 ==,即等价于(!a)==0。如果a≠0,则表达式为真,否则表达式为假。所以 ( a = = !0)与(!a == 0 )的逻辑值不等价。

  2. “=“优先级低于”<” “>”。(✔)

  3. C语言的关系表达式: 0<x<10完全等价于: (0<x) && (x<10)。(✘)
    【解析】(x>0)&(x<10)的值是1或0,条件是x>0并且x <10。但是0<x<10这种写法的结果任何时候都是1

  4. 以下选项中,能判断char型变量c中是大写字母的是( C )。
    A. (c>=‘A’)OR(c<=‘Z’)
    B、‘A’<=c<=‘Z’
    C、(c>=‘A’) && (c<=‘Z’)
    D、 (‘A’<=c) AND (‘Z’>=c)
    【解析】C语言中,OR、AND都是不合法的。选项B中“<=”、“<=”不能连用,否则得到的不是想要的结果,选项C中,当c是大写字母时,c>='A’和c<='Z’都为真,所以逻辑与表达式也是真,本题答案为C。

  5. 关系运算符的结果有三种:0,1,-1。(✘)
    【解析】关系运算符的结果只有“真”和“假”。

4.3 if语句和用if语句构成的选择结构(150-164题)

  1. else不是一条独立的语句,它只是if语句的一部分。(✔)

  2. 有以下程序

 #include <stdio.h>
 main()
{
int a=0,b=0,c=0,d=0;
if(a=1) b=1;c=2;
else d=3;
printf("%d,%d,%d,%d\n".a,b,c,d);
}

则程序输出(A
A、编译有错 B、0,0,0,3 C、1,1,2,0 D、0,1,2,0
【解析】C语言规定else总是和之前与其最近的且不带else的i配对,题目中,if(a=1) b=1;c=2;默认省略的else已经配对了,下一句else没有匹配 if,为非法else,会产生编译错误。因此答案为A选项。

  1. 逻辑与运算符优先级比逻辑或运算符优先级高。(✔)

  2. 语句if(sel!=0) ;else row=5;与语句if(!sel) row=5;不等价。(✘)
    【解析】if(sel!=0); else row=5;即为sel==0时执行row=5。与语句" if(sel) row=5"等价,此处sel等于0时,! sel的值才为真,执行row=5。所以等价。

#include <stdio.h>
main()
{
int x=1, y=0;
if(!x) y++;
	else if(x==0)
		if(x) y+=2;
			else y+=3;
printf("%d\n",y);
}

程序运行后的输出结果是2。(✘)
【解析】因为x=1,!x为0,x==0为假,所以 if 和else if的判断条件都不满足,程序运行时只执行x,y的初始化语句和printf()函数,打印出y的值为0

#include<stdio.h>
main()
{
int x = 0x13;
if(x = 0x12) printf("True");
printf("False\n");
}

程序运行后的输出结果是False。(✘)
【解析】if (x=0x12〉表示x=0x12,此为赋值语句,表达式的值为0x12,非零为真,执行printf(“True”),再执行printf(“False\n”),因此输出结果为TrueFalse。
注意赋值操作符"="与相等操作符"=="的区别。

if(year%400 == 0)  return 1;
	else if(year%100!=0)
if(year%4==0)  return 1;
	else refurn 0;

若要利用if-else语句判断year是否闰年,是闰年则返回1,不是闰年则返回0。上述程序段能完成正确判断。(✘)
【解析】判断year是闰年,需要满足两个条件之一:
(1) year可以被4整除且year不能被100整除。
(2) year可以被400整除。
上述程序段没有考虑year能被100整除不是闰年的情况,所以错误。

  1. if(m>n) m--
    else n--;
    编译时会产生错误信息。(✔)
    【解析】if语句语句块m- -后少了个分号,是不合法的,所以编译会出错。

 #include <stdio.h>
 main()
{
int t;
scanf("%d",&t);
if( t++<6 ) printf("%d\n", t);
else    printf("%d\n", t--);
printf("\n");
}

执行时输入:6<回车>,则输出结果是6。(✘)
【解析】后置自增〈自减)运算:先使用参与运算,再自加(自减)。t 的初值为6,表达式t++的值为6,t自增1值变成7,t++<6为假,执行printf("%d\n", t--);此时t=7,t- -为后置- -,先使用再自减,所以表达式t - -的值为7,打印输出结果为7,之后t自减1值变成6。所以输出结果为7

 scanf("%d%d%d",&a,&b,&c);
 if(a<b) a==b;
 if(a<c) a==c;
 printf("%d\n",a);

该程序段的功能是输出a的原始值。(✔)
【解析】程序段执行过程为:从键盘读入3个整型数据分别赋值给a,b,c,如果a<b,判断a与b是否相等,无论结果如何不做任何改变。如果a<c,判断a与c是否相等,无论结果如何不做任何改变。最后对于a,b,c的值不做任何改变,输出a的原始值。

#include <stdio.h>
void get_put()
{
	char ch;
	ch = getchar();
	if(ch != '\n') get_ put();
	putchar(ch);
}
main()
{
	get_put();
	printf("\n");
}

程序运行时,输入1234<回车>,则输出结果是1234。(✘)
【解析】在调用一个函数的过程中又出现直接或间接的调用该函数本身,称为函数的递归调用

本题程序的执行过程为:
在输入1234<回车>的情况下,调用 get put() 函数,getchar()读入1,在这次调用中的
局部变量ch=‘1’, if条件成立→调用get put()函数,读入2;
局部变量ch='2’→调用get_put)函数,读入3;
局部变量ch='3’→调用get_put()B函数,读入4;
局部变量ch='4’→调用get_put)函数,读入回车, if条件不成立。
返回执行每次调用函数中if语句后的输出语句,即依次输出4321

4.4 switch语句和goto语句(165-170题)

#include <stdio.h>
main()
{ int a,b;
	for (a=0; a<3; a++)
	{ 
	scanf("%d",&b);
	switch(b){
		default: printf("%d,",++b);
		case 1: printf("%d,",++b);
		case 2: printf("%d,",++b);
		     }
	}
}

执行时输入:1 2 3<回车>,则输出结果是2,2,3,4,4,4。(✘)
【解析】程序在执行switch语句时,根据switch后面表达式的值找到匹配的入口标号,执行对应的case语句,之后不再进行判断,继续执行此case后面的语句,并且各个case和default的出现次序不影响执行结果,即题目中的default放在开始位置,与放在最后是一样的结果。
本题,第一次循环输入b=1,执行case 1,输出2,再执行case 2,输出3,第二次循环输入b=2,执行case 2输出3,第三次循环,输入b=3,没有case与其对应,故执行default输出b=4,接着行case 1:,输出5,再执行case 2,输出b=6,至此退出for语句。因此,最后输出为2,3,3,4,5,6

#include <stdio.h>
main()
int x=1,y=0,a=0,b=0;
switch(x){
	case 1:
	switch(y){
		case 0: a++; break;
		case 1: b++; break;
		}
	case 2: a++; b++; break;
	case 3: a++; b++;
}
prinf("a=%d, b=%d\n",a,b);

程序的运行结果是a=1,b=0。(✘)
【解析】x=1;进入第一层switch, y=0;
进入第二层switch,执行a+ +;break;后a=1;
再进入case2, (这里case1: 没有break, )执行了a++,b++; 由于存在break,则跳出switch,得到a=2,b=1。

#include <stdio.h>
main()
int a,b;
for (a=0;a<3; a++){ 
	scanf("%d", &b);
	switch(b){
		default: printf("%d,",b+1); continue;
		case 1: printf("%d,", b+1);
		case 2: printf("%d,", b+1); continue;
			}
				}

执行时输入: 1 2 3<回车>,则输出结果是2,3,3,4,5,6(✘)
【解析】continue语句的作用是跳过循环体中剩余的语句而强行执行下一次循环。switch…case如果没有break会导致多个分支重叠。
输入1时执行case 1: printf("%d,", b+1); case 2: printf("%d,", b+1); continue;后结束。
输入2时则执行case 2: printf("%d,", b+1); continue;
输入3时则执行default: printf("%d,",b+1); continue;得到的结果是2,2,3,4。

  1. switch语句的一般形式为:
switch(表达式)
{
	case常量表达式1:语句1;
	case常量表达式2:语句2;
	default:语句n;
}

其中switch后的表达式只能是整型或字符型;
case 后面必须是常量表达式;
switch()右括号后面不能有分号。(✔)

#include <stdio.h>
main()
{
int i=1,k=0;
for( ;i<6; ){
	switch(i%3){
		case 0: k++;
		case 1: k++;break;
		case 2: k++;continue;
				}
		i+=1;
		 	{ 
printf("%d\n",k);
}

程序的运行情况是输出5(✘)
【解析】本题执行过程为: i=1,k=0, i<6成立,执行for循环: i%3=1, 匹配case1,k=1,break退出
switch, i=2; i<6成立, 执行for循环: 2%3=2,匹配case2,k=2,执行continue,由于其只用于循环结构,退出switch, 且不执行此次for循环以后的语句,i=2不变,i<6成立,执行下一次for循环,以后的循环情况与刚刚的情况完全一致, i=2不会改变,形成无限循环

#include <stdio h>
main()
int m=10247,a=0,b=0,c=0;
	do {
		switch(m%10)
		{
			case 0: m/=10; a++;
			case 1: case 3: case 5: case 7: case 9: m/=10; b++; .
			case 2: case 4: case 6: case 8: m/=10; c++;
		}
	}while(m!=0);
printf ("%d,%d,%d\n" ,a,b,c);

程序运行后的输出结果是0,1,1(✘)
【解析】程序定义整型变量m初值10247, a, b, c初值为0,接着执行do…while循环,使用switch语句从个位开始判断m的数值位。

第1轮循环: m=10247, 个位数字是7,执行case7, case9, m除以10等于1024, b自增1后值为1;接着执行case2, case4,case6, case 8, m再除以10等于102,c自增1后值为1;
第2轮循环: m=102,个位数字是2,执行case2, case4, case6, case8, m除以10等于10, c自增1后值为2;
第3轮循环: m=10,个位数字是0,执行case0, m除以10等于1,a自增1后值为1;继续执行case1, case3, case5, case 7,case9, m除以10等于0,b自增1后值为2;继续执行case2, case4, case6, case8, m除以10等于0,c自增1后值为3
循环结束;
综上,a的值为1,b的值为2, c的值为3。

第五章 循环结构

5.1 while循环语句(171-178题)

 #include<stdio.h>
 #include<math.h>
 main()
{
int s; float n,t,pai;
t=1,pai=0,n=1.0,s=1;
	while(fabs(t)>1.0e-6)
	{
	pai+=t;
	n+=2; s=-s;t=s/n;
	}
printf("total=%f\n" ,pai);
}

程序所计算的是( D )。
A、1-1/2!+1/3!-1/5!+1/7!-…
B、1+1/3+1/5+1/7+1/9-…
c、1+1/2+1/3+1/4+1/5-…
D、1-1/3+1/5-1/7+1/9-…
【解析】main()函数首先定义整型变量s,初值为1,定义float类型的n、t、 pai,其中n初值1.0,t初值为1,pai初值为0; while循环判断t的绝对值(fabs)为求float类型值的绝对值)是否大于1.0* 10 ^ -6,若t的绝地址大于1.0*10 ^ -6,那么,执行下列语句:
pai+=t; n+=2; s=-s; t=s/n;
所以每轮循环pai累加s/n(其中s是上一轮s的相反数,n是上一轮n累加2的值),第一轮循环时,pai被赋值为1,s是正数,所以最终pai的计算结果是:
1-1/3+1/5-1/7+1/9…,本题答案为D。

  1. 若有定义: char ch;当执行以下循环时从键盘输入abcde<回车>,将输出* 的个数是1个
    while((ch=getchar())=='e') printf(" * ");(✘)
    【解析】while((ch=getchar()==’ e’ ),输入abcde,接收到的第一个字符是a, while循环的条件为0,跳出循环结束。因此printf没有执行过。因此,没有打印任何字符出来。

#include <stdio.h>
main( ){
	char *s="01234";
	while(*(++s)!='\0'){
		switch(*s-'0'){ 
			case 0:
			case 1: putchar(*s+1); break;
			case 2: putchar(*s+1); break;
			case 3: putchar(*s+1);
			default: putchar(*s+1); break;
					  }
					    }
	    }

程序执行后的输出结果是23445。(✔)
【解析】程序首先定义一个字符指针s,指向一个字符串"01234" ;接着while循环的循环条件每次将指向下一个字符,然后判断指向的字符是否为空字符’\0’,若不是,则执行循环体,将当前字符与0的ASCII码差值作为switch语句的常量表达式,执行对应的case语句;否则终止循环,程序结束。

所以对于字符串"01234"可知:循环过程中s指向的各个字符分别是: 1、2、3、4。
当 * s是 ‘1’时,* s- ‘0’ 的值为1, 执行case 1语句,输出 * s+1 即字符 ‘2’;
当 * s 是’2’时,* s-‘0’ 的值为2,执行case 2语句,输出 * s+1即字符 ‘3’;
当 * s 是‘3’时,* s-‘0’ 的值为3,执行case 3和default语句,输出两次 * s+1即字符 ‘4’;
当 * s 是’4’时,* s-‘0’ 的值为4,执行default语句,输出 * s+1 即字符’5’。
综上程序输出结果为: 23445。

#include 
<stdio.h>
main()
int a=1,b=1;
while(a--)
	b--;
printf("%d,%d\n", a,b);

程序的运行结果是0,0。(✘)
【解析】本题执行过程为:先取a值为1,执行循环,a=0, 执行b–, b=0,再取a值为0,判断条件不成立,退出循环,再执行a-- 得到a=-1,最后输出a=-1,b=0

#include <stdio.h>
main(
int a=-2,b=0;
while (a++ && ++b); 
	printf("%d,%d\n". a,b);

程序运行后输出结果是0,3。(✘)
【解析】本题重点考察while语句,变量a和b分别赋初值为2和0,while语句的语义是:计算表达式的值,当值为真(非0)时,执行循环体语句,循环体为空语句。a++即a参与运算后,a的值再自增1。++b即b自增1后再参与其它运算。当表达式的值为时,退出循环。

第一次循环后, a=-1, b=1;第二次循环后,a=0,b=2;
当a++=0时,根据 短路原则++b不需要计算,条件表达式为退出循环。所以退出循环时a=1,b=2。

#include <stdio.h>
main(){
	char c;
	while(c=getchar()){
		if(c=='i'){	
			c=getchar();
			for(;!((c==i)(=='.')|(c=='\n')); c=getchar()
			if(c=='a')  continue;
				else printf("%c",c);
				}
					else if(c=='\n') break;
					}
	printf("%c",c);
		}

若程序运行时输入字符串: this is a string <回车>,则程序的运行结果是
【解析】程序使用函数getchar()读入字符,当读入字符时,if条件为真,再执行c=getchar(), 则c=‘s’ ,此处for循环的的循环条件为真。执行循环体 if-else 语句,c为字符s不满足if条件,执行else子句, 输出变量c的值即s;接着执行for循环的c=getchar(),则c为字符空格,循环条件为真,i条件不满足,执行else子句,输出变量c的值即空格,接着执行for循环的c=getchar0,此时c的值为字符i,循环条件不满足,退出for循环;继续执行while循环的c= getchar(),直到c为字符时,进入到if语句,执行c=getchar0,此时c的值为字符n,循环条件为真,执行循环体if-else语句,c为字符n不满足i条件,执行else子句,输出字符c的值即n.接着执行fo循环的c-getcharo.则c的值为字符g,循环条件为真,执行循环体if-else语句,c为字符2不满足if条件,执行else子句,输出c的值为g,再次执行for循环的:har(,则c的值为字符",循环条件不满足退出for循环;继续执行while{循环中的C=getchar),此时c的值为回车,if条件不满足,执行eiseif子句, 退出循环。

#include <stdio.h>
main( )
int m,n;
scanf("%d%d", &m,&n);
while(m!=n){
while(m>n) { m=m-n; }
while(n>m) { n=n-m; }
printf("%d\n".m);

该程序的功能是求最大公约数
【解析】 题目使用尼考曼彻斯法求最大公约数,尼考曼彻斯法的特色是做一系列减法, 辗转相减,从而求得最大公约数。

  1. 以下程序中给数组所有元素输入数据,请从选项中选择正确的答案填入下划线处
#include <stdio.h>
main( )
{
int a[10], i=0;
while(i<10) scanf("%d",_______ );
}

A、a+(i++)
B、&a[i+1]
C、a+i
D、&a(i++)
【解析】A选项为数组首地址,i++先取i值再加1,scanf读入 的数据依次存放在数组中,A选项正确。
B选项,第一个数据读入a[1],最后一次循环引用a[10],数组越界,B选项错误。
C选项,控制变量 i 没有依次加1,无法结束循环,也无法对整个数组赋值,输入的数全是a[0],C选项错误。
D选项数组元素引用错误,数组元素引用为[ ],不是( ),D选项错误。

5.2 do…while循环语句(179-181题)

  1. do 循环体 while (条件表达式);
    条件表达式的执行次数总是比循环体的执行次数多一次。(✘)
    【解析】 do…while循环的执行过程是先执行一遍循环体后再执行条件表达式判断条件直到条件不成立跳出循环,所以循环体的执行次数和条件表达式的执行次数是一致的

 i=0;
do prinf("%d," ,i);while(i++);
printf("%d\n",i);

其输出结果是0,0。(✘)
【解析】do-while循环第一 次执行循环时,先执行do后面的循环体,打印输出的值0,然后再判断while后表达式i++的值,后置++先使用后自增,表达式i++的值为0,变量的值自增为1,所以判断时条件为假,结束do-while循环,接下来执行printf语句,打印输出的值为1,所以程序输出结果是0,1

#include <stdio.h>
main()
{
int x,y=0,z=0,t;
do{
	scanf("%d",&x);
	t=x>0;
	switch (t){
		case 0: break;
		case 1: y+=x; continue;
			  }
		z+=x;
	}
	while(x);
printf("%d,%d\n",y,z);
}

程序运行时输入: -1 1 -2 2 0<回车>,则输出结果是3,0。(✘)
【解析】break语句是跳出switch语句,接着执行do… while循环体剩下的部分;
continue语句是直接进入do…while的下一个循环。
由此可知每次循环,当t=0时,执行break语句,接着将z值累加x;
当t=1时,执行continue语句, 将y值累加x,所以当x输入-1、-2、0时,t=0,z值累加为-3;
当x输入1、2时,t=1, y值累加为3,输出y、z的值分别为3、-3

5.3 for循环语句(182-190题)

#include <stdio.h>
main()
{
	int a = 1, b = 1;
	for( ; a--; ) b--;
	printf("%d,%d\n", a, b);
}

程序运行后的输出结果是0,0。(✘)
【解析】题干中语句for( ; a- -; ),条件 a- -!0,先判断 a!=0 成立,则进入循环,然后a自减1为0,起始a=1不等于0,满足条件进入for循环,然后a自减为0,b自减1为0,继续循环;再跳回for语句时, a!=0 不成立,不会进入循环,但是a也要自减1为-1,循环结束。因此最后输出a=-1,b=0

#include <stdio.h>
main(){
	int a=-2, b=2;
	for(; a++,b-- ;)
printf("%d,%d,",a, b);
	  }

程序执行后的输出结果是-1,1,0,1。(✘)
【解析】 main() 函数中定义两个整型变量a、b, 初值分别为-2,2。for循环每次判断表达式a++,b - -的值,这是逗号表达式,首先计算a++,再计算b- -,整个表达式的值是b–的值,若逗号表达式的值不为0,则执行for循环,输出a、b的当前值,再执行下一次循环,直到逗号表达式为0,循环终止。所以程序最后的结果是-1,1,0,0

!!!逗号表达式的值:最后一个表达式的值。

#include <stdio h>
main(
{
int i;
for(i=0;i<5; i++)
putchar(9' - i% 2);
}

程序运行后的输出结果是'9''8''7''6''5'。(✘)
【解析】main()函数循环遍历的值为0、1、2、3、4,每次遍历调用putchar()函数输出表达式'9'-i%2的结果, 由运算符优先级可知表达式'9'-i%2首先计算i%2的值,再执行减法操作,所以当 i 取值为偶数时,‘9’ - 0 的值为0, ‘9-0结果为"9; 当 i 取值为奇数时,i%2的值为1, ‘9’-1结果为’8’,程序运行后的输出结果是98989

#include <stdio.h>
main()
int a=1,b=2;
for(;a<8;a++) {b+=a; a+=2;}
prinf("%d,%d\n" ,a,b);

程序运行后的输出结果是9,18。(✘)
【解析】第一次循环a的值为1,满足条件执行b+=a,与a+=2则的值变为3,a的值变为3。执行a++,a的值为4,满足条件进入第二次循环,执行完循环体后b的值为7,a的值为6。执行a++ ,a的值为7满足条件进入第三次循环,执行完循环体后b的值为14,a的值为9。执行a++, a的值变为10。程序运行后的输出结果是10,14

  1. break和continue都是作用于循环的,比如for循环和while循环。
    break:结束所有循环,本次循环体不再执行,跨出循环体以内的内容。
    continue:结束本轮循环,开启下一轮循环,本轮循环剩下的内容不在执行。

for(i=O;i<4;i++,i++)
	for(k=1;k<3;k++);
	printf("*");

程序段的输出结果是****。(✘)
【解析】由于内层循环for(k=1;k<3;k++)后面直接跟了空语句" ; " 所以在整个循环里什么操作也不做,跳出外层循环后执行打印语句,所以打印了一个"*"。

  1. 以下判断形参变量a是否为素数的函数正确的是( A )。

A、

int isprime(int a)
{int i
for(i=2;i<=a/2; i++)
if(a%i==0) returm 0;
return 1;}

B、

int isprime(int a)
{ int i;
for(i=2;i<=a/2; i++)
if(a%i==1) return 1;
return 0;}

C、

int isprime(int a)
{int i
for(i=2;i<= a/2; i++)
if(a%i==0) return 0;
else return 1;}

D、

int isprime(int a)
{int i
for(i=2;i<=a/2; i++)
if(a%i==1) return 1;
else return 0;}

【解析】判断一个整数a是否为素数,最简单的办法是用 a与2~a/2 之间的所有整数逐个求余,若存在任一个整数i,使得a%i= =0,说明存在整数是a的约数,那么认为a不是素数,否则a是素数。

选项B:判断a%i= =1时,认为a是素数,这是错误的;
选项C:认为只要存在一个整数使得a%!=0,则认为a是素数,换句话说,选项C认为2~ a/2之间只要有一个数不是a的约数,就认为是素数,这也是错误的,必须是2~ a/2之间所有的整数都不是a的约数,a才是素数;
选项D:认为2~a/2之间只要有一个整数i,使得a%i==1, 则认为a是素数,这也是错误的,比如15%7=1, 但15不是素数。答案为A。

#include <stdio.h>
double f(double x);
main(){
	double a=0;
	int i;
	for(i=0;i<30;i+=10) a+=f((double)i);
	prinf("%3.0f\n" ,a);
}
double f(double x)
{return x*x+1;}

程序运行后的输出结果是503。(✔)
【解析】本题重点考查函数的定义和调用。
第一次循环,a=0, i=0; 返回值a=0 * 0+1=1;
第二次循环,a=1, i=10; 返回值a=10 * 10+1+1=102;
第三次循环,a=102, i=20; 返回值a=20 * 20+1+102=503;
第四次循环,a=503, i=30; 不符合i<30,跳出循环,最后结果输出a=503。

5.4 循环的嵌套(191-193题)

#include<stdio.h>
main(
int i=1j.ch,sum=0;
for(i=S;i>=0;i-=2)
ch=j=1;
while(j<=i)
ch*=j++;
sum+=ch;
printf("%d\n" ,sum);}

程序运行后的输出结果是127。(✔)
【解析】程序为循环嵌套,当i=5时,ch=j-1,执行内循环while,ch的值为5!,累加到sum中;当i=3时,ch=j=1;执行内循环,ch的值为3!,累加到sum中。当i=1时,ch=j=1;执行内循环, ch=1!,累加到sum中,则sum=5!+3!+1!=127。

#include <stdio.h>
main(){ 
	int a[3]={0}, i,j,k=2;
	for( i=0; i<k; i++)
		for(j=0; j<k; j++) a[j] = a[i]+1;
printf("%d\n",a[1]);
}

程序运行后的输出结果是2。(✘)
【解析】该题首先初始化一维数组a[3]所有元素都为0;执行嵌套循环for语句。
当i=0、j=0时,a[0]-a[0]+1=1;
当i=0、j=1时,a[1]=a[0]+1=2;
当i=1、j=0时,a[0]=a[1]+1=3;
当i=1、j=1时,a[1]=a[1]+1=3。因此输出结果为3

#include <stdio h>
main(){
int i,j,x=0;
	for(i=0;i<2;i++){
		x++;
	for(j=0;j<=3;j++){
		if(j%2)continue;
			x++;
			}
				x++; 
				}
printf("x= %d\n",x);
}

程序执行后的输出结果是x=6。(✘)
【解析】continue的作用是跳出循环体中剩余的语句而进行下一次循环。
第一次执行外循环的值为0,执行x++,x值变为1。
        第一次执行内层循环的值为0,不满足if条件,执行x++ ,x的值变为2。
        第二次内循环j的值为1,if条件成立,跳出本次循环。
        第三次执行内循环的值为2,不满足if条件x的值变为3。
        第四次执行内循环,j的值为3满足条件跳出本次内循环,x的值加1,即为4。第一次外循环结束。
第二次执行外循环时同理,x的值被加了4次,变为8,所以x=8

5.4 循环的嵌套(194-195题)

do {
while (条件表达式1)
循环体A;
} while (条件表达式2);
while (条件表达式1)
do {
循环体B;
}
while (条件表达式2);

循环体A与循环体B的执行次数相同。(✔)

  1. do{*t++=*s++;} while(*s );不能将s所指字符串正确复制到t所指存储空间(✔)
    【解析】C语言中,字符串包含结尾的 ’ \0’ 字符,所以在拷贝字符串时需要将’ \0 ’ 字符也当作字符串的一部分拷贝,需要遍历s所指的字符串,逐个将字符串s中的字符(包括 ’ \0’ )一起复制到 t 中,然后结束循环。
    上述代码未能考虑到结尾的 ’ \0’ ,所以 ’ \0’ 未能复制到 t 中,这是错误的。

5.5 break语句和continue语句(196-198题)

  1. break语句只能用在循环体內和switch语句体内。(✔)

#include <stdio.h>
main(){
int i, j;
for(i=0;i<5;i++)
{
	for(j=1;j<10:j++) if(j==5) break;
		if(i < 2) continue;
		if(i > 2) break;
			printf("%d,", j);
}
printf("%d\n", i);
	}

程序运行后的输出结果是5,3(✔)
【解析】本题考核循环嵌套,内循环fo语句的循环体为if语句,当j==5时结束内循环。当结束内循环后。外循环中的取值可能为0,1,2,3,4。
当 i<2时,执行continue语句。
当 i>2时执行break语句结束循环。
当 i=2时,执行内循环for,j=5时内循环结束,判断 i 条件,条件不满足,打印输出的值为5。此时i自增至3,执行外循环循环体,因为i=3, if 条件 i>2 满足,执行break语句,退出外循环。打印输出i的值为3。

#include <stdio.h>
main()
{int a,b;
for( a=1,b=1;a<=100; a++ )
{ if(b>=20) break;
if(b%3==1) { b=b+3; continue; }
b=b-5;
}
printf("%d\n",a);
{

程序的输出结果是8。(✔)
【解析】首先注意for循环的控制条件:当b>=20或者a>100则跳出for循环,也即b<20且 a<=100时执行for循环。
第一次进入循环,a=1,b=1均满足循环条件,但b%3= =1条件满足,故执行b=b+3,得到b=4。注意有continue,所以后面语句不执行,直接跳转到a++这个语句,所以第一次循环完之后a=2,b=4;
第二次进入循环,b%3= =1也是满足的,故再次b=b+3,此轮循环执行之后a=3,b=7;
进入下一轮,此后和前面循环同理,都是b%3==1满足,因为每次都是加3,而之后又去模3,且都跳过for后面语句直接执行a++,所以,一直循环到b=22跳出for循环。此时a为8。
综合起来就是,每次循环b增加3,a增加1,且当b>22时跳出循环,结束程序。所以从1增加到22,有(22-1) /3=7。所以a=1+7=8。

第六章 数组

6.1 一维数组的定义和引用(199-206题)

  1. 要求定义一个具有6个元素的int型一维数组,以下选项中错误的是( A )
    A、int N=6, a[ N ];
    B、int a[2*3]={0};
    C、#defineN 3
    int a[ N+N ];
    D、int a[ ]= {1,2,3,4,5,6};
    【解析】数组名后面括号的值必须是整形常量,不可以是变量,A选项定义错误,答案为A选项。

  2. 设有如下程序段

int a[1]= {0};
int b[ ]= {9};
char c[3]= {"A","B"};
char d= "12";

以下叙述正确的是( A )
A、a, b的定义合法,c, d的定义不合法
B、a,b,c,d的定义都是合法的
C、a,b,c的定义是合法的,d的定义不合法
D、只有a的定义是合法的
【解析】int a[1]={0};表示定义一个数组a[1]初值为0。
int b[ ]= {9};表示定义一个数组b,其中只有一个值9, 系统自动识别数组有1个元素。
char c[3]= {"A", "B"};数组元素为字符串,需要用二维数组来表示,C选项错误;
char d= "12";字符串常量不能赋值给字符变量,D选项错误。

  1. 如果定义:float a[10], x;则以下叙述中正确的是( A )
    A、语句a= &x;是非法的
    B、表达式 a+1 是非法的
    C、三个表达式a[1]、* (a+1)、 * &a [1]表示的意思完全不同
    D、表达式* &a[1]是非法的,应该写成 *(&(a[1]))
    【解析】B选项中,数组名表示数组首元素地址,则a+1表示数组第二个元素的地址即&a[1],所以a+1不是非法的;
    C选项中, * (a+1)即指 a[1], * &a[1]也表示a[1],所以三者本质是相同的,都表示a[1];
    D选项中, * &a[1] 即a[1], 所以不是非法的。

  2. 数组下标可以使用实数。(✘)
    【解析】数组下标必须用整型、整型表达式、枚举型或字符型,不能是实型。

  3. 数组说明符的一对方括号中只能使用整型常量,而不能使用表达式。(✘)
    【解析】数组说明符的一对方括号中可以是整型常量,可以是整型常量表达式。

  4. 数组下标的下限是1。(✘)
    【解析】数组下标的下限是0。

#include <stdio.h>
main( )
{
inti,j= 0;
char a[] = "How are you!", b[10]= {0};
for (i=0; a[i]; i++)
if(a[i]=='')
b[j++]= a[i-1];
printf("%s\n", b);

程序运行后的输出结果是ay。(✘)
【解析】for语句循环体执行功能是,每次当a[ i ]元素为 ’ ’ (空格)时,将数组元素a[ i ]的前一个元素a[ i-1 ]赋值给b[ j ],赋值完成后,j值加1,因此a[i]的w和e分别赋值给b[0],b[1],输出结果为we

#include <stdio.h>
main(){
int s[12]={1,2,3,4,4,3,2,1,1,1,2,3},c[5]={0};
for(i=0; i<12; i++)
c[s[i]]++;
for(i=1;i<5;i++)
printf("%d ", c[i]);
printf("\n"); 
}

程序的运行结果是4322。(✔)
【解析】在for(i=0; i<12; i++) c[s[i]]++;中,数组元素s[ i ]的值作为数组c的下标,该for循环的功能是统计数组s中各个元素对应的个数,1有4个, 2有3个,3有3个,4有2个,所以当退出循环时,数组c的4个元素的值分别为4、3、3、2。

6.2 二维数组的定义和引用(207-217题)

#include <stdio.h>
main( ){
char b[4][10];
int i;
for( i=0;i<4; i++ )
	scanf( "%s",b[i] );
for( i=3;i>=0;i-- )
	printf( "%s ",b[i] );
	printf( "\n" ); 
}

执行时若输入: Peach flower is pink <回车> ,
则输出结果是pink. is flower Peach。(✔)
【解析】scanf函数以%s作为格式控制符输入字符串时,空格是作为间隔符的,所以第一个for循环对二维数组b初始化后,数组b中存放的每一行字符串依次是 “Peach”、“flower”、 “is”、 “pink”; 第二个for循环,从后向前倒序打印二维数组b的每一行字符串,因此,得到的答案是pink. is flower Peach。

  1. 以下选项中能正确定义二维数组的选项是
    A、double a[ ][3]={2*3 };
    B、double a[ ][3];
    C、double a[ ][3]={ };
    D、double a[2][3]{1.0},{2.0},{3.0,4.0};};
    【解析】如果第一维的长度没有指定,则定义的同时需要完成初始化,否则不知道分配多大的内存空间给它,所以选项B、C错误;
    二维数组a[2][3]中只有两个元素,都是维数组,一维下标最大只能是a[1],所以选项D错误;
    若完成初始化的二维数组,第一维的长度没有指定,则第一维的大小按如下规则确定: 若初值个数能被第二维大小整除, 所得的商就是第一维的大小,若不能整除,则所得的商加1作为第一维的大小, 所以选项A相当于: double a[1][3]= {6};其中a[0][0]=6, 其他元素赋值0,选项A正确,答案为A。

#include <stdio.h>
main( )
char b[3][10],c;
int i;
for (i=0; i<2; i++) scanf("%s", b[i]);
i=0;
while ((c=getchar())!='\n') b[2][i++]=c;
b[2][i]= '\0';
printf("%s%s%s\n", b[0],b[1],b[2]);
}

执行时若输入以下字符串:
Peach flower is pink.<回车>
则输出结果是Peachflower is pink。(✔)
【解析】scanf函数用"%s"格式输入字符串时,空格被作为间隔符,因此for循环输入b[0]=“Peach”, b[1]=“flower”,而while语句给b[2]赋值时,函数getchar()能识别获取空格符,因此b[2]=" is pink",最后用"%s"格式输出b[0]、b[1]、b[2]为Peachflower is pink。

  1. 若有定义:
    int w[3][5];
    则以下不能正确表示该数组元素的表达式是
    A、* (&w[0][0]+1)
    B、* ( * w+3)
    C、* ( * (w+1))
    D. * ( w+1 )[4]
    【解析】A选项中*(&w[0][0]+1)表示w[0][1];
    B选项中 * ( * w+3)表示w[0][3];
    C选项中 * ( * (w+ 1))表示w[1][0];
    D选项中 * (w+1)[4],其中w+1表示行指针移动到第二行,此时[4]表示行指针在原来的基础上继续移动4个单位,但是定义的数组只有3行,因此D选项不能正确表示该数组中的元素。选择D选项。

#include <stdio.h>
main ( )
{
int a[3][3]={{1},{2},{3}},*p[3],i;
for (i=0; i<3; i++)
{
	p[i]=a[i];
	a[i][i]=*p[i]+2;
}
for (i=2; i>=0; i--)
	printf("%d,",a[i][i]);
}

程序运行后的输出结果是3,4,5。(✘)
【解析】程序首先定义一个二维数组a,并对其初始化,初始化后,数组a的各个元素值分别为:a[0][0]=1,a[0][1]=0,a[0][2]=0,a[1][0]=2,a[1][1]=0,a[1][2]=0,a[2][0]=3,a[2][1]=0,a[2][2]=0,另外还定义整型指针数组p,通过第一个for循环,将a的三个数组元素的地址赋给p的对应元素,此时p[ 0 ] 指向a[0],p[1]指向a[1],p[2]指向a[2],接着将p所指向的数组的第一个元素值+2,赋值给数组a的对应主对角线上的元素,通过第一个for循环,a[0][0]=[0][0]+2=3, a[1][1]=a[1][0]+2=4,a[2][2]=a[2][0]+2=5,第二个for循环将a的主对角线上的元素逆序输出为5,4,3

#include <stdio.h>
void fun(int a[ ], int n, int flag){ 
int i=0,j, t;
for (i=0; i<n-1; i++)
for (j=i+1; j<n; j++)
	if(flag ? (a[i]<a[j]):(a[i]> a[j])
		{ t= a[i]; a[i]= a[j]; a[j]=t;}
}
main()
{int c[10]={7,9,10,8,3,5,1,6,2,4},i;
	fun(c,5,1);
	fun(c+5,5,1);
	fun(c+3,5,0);
	for (i=0;i<10; i++)
		printf("%d,"., c[i]);}

执行后的输出结果是 10,9,8,3,4,5,6,7,2,1。(✔)
【解析】函数fun是对数组进行插入排序,如果传入的flag值为1为降序,flag值为0是按照升序排列。
在main函数中,定义了10个元素的数组c,并初始化7,9,10,8,3,5,1,6,2,4。 调用语句fun(c, 5, 1);对数c前5个元素按照降序排列,排列后数组元素值为: 10,9,8,7,3,5,1,6,2,4。
再次调用函数: fun(c+5, 5, 1);,数组第6个元素开始按降序进行排序,排序后数组元素值为: 10,9,8,7,3,6,5,4,2,1。
再调用函数: fun(c+3, 5, 0);从函数第4个元素开始的后面5个元素按升序排列,排序后的数组元素值为: 10,9,8,3,4,5,6,7,2,1。for循环输出数组c的元素值。

#include <stdio.h>
main()
{ char v[4][10]; int i;
	for (i=0;i<4; i++)
		scanf("%s", v[i]);
		printf("%c,%s,%s,%c", *v[0],v[1],v[2]+2,*(v[3]+1));
}

执行时若输入: TEST OUR FINAL EXAMINE<回车>,则输出结果是T,OUR,NAL,X。(✔)
【解析】程序定义一个二维字符数组v,通过for循环,将v的四个元素分别赋值为四个字符串,v[0]、 v[1]、 v[2]、v[3]分别存放TEST、OUR、FINAL、EXAMINE,所以 * v[0]为 v[0]的第一 个字符T, v[1]是OUR, v[2]+2是FINAL第三个字符开始后的子串NAL, *(v[3]+1)是 EXAMINE第2个字符X。所以输出结果是T,OUR,NAL,X

#include <stdio h>
main( )
char b[4][10], c;
int ij;
for (i=0;i<4;i++) 
{ j=0;
while ((c=getcharO)!=' ' &&c!=^n) b[i][i++]=c;
b[][]= ^0';
prinf("%s%s%s%s\n", b[0], b[1], b[2], b[3]);

程序运行时从第一列开始输入:
Peach flower is pink <回车>
则输出结果是Peachflowerispink。(✔)
【解析】for循环的循环体中嵌套while循环,while循环的循环条件是判断键盘获取的字符不等于空格也不等于字符串结束标识符’\0’,所以for循环的作用是将Peach、flower、 is和pink分别存入二 维数组b的每一行中, 并且末尾加上字符串结束标识符’\0’,因此维数组b中依次存 放的是字符串"Peach"、“flower”、“is”、“pink” ,最后通过 %s格式控制符 , 将二维数组b中的四行字符串无空格连续输出

#include <stdio.h>
main()
{
char b[3][10]; int i;
for (i=0; i<2; i++)
	scanf("%s", b[i]);
	gets(b[2]);
printf("%s%s%s\n", b[0],b[1],b[2]);
}

执行时若从第一列输入:Fig flower is red. <回车>
则输出结果是Figflower is red.(✔)
【解析】scanf()函数:从输入设备按照指定的类型输入对应类型的若干个数据,遇到空格、制表符和回车时,读取结束。
gets()函数:从标准输入设备键盘上读取1个字符串( 可以包含空格),并将其存储到字符数组中去。此函数的读取结束符是换行符,即当遇到一个换行符时,就停止读操作,并且换行符不能够作为字符串的内容来存储,系统会自动用“0"来代替。
可知读到第一个空格时b[0]赋值结束,为Fig,读到第二个空格时b[1]赋值结束,为flower,退出for循环执行gets()函数,空格为有效字符,b[2]=" is red.",之后打印三个字符串。输出结果是Figflower is red.

  1. 若有以下程序段:
char str[4][12] = {"aa","bbb","cccc","ddddd"},*strp[4];
int i;
for( i=0; i<4; i++) strp[i]=str[i];

则以下错误引用字符串的选项是(其中0≤k<4)( A
A、strp
B、str[k]
C、strp[k]
D、*strp
【解析】 for循环实现将每个字符串的首地址赋给指针数组中每一个元素 。
strp为指针数组首地址,不是字符串的引用。
str[k] 为第k个字符串的地址, 表示第k个字符串的引用。
strp[k] 表示指针数组的第k个元素,为第k个字符串的地址,也是这个字符串的引用。
*strp 取指针数组第一个元素, 即为第一个字符数组的地址, 也即为第一个字符串的引用。 故选择A选项。

 #include <stdio.h>
main()
{ char a[3][10]={"efg","abcd","mnopq"};
char *p[3];
int i, k;
for(i=0;i<3;i++)
	{ p[i]= a[i];
	while (*p[])
	p[i]++;
	k= p[i]- a[i]: 
	printf("%c", *(a[i]));
	printf("%s", a[i]+k/2);
	}
}

执行后的输出结果是efgacdmopq。(✔)
【解析】main函数定义了字符串数组a,包含3个字符串。
当i=0时,p[0]=a[0],p[0]指向数组第1个字符串"efg",执行while循环直到p[0]为字符串结束标志结束循环,即p[0]指向第1个字符串的结束标志。因为a[0]指向第1个字符串的首字符,变量k=p[0]-a[0]=3,输出a[0]指向的字符e,输出字符串a[0]+3/2为字符串fg。
当i=1时,p[1]=a[1],p[1]指向数组第2个字符串"abcd",经过while循环,p[1]指向第2个字符串的字符串结束标志,因为a[1]指向第2个字符串的首字符,k=p[1]-a[1]=4,输出a[1]指向的字符a,输出字符串a[1]+k/2=a[1]+2为字符串cd。
当i=2时,p[2]=a[2],p[2]指向第3个字符串"mnopq";while循环后,p[2]指向第3个字符串的字符串结束标志。因为a[2]指向第3个字符串的首字符,变量k=p[2]-a[2]=5,输出a[2]指向的第3个字符串首字符m,输出字符串a[2]+5/2=a[2]+2,为字符串opq。

6.3 字符数组(218-245题)

  1. 字符数组a和b中存储了两个字符串,判断字符串a和b是否相等,应当
    使用if(strcmp(a,b)==0))(✔)
    【解析】C语言中,判断字符串是否相等,使用字符串比较函数strcmp(),如果函数strcmp(a,b)值为0,则表示a、 b两个字符串相等。

  2. 如果是十六进制数代表的ASCII符,应该以\x开头,而不是以\X\0x开头。(✔)

  3. char st[7]= "string!";在语法上是合法的,运行也是安全的。
    【解析】字符串实际占有单元的数量等于字符串长度+1。该字符串常量占8个字符,所以不能赋值在str[7]中。

  4. 字符串常量"Hello"会被隐含处理成一个无名字符型数组,它有5个元素。(✘)
    【解析】有6个元素,其中包括结尾字符。

  5. 不能用字符串常量对字符数组名进行整体赋值操作。(✔)

  6. 字符串数组,是指数组中的每个元素都是一个存放字符串的一维数组。(✔)

char str[] = "Hello";
printf("%d %d", sizeof(str), strlen(str));

则语句的输出结果是5 6。(✘)
【解析】本题考查sizeofstrlen对字符串的处理不同之处。
sizeof求出字符串的字符个数,包括结尾符。
strlen求出字符串的实际字符,不包括结尾符。所以答案为6 。

  1. 语句printf("%d\n",strlen("\t"\"\\\n\'\065\08AB"));的输出结果是10。(✘)
    【解析】字符串"\t"\"\\\n\'\065\08AB"中共有10个字符,分别是:\t ,", \, \n, ' ,\65 ,\0 ,8 ,A ,B。 而strlen()函数从字符串第一个字符开始扫描,直到碰到第一个结束符'\0'为止, 然后返回计数器值(长度不包含\0)。故输出结果为6

  2. 当拼接两个字符串时,结果字符串占用的内存空间是两个原串占用空间的和。(✘)
    【解析】当使用连接函数strcat时,内存空间会减少一个字符位置。

  3. C语言本身没有提供对字符串进行整体操作的运算符。(✔)

  4. 进行字符串复制时,目的串的存储空间必须足够大。(✔)

  5. 计算一个字符串的长度时,应包含串尾的结束标志。(✘)
    【解析】字符串需要包含串尾的结束标志,但是计算字符串长度时,不包含串尾的结束标志。

  6. 空字符串不占用内存,其内存空间大小是0。(✘)
    【解析】空字符串不包含字符,但包括字符结束符’\0’,其内存空间大小是1

  7. 两个连续的单引号('')不是合法的字符常量;两个连续的双引号(" ")是合法的字符串常量。(✔)
    【解析】两个连续的单引号不占空间,而字符常量是用单引号括起来的一个字符,占一个字节的内存空间;
    字符串常量是由一对双引号括起的字符序列,两个连续的双引号是空字符串,包含字符串结束符’\0’,是合法的字符串常量。

  8. 可以对字符串进行关系运算。(✘)
    【解析】C语言字符串比较不能直接用关系运算符进行正确比较,可以用字符串比较函数strcmp来实现。

  9. 以下语句中存在语法错误的是( A )。
    A. char ss[6][20]; ss[1]= "right?”;
    B、char ss[20]= { "right? "};
    C、char *ss[6]; ss[1]= "right? ";
    D、char *ss[]= { "right? "};
    【解析】数组定义后,不可以对数组整体赋值。
    s是二维数组,所以ss[1]是一维字符数组,即字符串,字符串赋值可以使用strcpy(ss[1],"right");这样的形式,而选项A中,ss是二维数组,对二维数组中的第1维(相当于一个一维数组)赋值,是不可以的。
    选项B和D是在定义数组的同时进行初始化赋值,这是可以的。
    选项C中,ss是指针数组,将字符串在内存中的首地址赋给指针数组的其中一个元素,这是可以的。

#include <stdio.h>
main(){
char s[]="012xy\08s34f4w2";
int i, n=0;
for( i=0; s[i]!=0;i++ )
if(s[i]>='O' &&s[i]<= '9') n++;
printf("%d\n",n);
}

程序运行后的输出结果是0(✘)
【解析】题意统计字符s中阿拉伯数字的个数。char s[]="012xy\08s34f4w2";元素是字符型。' 0 ' =48;而'\0'=0:因此可以计算出’\0’之前阿拉伯数字的个数,由字符串s可知,有3个阿拉伯数字。

#include <stdio.h>
main(){
char name[10]= {'S','T', ' R', 'T','N','G'};
name[3]= 'E'; name[5]= 0;
printf("%s\n", name);
}

程序运行后的输出结果是STREN0(✘)
【解析】printf函数按照格式符说明输出对应的数据。%s控制符用于输出字符串,输出时从给定地址开始依次输出字符,直到遇到’\0结束。给字符变量赋值0,相当于赋值’\0’。初始化时name=“STRING”,改动数组第4个和第6个元素之后字符串变为"STREN"。调用print输出字符串为STREN

#include <stdio.h>
main( )
char s[]=" abcde";
s+=2;
printf("%d\n",s[0]);

执行后的结果是输出字符c的ASCII码。(✘)
【解析】本题重点考查数组名的概念。在C语言中,数组名类似于一个指向数组首地址的指针常量,一旦定义就不能修改其内容。所以本题中的s+=2;语句让数组名s的内容加2是错误的,编译无法通过。因此程序出错

#include <stdio.h>
main()
{ char a[20], b[]="The sky is blue."; int i;
for(i=0;i<7; i++) scanf("%c", &b[i]);
gets(a);
printf("%s%s\n", a,b);
}

执行时若输入: (其中 < Enter >:表示回车符)
Fig flower is red. < Enter >
则输出结果是wer is red.Fig flo is blue.(✔)
【解析】程序首先初始化字符数组b[ ],执行for循环语句,循环变量的取值范围从0到6。在for循环语句中通过scanf函数将从键盘上输入的数据输入到b[ ]中,即b的值为Fig flo is blue.
退出for循环语句,执行语句gets(a); gets(函数的调用形式为:gets(str_ adr),其中str_ adr是存放输入字符串的起始地址,可以是字符数组名。字符数组元素的地址或字符指针变量。gets函数用来从终端键盘读入字符串(包括空格符),直到读入一个换行符为止,即a的值为wer is red.
所以输出结果是wer is red.Fig flo is blue.

  1. 若有定义语句: char str1[]="string" ,str2[8],*tr3, str4[10]="string";库函数strcpy的功能是复制字符串,strcpy(tr3, "HELLO!")是错误的函数调用。(✔)
    【解析】字符串拷贝函数strcpy
    格式:strcpy(字符数组1,字符串2)
    功能:把字符数组2,拷贝到字符数组1中去
    返值:返回字符数组1的首地址
    说明
    字符数组1必须足够大,至少大于字符串2;
    字符数组1必须是数组名形式(str1),字符串2可以是字符数组名或字符串常量;
    拷贝时’\0’一同拷贝。

  2. 字符串连接函数strcat(字符数组1,字符数组2)
    字符数组1必须足够大而且连接前,两串均以’\0’结束;连接后,串1的’\0’取消,新串最后加’\0’。(✔)

  3. 若有定义和语句:

#include <string.h>
char str1[ ]="Hello!", str2[8]="0",*str3=" stop",*str4=0;

则以下对函数strcat的运用正确的是( A )
A、strcat(str2,str1)
B、strcat(str1,st3)
C、strcat(str3,str1)
D、strcat(str4,str2)
【解析】 strcat函数的功能是将第二个参数所指字符串的内容连接到第一个参数所指的字符串后面,并自动覆盖第一个参数末尾的空字符”0’。所以第一个参数必须要有足够的存储空间来存放合并后的字符串。
str1有7个字节空间,存放空字符在内的7个字符;
str2有8个字节空间,存放1个空字符;
str3有5个字节空间,存放空字符在内的5个字符;
str4有0个字节空间。
选项A将str1的7个字符连接到str2中,8个字节刚好,正确;
选项B将str3的5个字符连接到str1中,连接后的新串占11个字节,存储空间不够,错误;
选项C将str1的7个字符连接到str3中,连接后的新串占11个字节,存储空间不够,错误;
选项D将str2的空字符连接到str4中,由于str4不占存储,所以也是错误的。

  1. 以下不能将s所指字符串正确复制到t所指存储空间的是( A )
    A. do{*t++= *s++;} while(*s);
    B、for(i=0;t[i]=s[i];i++);
    C、while(*t= *s) {t++= s++;}
    D. for(i=0,j=0;t[i++]=s[j++]; ) ;
    【解析】 A选项中当 * s值为 ‘\0’ 时,while( * s)会 跳出循环,这样字符串结束标志’\0’就没有复制给 * t,会造成 *t 不完整。
    注意: * t++=*s++是先执行 * t=*s, 然后再执行s++, t++。选项B、C、D都能将字符串结束标志’\0’复制过去。

#include <stdio.h>
main( )
{ char a[20], b[]="The sky is blue."; int i;
for (i=0; i<10; i++) scanf("%c", &a[i);
a[i]='\0';
gets(b);
printf("%s%s\n", a,b);
}

执行时若输入:Fig flower is red. <回车>
则输出结果是Fig flower is red.(✔)
【解析】本题考查字符数组的赋值以及字符串的处理函数,本题中输入字符串Fig flower is red时,首先是将前10个字符赋值给字符数组a,然后执行gets(b)后:将后续字符存放到b中当输出时,首先输出字符数组a然后输出字符串b。

 #include <stdio.h>
#include <string.h>
main()
{
char ss[10]="12345"; 
strcat( ss, "6789" );
gets( ss );
printf("%s\n", ss );

执行时输入: ABC<回车>, 则输出结果是ABC(✔)
【解析】gets(ss)读入一串字符串,直到遇到回车,读入的数据从数组的起始位置覆盖。数组s里的内容是ABC\056789\0,因此打印出ABC。

  1. 有定义语句: int i; char s1[10]. s2[10]= "Program";则能正确给s1数组赋字符串的语句是( A )
    A、for(=0; i<=7; i++) s1[i]=s2[i];
    B、s1=s2;
    C、while(s2) s1++ =s2++;
    D、for(i=0; s2[i];i++ ) s1[i]=s2[i];
    【解析】首先字符数组只有在初始化的时候整体赋值,否则只能对字符数组逐个赋值,所以选项B错误;
    另外字符数组名s1、s2是常量,不能改变,选项C错误;
    字符串"Program”包含结尾的’\0’,选项D中在处理到s2[i]=‘\0’时,跳出循环,未将’\0’赋给s1,所以选项D也是错误的;
    由于"Program"包含结尾的’\0’总共有8个字符,所以选项A是正确的。

第七章 函数

7.1 函数概述(246-251题)

  1. 若有代数式子√lnx+ exl(其中e仅代表自然对数的底数,不是变量),能够正确表示该代数式的C语言表达式是 sqrt(fabs(pow(n,x)+exp(x)))(✔)
    【解析】fabs()返回浮点数的绝对值,sqrt()是开根号,exp(x)代表ex

  2. C语言主要是借助定义函数实现程序模块化。(✔)

  3. 在C语言的函数内部,可以定义局部嵌套函数。(✘)
    【解析】关于函数的定义不可以嵌套,但函数的调用可以嵌套。

  4. 实用的C语言源程序总是由一个或多个函数组成。(✔)

  5. 返回基本数据类型的库函数的调用,均可以出现在赋值号右边的表达式中。(✔)
    【解析】函数的调用有两种形式:
    (1) 出现在表达式中,有可以出现在赋值号右边的表达式中
    (2) 作为独立的语句完成某种操作

  6. 在C语言中函数的实参个数可以有多个,各实参之间用分号隔开
    【解析】在C语言中函数的实参个数可以有多个,各实参之间用逗号分开。

7.2 函数定义的一般形式(252-259题)

  1. C语言中,函数声明的函数名、返回值类型和参数列表必须与函数定义相同,其中参数列表中可以省略参数名。(✔)

  2. 函数调用语句: fun( ( exp1, exp2 ),( exp1, exp2, exp3);含有的实参个数是5个。(✘)
    【解析】函数名后括号内的数据称为"函数参数”,其中列出的是各个参数的数据类型和名称。调用函数时,括号里面的实参应该与形参的个数 与数据类型一致。函数fun参数列表中有两个参数, 分别是逗号表达式(exp1, exp2)值与(exp1, exp2, exp3)值,所以实参个数有2个

254.有函数int fun(int a[4][5], int *n)…调用函数之前需要对函数进行说明,即所谓的函数向前引用说明,以下对fun函数说明正确的是( D )
A、int fun(int **a[6],int );
B、int fun(int a[4][ ], int *n);
C、int fun(int a[ ][5], int n);
D. int fun(int b[ ][5], int *);
【解析】根据函数定义可知,函数的两个形参类型分别为:整型二维数组、整型指针。对函数进行说明时,函数名、函数返回类型、形参个数以及形参类型都要与函数定义保持一致。
选项A中,两个形参类型不一致;
选项B中,二维数组作为形参可以省略第一个方括号中的常量表达式(行数), 不能省略第二个方括号中的常量表达式(列数) ;
选项C中,形参n是整型变量,和指针类型不一致,符合要求的只有选项D。

  1. 若有如下函数定义
double fun(int x,int y)
{ return (x+y); }

returm语句中表达式值的类型与说明的类型不一致,则编译出错。(✘)
【解析】题意中x+y是整型,函数的返回值是double类型,由于整型可以自动转换成double类型,所以函数的返回时整型自动转换成double类型

  1. 参数是数组类型,可以声明为指针类型;参数是整型指针变量,参数名可以省略。(✔)

  2. int fun() { }是空函数。(✔)
    【解析】空函数是函数体没有执行语句的函数。

  3. 对于函数声明void fun(float array[],int *ptr);以下叙述正确的是( A )。
    A、函数fun的参数array, ptr都是指针变量
    B、函数fun的参数array是数组名,ptr 是指针变量,它们有本质区别
    C、调用函数fun时,实参数组元素个数可以比形参array数组元素个数多
    D、调用函数fun时,传送给形参array的应是数组的所有元素
    【解析】 fun()函数两个参数: array和ptr, 返回值为void类型,其中array是float型数组名,ptr是整型指针变量。
    C语言中,数组名本身就是一个地址,作为形参时,数组名看作指针类型,所以array就是一个指针变量, 选项A正确,B错误;
    调用函数fun()时,实参数组元素的个数形参array数组元素个数应保持一致, 选项C错误;
    调用函数fun()时,传递给形参array的只是实参数组的首地址,并不是数组所有元素,选项D错误,本题答案为A。

  4. 有以下程序:

#include <stdio.h>
void fun(int a, int b)
{int t;
t=a; a=b; b=t;
}
main(){
int c[10]={1,2,3,4,5,6,7,8,9,0},i;
for(i=0; i<10; i+= 2) fun(c[i],c[i+ 1]);
for(i=0; i<10; i++ ) printf("%d, ", c[i]);
printf("\n"); 
}

程序的运行结果是2,1,4,3,6,5,8,7,0,9。(✘)
【解析】函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化,所以数组c中的元素的值并没有变化,结果是1,2,3,4,5,6,7,8,9,0
避免形参不能改变实参,可以利用指针解引用直接对实参进行操作。

7.3 函数参数和函数返回值(260-272题)

  1. 函数返回值可以整型、实型、字符型、指针和结构类型,也可以没有返回值。(✔)

  2. 没有retun语句的自定义函数在执行结束时不能返回到调用处。(✘)
    【解析】没有retun语句的函数在执行到函数的最后一条语句后会自动返回到调用处。

  3. 用户定义的函数中可以有多个return语句,以便可以调用一次返回多个函数值。(✘)
    【解析】本题重点考查函数返回值的相关知识,函数的值只能通过retrm语句返回主调函数,在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行,因此只能返回一个函数值。不返回函数值的函数,可以明确定义为"空类型",类型说明符为"void"。

  4. 函数调用必须传递实参。(✘)
    【解析】函数如果没有形参也就不必传递实参。

  5. 函数形参的类型与返回值的类型无关。(✔)
    【解析】函数参数有两种:形式参数和实际参数。
    形式参数:函数定义时函数名后括号内是形参列表,每个形参由类型和名称两部分组成。在定义函数时,系统并不给形参分配存储单元,当然形参也没有具体的数值,所以称它为形参,也称虚参。
    形参在函数调用时,系统暂时给它分配存储单元,以便存储调用函数时传来的实参。一旦函数结束运行,系统马上释放相应的存储单元。
    实际参数:实参函数调用时函数名后括号内是实参列表,实参可以是常量、变量或表达式。当函数返回到主调函数时,有时会有数据带给主调函数,也可以没有任何数据返回给主调函数,返回的数据称为函数的返回值。函数形参的类型与返回值的类型无关。

  6. int fun( int *p) { return *p: }
    fun函数返回值是形参p中存放的值。(✘)
    【解析】返回值为指针变量指向的数据,该数据已被定义为整型。因此fun函数返回值是一个整数

  7. 形参可以是常量、变量或表达式。(✘)
    【解析】函数中,形参必须是变量,实参可以是常量,变量或表达式。

  8. 实参的类型应与形参的类型赋值兼容,实参的个数应与形参的个数一致。(✔)

  9. 函数返回值可以是整个数组。(✘)
    【解析】函数的返回值可以是整数、实数、字符、指针、结构体或一个函数的地址等,但不能是整个数组,C语言中对数组的操作都是通过下标引用或指针,不能整体操作。

fun(void)
double d;
long t=rand();
d=t*0.618;return d;

则函数返回值的类型是double。(✘)
【解析】fun()函数中,使用rand()函数生成一个随机无符号整数,然后该无符号整数自动转换为long类型,赋给t,然后将 t 与0.618的乘积,将long自动转换为double类型,然后再运算,结果赋给d;当函数的返回类型为int类型时,可以省略函数的返回类型,由于fun()函数定义时,返回类型省略了,可知fun()函数的返回值是int类型
默认返回的是int类型,如果没有明确写出返回类型的话,默认为int类型。

main()
{.....x=fun(2,10);.....}
float fun(int a,int) { .....}

是错误的。(✔)

【解析】在调用子函数时,应对其进行说明。上述代码,调用时,没有对子函数进行说明。

#include <stdio h>
double fun(double s,double a,double b){
a= (int)(s); 
b= s-a;
return a+b;
}
main( )
{
double s=12.654,a=11,b=22;
printf("%5. 2lf,",fun(s,a,b));
printf("%5. 2lf,%5.2lf\n" ,a,b);
}

程序运行后的输出结果是12.00,12.00,0.65。(✘)
【解析】(1) 函数fun的功能是将参数s的整数部分赋给形参a,小数部分赋给形参b,然后返回a+b,所以可知fun函数返回值等于s;
(2) C语言的参数是按值传递,所以对形参值的修改不会影响实参。
(3)格式控制符%lf输出double类型的值,5.2表述输出宽度为5 (包含小数点),输出2位小数
综上,main函数调用函数fun,传入s,a, b时,返回值是s,输出12.65,输出a,b的值为:11.00,22.00

7.4 函数的调用(273-283题)

  1. 函数形参的值也可以传回给对应的实参。(✘)
    【解析】在C语言中,函数之间传值是单向的,只能实参传给形参,函数形参的值不可以传回去。

  2. 设有函数定义: void sub(int k,char ch){ .. }则以下对函数sub的调用语句中,正确的是( A )。
    A、sub(1,97);
    B、sub(2,‘97’);
    C、n=sub(3,‘a’);
    D、sub(4,“a”);
    【解析】函数的参数有两个,第一个是整型,第二个是字符类型,在调用函数时,实参必须一个是整型,一个是字符型。
    A选项中97为字符’a’的ASCII码,可以作为字符传入函数,A选项正确。
    B选项’97’不是合法字符,字符单引号里面只能有一个字符,B选项错误。
    C选项函数sub返回类型为空,即不返回任何值,故C选项中将函数返回值赋给是不正确的调用方法,C选项错误。
    D选项"a"为字符串,也不是合法的字符,D选项错误。

  3. 设有函数说明: void fun(int a[], int m);和定义语句: int a[10],n,x;且变量均已正确赋值,则下面调用该函数的语句正确的是( C )。
    A、fun(a[10],10);
    B、x=fun(int a,int n);
    C、fun(a,n);
    D、x=fun(a[ ],n);
    【解析】从定义语句可知,数组a为10个元素的数组数组下标为0~9,选项A中函数的调用为a[10]发生溢出。因为函数fun的类型会void没有返回值,选项B、D中用变量x接收函数fun的返回值,错误。选项C中,函数的调用是正确的。本题答案为C选项。

  4. 函数"说明”是指利用它在程序的编译阶段对调用函数的合法性进行全面检查。(✔)

  5. void类型的函数中不可以出现return语句。(✘)
    【解析】void类型的函数没有返回值,为了在函数体的任意地方退出,可以使用return语句,只是return后不用加返回值。

#include <stdio.h>
#include <string.h>
void fun(char p[],int m,int n) 
{
int i;
	for(i=0;i<n-m;i++)
		printf("%c",p[i]);
	for(i=-1;i>= m-n;i--)
		printf("%c",p[i]);
}
main()
{
char d[10]={'H','E','L','L','O','!'};
int 1;
for(i=0;i<5;i+=3)
fun(d+i,strlen(d+i),strlen(d));
printf("\n"); 
}

程序运行后的输出结果是LO!LEH。(✔)
【解析】参考解析: [解析] 在main函数for循环中,i=0时 ,strlen(d+i)=strlen(d)=6, 即函数调用为fun (d,6,6) ,进入函数fn内部,
m=n=6,m-n=0,不输出。
当main函数i=3时,strlen(d+3)=3,strlen(d)=6, 函数调用为fun(d+3,3,6),进入到fun函数内部,m=3,n=6; d+3指向第4个字符L即p指向第4个字符;
第1个for循环输出字符L、O和!。
第2个for循环m-n=-3, 循环条件成立,因为p指向第4个字符,p[-1]为第3个字符L,p[-2]指向第2个字符E,p[-3]指向第1个字符H。

#include <stdio.h>
int m=1,n=2;
void sub1(int m,int n)
{ m+=2; n++; }
void sub2( )
{ m++; n+=2; }
main( ){
printf("%d,%d,",m,n);
sub1(4,5);
printf("%d,%d,",m,n);
sub2();
printf("%d,%d\n",m,n);
}

程序运行后的输出结果是1,2,6,6,7,8。(✘)
【解析】全局变量与函数体内局部变量同名时,局部变量会覆盖全局变量,因此在sub1()函数内,全局变量m, n是不可见的,在sub1()对m,n操作的是局部变量,对全局变量不产生影响。
但在sub2()函数内,由于没有和全局变量变量重名,因此在此函数内,m,n是可见的。
因此,第一个printf()打印的是全局变量m, n,故打印的是1, 2;
第二个printf(),调用sub1()没有修改全局变量m,n,故打印的是1,2;
第三个printf(), 之前调用了sub2(),修改了全局变量m, n,打印的是2, 4。
程序运行后的输出结果是1,2,1,2,2,4

#include <stdio.h>
int f(int n);
main(){
inta=3,s;
s=f(a); s=s+ f(a); 
printf("%d\n",s);
}
int f(int n){
static int a= 1;
n+=a++;
return n;
}

程序运行后的输出结果是8。(✘)
【解析】题目中静态局部变量a,在静态存储区内分配存储单元,在程序整个运行期间都不释放。
所以第一次调用函数执行n+=a++;时先与n相加在再进行自增。n的值为4, a的值为2,且a变量执行完后空间没有释放。再执行s=s+ f(a)时,s的值为4,调用f(a)函数时n的返回值为n=3+2=5, s=s+f(a)=4+5=9, 且此时a的值变成3,程序最后输出s的值9

 #include <stdio.h>
int f(int n){
int t=0,a=5;
if(n/2) {int a=6; t+=a++; }
else {int a=7;t+= a++; }
return t+ a++;
}
main(){
int s=0, i=0;
for(;i<2;++) s+= f(i);
printf("%d\n", s);
}

程序运行后的输出结果是24(✔)
【解析】当i=0时。执行"s+=f(0);"语句,调用0并将的初值0传递给形参n。首先执行if语句中内条件: n/2,条件为假。则执行else下的语句,a=7;t=7+0=7, 使用return返回t,t=7+(a++)=7+5=12;返回主函数中,s=0+12=12。
当=1时循环继续,执行"s+=f(1);"语句,调用f()并将i的初值1传递给形
参n。变量t和a再一次赋初值,首先执行if语句中的条件: n/2, 条件仍为假,执行i下面的语句,t=0, a=7,t=0+7=7,使用return返回t, t=7+5=12, 返回主函数中,s= 12+12=24。最后输出的结果为24。

#include <stdio.h>
int fun (int x)
{ int y;
y=x++;
return y;
}
main()
{ int k;
for(k=0; k<3; k++) { printf ( "%d,", fun(k)+k); k++; }
}

执行后的输出结果是0,4(✔)
【解析】 fun()函数的功能是将参数x的值赋给y,然后x自增1,返回y的值,所以fun()的返回值与实参值相同;main()函数的for循环中,k的初值为0,执行printf语句时,输出fun(0)+0, 结果为0;接着执行两次k++,此时k的值为2,循环条件k<3满足,继续执行printf()函数,输出fun(2)+2, 结果为4;接着再次执行2次k++, k为4,不满足循环条件,程序运行结束,所以程序输出结果为: 0,4,

7.5 函数的嵌套调用与递归调用(283-285题)

#include <stdio.h>
int fun(int a[],int k)
{
if(k==0) return (a[0]);
return a[0]+fun(a+1,k-1);
}
main(){
int a[]={1,2,3,4,5};
printf("%d\n", fun(a,3));
}

执行后的输出结果是10(✔)
【解析】数组名当参数时,退化为指针类型,所以形式参数a是指针;函数fun是一个递归函数,当传入的形参k=0时,返回指针a指向的元素的值,当k>0时,返回指针a指向的元素的值与fun(a+1, k-1)函数返回值之和,而fun(a+1, k-1)函数返回值等于指针(a+1)指向的元素的值与fun(a+2, k-2)的返回值之和…直到传入的k值为0;
所以当main函数中传入fun(a, 3)时,返回值为: (k=3) 指针a指向的元素的值a[0]+ (k=2) 指针(a+1)指向的元素的值(a+1)[0]+ (k=1) 指针(a+2)指向的元素的值(a+2)[0]+ (k=0) 指针(a+3)指向的元素的值(a+3)[0],将指针转换为数组,即a[0]+a[1]+a[2]+a[3], 结果为10。

#include void fun(int n, int *s)
int f1, f2;
if(n==1||n== 2) *s= 1;
else{
fun(n-1, &f1);
fun(n-2, &f2);
*s=f1 + f2;
}
main(){
int x;
fun(6, &x);
printf("%dn", x);
}

程序运行后的输出结果是2。(✘)
【解析】题意中,函数fun的第二个参数通过指针作为函数返回值,它的功能是通过递归,求得fun(n)的值为fun(n-1)+ fun(n-2),由于当n取值为1,2时,值为1,所以可知整个数列如下: 1,1,2,3,5, 8…即某一项是前两项之和, 所以当n取值为6时,fun(6, *s)返回s的值为3+5=8

 #include <stdio.h>
void get_ put(){
char ch;
ch = getchar();
putchar(ch);
if(ch!= '\n') get_put();
putchar('.');
}
main(){
get_ put();
}

程序运行时,输入1234<回车>, 则输出结果是 (✔)

1234
....

【解析】main()函数调用get_put()函数,get_put()函数首先调用getchar()读入一个字符,然后调用putchar()输出该字符,输出字符后判断该字符是否为’\n’,若不是换行符,那么递归调用自身,继续读入字符并输出,若是换行符,输出,函数运行结束;对于题意中的输入"1234<回车>“,由于前面四个字符"1234"都不是换行符,所以递归调用自身,输出"1234”,对于<回车>字符,即’\n’, 输出该字符后,接着输出,由于递归层级为4层,所以最后输出四个'.')。

7.6 数组作为函数参数(286-293题)

  1. 若使用局部一维数组名作函数实参。在被调函数的参数列表中,必须给出形参数组的大小。(✘)
    【解析】数组作为形参时,退化为指针,不必要指明数组的大小。当数组作为实参,必须是已经定义的数组并指定大小。

  2. 函数FindMin的形参a所指数组中只存放正整数,函数的功能是查找数组中最小值,并作为函数值返回

#define MAX 2147483647
int FindMin(int a[], int n)
{ int i, min;
min=____
for( i=n-1;i>=0;i-- )
if(min>a[i]) min=a[i];
return min; 
}

程序中下划线处是给变量min赋初值,以下选项中错误的是( A )。
A、0
B、MAX
C、a[0]
D、a[n-1]
【解析】查找数组中最小的数,需要遍历整个数组,在遍历过程中需要记录当前扫描过的元素中的最小值,本题中使用min记录当前的最小值;因为FindMin中形参a所指数组只存放正整数,所以数组元素中的最小元素都大于0,若初始化min为0,则程序返回结果始终为0,这是不正确的,初始化min时可以设置min为最大值MAX,或者遍历数组时的首尾元素,选项B、C、D正确,答案选A。

#include <stdio.h>
int fun(int a].int n,int x)
int* p= =a;
while( p<a+n && *p!=x ) p++;
if(p<a+n) return p-a;
else return -1;
mainO
int
a[10]={1.2.3.4.5.6.7.8.9.10}; 
printf("%dn",fun(a,10,10));

程序运行后的输出结果是9(✔)
【解析】while( p<a+n && *p!=x) p++:p-a;n=10,x=10;while循环条件成立, 直到p=a+9, 结束循环,执行下一条语句,if条件成立,返回p-a, 此时执行p-a=a+9-a=9;因此,输出9。

#include <stdio.h>
int fun( char s[])
{
char *p=s;
while( *p!=0) p++;
return(p-s );
}
main(){
printf("%d\n",fun("0ABCDEF") );
}

程序运行后的输出结果是7(✔)
【解析】本题考查字符串作为函数参数以及while语句,本题中传入字符串"0ABCDEF",然后执行fun后,就得到了该字符串中字符的个数,其中while循环判断条件 * p != 0等价于 * p !=‘0’,所以不包括结束标识符0’,该字符串有’0’、‘A’、 ‘B’、 ‘C’、‘D’、‘E’、'F’共7个字符。

#include <stdio.h>
int f(int a[], int n){ 
if(n > 1)
{ int t;t=f(a, n-1);
return t > a[n-1] ? t : a[n-1];
}
else
return a[0];
}
main()
{ int a[= {8,2,9,1,3,6,4,7,5};
printf("%dn",f(a,9));
}

则程序的输出结果是8(✘)
【解析】本题主要考查了函数的递归调用,解题思路只需要将参数带入函数中,首先是执行f(a,9),递归执行(a,8)直到(a, 2),得到a[0]=8,然后判断a[0]是否大于a[1],本题实际上就是求出数组a元素的最大值。答案为9

#include <ctype.h>
#include <stdio.h>
long fun( char s[]){
long n; int sign;
for( ; isspace(*s); s++);
	sign=(*s=='-')?-1 : 1;
if(*s=='+'||*s=='-') s++;
for( n=0 ; isdigit(*s); s++)
	n=10*n+(*s-'O');
	return sign*n;
}
main(){
	char s[]="-26a3";
	printf("%dln ",fun(s));
}

程序运行后的输出结果是-26(✔)
【解析】isspace( c )检查参数c是否为空格字符,也就是判断是否为空格(’ ‘)、水平定位字符(’\t’)、归位键(‘\r’)、换行(’\n’)、垂直定位字符(’\v’)或翻页(’\f ')的情况。若参数c为空格字符,则返回TRUE,否则返回NULL(0)。

isdigit( c )函数检查参数c是否为阿拉伯数字0到9。返回值若参数c为阿拉伯数字,则返回TRUE,否则返回NULL(0)。
fun()函数的第一个for循环判断字符串是否负号。第二个for循环获取符号后面的数字字符,并将它们转化为整数。遇到了非数字的字符跳出,最后返回数组的结果。因此,可知首先获取负号,紧接着获取数值26,遇到了字符a,跳出返回-26,因此打印的结果是-26

#include<stdio.h>
#include <stdlib.h>
void fun( int *p1, int*p2, int*s){
s=( int*)calloc(1,sizeof(int));
*s=*p1+*p2;
free(s);
}
main(){
int a[2]={1,2},b[2]={40,50},*q=a;
fun(a,b,q);
printf("%d\n",*q);
}

程序运行后的输出结果是1(✔)
【解析】本题考查把数组名作为函数参数,执行fun函数后,s的值并没有发生变化,仍然是指向a,所以输出结果为1。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fun1(char*);
void fun2(double*);
main()
{ void *p;
p=malloc(8);
fun1((char *)p);
fun2((double*)p);
printf("%sin".(char*)p);
}
void fun1(char *p){ 
strcpy(p,"Hel1o");
}
void fun2(double *p){
char *q;
q=(char *)p;
strcpy(q,"World");
}

程序运行的结果是Hello(✘)
【解析】使用malloc申请的内存为void*类型。使用时,可以转换为其他数据类型。在main函数中p指向malloc申请的内存的空间。
调用函数fun1,将其转换为char * 类型,在函数 fun1内赋值为字符串Hello。
调用函数fun2,将其转换为double *类型,在fun2函数内又将其转换为char *,并赋值字符串World,这块空间的值为字符串World

7.7 全局变量与局部变量(294-303题)

  1. 在一个函数内的复合语句中定义的变量在本函数范围内有效。(✘)
    【解析】在一个函资数内的复合语句中定义的变量在本复合语句块范围内有效。

  2. 丞数的形参是局部变量。(✔)

  3. 在函数外定义的变量是全局变量。(✔)

  4. 全局变量和局部变量不能同名。(✘)
    【解析】若全局变量和局部变量同名,则在该函数内,此全局变量会被屏蔽,在该函数内访问的是局部变量,与同名的全局变量不发生任何关系。

  5. 全局变量是在函数外部任意位置上定义的变量。(✔)

  6. 用extern说明符可以限制全局变量的作用域。(✘)
    【解析】在不同编译单位内用extern说明符来扩展全局变量的作用域,extern可以将全局变量作用域扩展到其他文件,而不是限制全局变量的作用域。

  7. 未经赋值的全局变量值不确定,未经赋值的auto变量值不确定,未经赋值的register变量值不确定,未经赋值的静态局部变量值为0。(✘)
    【解析】C语言中,系统将未经赋初值的全局变量默认为0

  8. 在一个c源程序文件中所定义的全局变量,其作用域由具体定义位置和extern说明来决定范围。(✔)

  9. 在函数外部定义的变量在所有函数中都有效。(✘)
    【解析】全局变量有效范围是从定义的位置开始到所在源文件的结束,在这区域内的函数才可以调用,如果在定义函数之后,定义的变量,该变量不能被之前的函数访问。

#include <stdio.h>
int a = 1;
int func(int a){ 
int b= 1;static int c = 1;
a++; b++;++c;
return a+b+c;}
main()
{ int k, a = 4;
for(k=0; k<3; k++)
printf("%d," , func(a));
}

程序执行后的输出结果是9,10,11
【解析】程序定义一个全局变量a,初值为1,main()函数中定义局部变量a,初值为4,由于在局部作用域,局部变量会屏蔽全局变量,所以for循环中调用func()函改时,传入的a是局部变量,值为4。func()函数中,参数a的值为4,另外定义局部变量b,初值为1,静态局部变量c,初值为1,然后将局部变量a、局部变量b、静态局部变量c自增1,再将自增后的值累加后返回,由于静态局部变量只在定义时初始化一次,后续for循环再次调用时,都是使用上一次的值。
所以for循环中,k=0时,返回值为a+b+c=5+2+2=9,k=2时,返回值为a+b+c=5+2+3=10,k=3时,返回值为a+b+c=5+2+4=11,程序输出9,10,11

7.8 变量的存储类别(304-316题)

  1. 以下与存储类别有关的四组说明符中,全部属于静态类的一组是( A )。
    A、extern和static     B、auto和static
    C、register和static     D、register和extern
    【解析】auto变量用来声明函数中的局部变量,是动态的分配存储空间的,选项B错误;
    register关键字用来声明放在CPU的寄存器中的局部变量,不属于静态分配存储空间,选项C、D错误;
    extern用来声明外部变量,外部变量即全局变量,存放在静态存储区;
    static用来声明静态存储变量,存放在静态存储区,选项A正确。

  2. C语言的寄存器变量位于内存,因此可以求地址。(✘)
    【解析】register变量 又称为寄存器变量,用register说明的变量建议编译程序将变量的值保留在CPU的寄存器中,所以register变量没有地址,不能对它进行求地址运算。

  3. 将函数内的局部变量说明为static存储类是为了限制其他编译单位的引用
    。(✘)
    【解析】 将函数内的局部变量说明为static存储类,是为了只在第一次调用该函数时才对其初始化,后续调用时使用上一次调用结束后的值;函数体内的局部变量无论是否声明为static,外部编译单位都不能引用。

  4. 函数中的静态变量其所占内存在函数退出后不被释放。(✔)

  5. C程序函数中定义的赋有初值的静态变量,每调用一次函数, 赋一次初值。(✘)
    【解析】函数内的静态变量,只在第一次调用时候赋值, 以后调用保留上次值。

  6. C程序函数中定义的自动变量,系统不自动赋确定的初值。(✔)
    【解析】自动变量未赋初值,为随机值。

  7. 用egister说明的变量被强制保留在CPU的高存器中。(✘)
    【解析】register变量只是建议编译器将其值保存在寄存器中,而不是强制性的。

  8. static变量定义的变量,未初始化时,在程序运行时,首先将这四个变量赋值为0。(✔)

#include<stdio.h>
int *fun(){
static int a[2]={0,1};
a[0]+=a[1]; .
a[1]+=a[0];
return a;
}
void main(){
int i,*b; .
for(i=1;i<5;i++)
b=fun();
printf("%d %d ",b[0],b[1]);
printf("n");
}

程序的运行结果是1 2 1 2 1 2 1 2。(✘)
【解析】题意中,fun()函数定义一个静态数组a,它包含两个整型元素,然后将两个元素的和赋给第一个元素,再将两个元素的和赋给第二个元素,同时将数组a的指针当做返回值返回; main()函数中,在for循环中4次调用fun()函数,并输出返回的两个元素;由于a是静态数组,所以4次调用中,只有第一次调用时初始化为0、 1,后续调用时,a的元素值都是上一次调用后的值,所以=1时,输出1、2; i=2时,输出3、5;i=3时,输出8、13;i=4时,输出21、34;本题答案为1 2 3 5 8 13 21 34

 #include <stdio h>
int a=4;
int f(int n){
int t= 0;
static int a=5;
if(n%2) {int a=6; t+=a++; }
else {int a=7; t+=a++; }
}
return t+ a++;
main(){
int s=a, i=0; 
for(;i<2;i++) s+= f();
prinf("%d\n", s);
}

程序运行后的输出结果是31。(✘)
【解析】在主函数main()中定义了两个变量s和i,同时给赋初值。a=4, 现赋初值0。
当i=0时:执行s+=f(0); 语句,调用f()并将的初值0传递给形参n。首先执行if语句中内条件: n%2,若 条件为假。则执行else下的语句,a=7,t=7+0=7,
使用return返回t, t =7+(a++)=7+5=12,此时a运算完后自增1,变为6;返回主函数中,s=4+12=16。
当i=1时:执行s+=f(1); 语句,调用f()并将的初值1传递给形参n。首先执行i语句中的条件: n%2,条件为真,执行i下面的语句,t=0, a=6,t=0+6=6,使用return返回t, t=6+6=12, 返回主函数中,s= 16+12=28。最后输出的结果为28

#include <stdio.h>
int a=5;
int func(int a)
{ int b=1;
static int c=5;
a++;b++;++c;
return(a*b*c);
}
main()
{ int k, a=4;
for(k=0;k<3;k++)
printf("%d," func(a));
}

程序执行后的输出结果是60,70,80(✔)
【解析】首先程序中有一一个全局变量a,初值为5,在main()函数中,局部变量a屏蔽全局变量a,同样,在func()函数中,形参a也屏蔽全局变量a;另外func()函数中,c是静态局部变量,只会初始化一次, 后续使用时,c的值是上一次调用函数后c的值,综上,main()函数中:
当k=0时,实参a=4, func()函数的形参a=4, b=1, c=5, 自增后形参a=5,b=2, c=6, 返回值为60,输出60;
当k=1时,实参a=4, func()函数的形参a=4, b=1, c=6,自增后形参a=5,b=2, c=7,返回值为70,输出70;
当k=2时,实参a=4, func()函数的形参a=4, b=1, c=7,自增后形参a=5, b=2, c=8,返回值为80,输出80。

  1. 设有定义和语句(假设short int型数据占2字节)
short int  * pi, * pj;
pi=pj=(short *)malloc(2);

pi和pj分别指向了一个short int型存储单元。(✘)
【解析】语句pi=pj=(short *)malloc(2);首先使用动态分配函数malloc分配2个字节的内存空间,然后将内存首地址转换为short *类型并返回,赋值给pj,再将pj的值赋给pi,所以指针pi和pj的值是相同的,指向同一个short int型的存储单元

#include <stdio.h>
int a=3;
int func(int d)
{ int b=4,f;
static int c=5;
{ int c=6;
a--;b--;--c; --d;
f= a+b+c+d;
}
return f+c;
}
main( )
{ int k, a=4;
for(k=0;k<3;k++)
printf("%d," func(a--));
}

执行后的输出结果是18,16,14(✔)
【解析】程序定了全局变量a=3,在main函数定义了局部变量a=4。
for循环中,当k=0时,调用func (a- -),形参d=4,局部变量a=3。
在func函数中,定义局部变量b=4, f,以及静态局部变量c=5。
在复合语句中定义局部变量c=6,屏蔽静态变量c,执行a--;b-;--c; --d;后,全局变量a=2,局部变量b=3,局部变量c=5,形参d=3,变量f= a+b+c+d =13,函数返回值为f+c=13+5=18,此处变量c为局部静态变量。
当k=1时,调用func (a- -),形参d=3,局部变量a=2。在func函数中,局部变量b=4,静态变量c保留上次的值为5。在复合语句中定义局部变量c=6,屏蔽静态变量c,执行a--;b-;--c; --d;后,全局变量a=1,局部变量b=3,局部变量c=5,形参d=2,变量f= a+b+C+d=11,函数返回值为f+c=11+5=16,此处变量c为局部静态变量。
当k=2时;调用func (a- -),形参d=2,局部变量a=1。在func函数中,局部变量b=4,静态变量c保留上次的值为5。在复合语句中定义局部变量c=6,屏蔽静态变量c,执行a--;b-;--c; --d;后,全局变量a=0,局部变量b=3,局部变量c=5,形参d=1,变量f= a+b+c+d=9,函数返回值f+c=9+5=14,此处变量c为局部静态变量。

第八章 指针

8.1 关于地址和指针(317-331题)

  1. p=f可以让函数指针p指向一个同类型的函数f。(✔)
    【解析】函数指针可以指向一个同类型的函数。

  2. 所有指针变量如果未赋初值,则自动赋空值NULL。(✘)
    【解析】未赋初值的指针变量自动赋任意地址值。

  3. 可以取变量的地址赋值给同类型的指针变量。(✔)
    【解析】在计算机内存中,用一个字节表示一个内存单元并为每一个存储单元编号 ,这个编号就是存储单元的“地址”。一个变量的地址称为该变量的“指针”。专门用来存放变量地址的变量,称为“指针变量”。

  4. 可以取常量的地址赋值给同类型的指针变量。(✘)
    【解析】常量存储在编译文件中,不能取地址。

  5. 所有类型的指针变量所占内存的大小是一样的。(✔)
    【解析】专门用来存放变量地址的变量称为“指针变量",所有地址值所占字节都是一样的, 故指针变量所占内存大小一样。

  6. 指针变量之间不能用关系运算符进行比较。(✘)
    【解析】指向同一数组的两指针变量进行关系运算可表示它们所值数组元素之间的关系。

  7. 如果企图通过一个空指针来访问一个存储单元,将会得到一个出错信息。(✔)

  8. p = NULL;p = 0;p = '\0'是等价的。(✔)

  9. 无论指针变量p具有何种基类型,表达式p=p+1都代表指针p移动一个字节。(✘)
    【解析】 指针自增或自减1,移动的字节数与指针变量指向的具体类型有关,假设指针变量p指向的是int类型,那么p=p+1表示指针p移动4个字节(通常int类型占4个字节)。

  10. 指针变量具有基类型,基类型不同的指针变量不能直接相互赋值。(✔)

  11. 在程序的开头包含头文件stdio.h后,可以给指针变量赋NULL值。(✔)

  12. 将一个指针变量中的值赋给另一个指针交量,则这两个指针指向同一地址。(✔)

  13. 通过强制类型转换可以将一种类型的指针变量赋值给另一种类型的指针变量。(✔)

  14. 可以取一个指针变量的地址赋值给基类型相同的指针变量。(✘)
    【解析】可以取一个指针变量的地址,但是指针变量的地址属于指针,只能赋值给指针类型的指针变量。

  15. 可以取一个表达式的地址赋值给同类型的指针变量。(✘)
    【解析】表达式的值存储在临时变量中,内存中存在专门用来存储临时变量的区域,对这块地址进行操作也是没有意义的,C语言不允许这样做,编译会出错。

8.2 变量的指针和指向变量的指针变量(332-344题)

  1. 函数指针p指向一个同类型的函数时,必须写成: p= &f。(✘)
    【解析】函数指针p指向一个同类型的函数时,可以写成: p= f而不能写成&f。

333.指针p指向一个数组时,必须写成: p=&f。(✘)
【解析】函数名代表函数的入口地址,指针p指向一个数组时f,可以写成: p=f, 也可写成&f,数组名f,可以代表数组的首地址。

#include <stdio.h>
main( ){
char* p1=0;
int* p2=0;
float* p3= 0;
printf("%d,%d,%d\n", sizeof(p1), sizeof(p2), sizeof(p3));
}

程序运行后的输出结果是1,4,8。(✘)
【解析】sizeof ()函数表示求该变量所占字节空间,同时一个指针变量占用4个字节长度,因此输出为4,输出结果是4,4,4

  1. %lf, %le是 针对double的,如果仅用%f,输入的数据可能不能被完全接收,数据的精度可能不足。%f主要针对float类型变量的输入。(✔)

  2. 两个指针可以通过加运算求和,形成一个功能更强大的指针。(✘)
    【解析】指针只能与一个整数进行运算,即移动指针,两个指针不能运算。

  3. 设有定义:int x=2,*p=&x;float y=3.0; char z='c';,则立即进行以下运算有安全隐患的是( A )。
    A、p++;    B、x++;  C、 y++;  D、z++;
    【解析】由于x是一个整形变量,将地址赋值给p指针后,A选项中p++对指针p进行加1运算,p指针的值相当于加4(整型变量的地址占4个字节),此时p指向了未知的内存地址,对未知内存地址进行操作具有安全隐患,故答案为A选项。

  4. 以下程序段完全正确的是
    A、 int * p; scanf(“%d”,&p);
    B、int * p; scanf(“%d”, p);
    C、int k, *p=&k; scanf(“%d”,p);
    D、int k,*p;*p=&k; scanf(“%d”, p);
    【解析】 A选项中错在没有对指针进行初始化,无效指针,并且在scanf(“%d”,&p)中无需再进行取地址操作;
    B选项中没有对指针进行初始化,无效指针;
    D选项中语句 * p=&k;的左端 * p是指针所指内存空间的值,&k是地址,应为p=&k。指针初始化的同时可以直接赋值,所以语句int * p=&k;是合法的,C选项正确。

  5. 设已有定义: float x;,则以下对指针变量p进行定义且赋初值的语句中正确的是( )。
    A、 int *p=(float)x;     B、 float *p= &x;
    C、float p= &x;           D、 float *p= 1024;
    【解析】 指针是用来存放地址的变量,用 (类型名 * 指针变量名) 的形式定义。赋值时应将某个变量地址即&x赋给指针变量,所以选择B。
    int *p = &a; //初始化一个int * 类型指针,同时将变量a的地址存入p指针
    这里是一个特殊用法,仅在初始化变量的时候可以使用,应分为两个部分去进行理解。
    int *p; //初始化一个int * 类型指针p
    p = &a; //将变量a的地址存入p指针,此时p表示变量a的地址
    *p = a; //表示指针p指向变量a,这时 * p表示变量a的数值

  6. 指针的运用可使程序代码效率更高。(✔)

  7. 基类型不同的指针可以直接相互赋值。(✘)
    【解析】 把一个指针变量的值赋给另一个指针变量, 但定要确保这两个指针变量的基类型是相同的。

  8. 若定义void *p;,则p可以保存任何内存地址。(✔)
    【解析】void *为无类型指针,使用时,可以强制转换为任意的指针类型。

  9. 若定义char *p=" ";,则p保存的数值是0。(✘)
    【解析】 p中存放的是字符串首地址。

  10. 已定义以下函数: .

void fun (char *p2, char *p1)
{ while ((*p2= *p1) !='\0')
{p1++; p2++; } 
}

函数的功能是将p1所指字符串复制到p2所指内存空间。(✔)
【解析】fun()函数接收两个字符指针p2、p1, while循环每次将p1指向的字符赋给p2指向的字符,然后判断p2指向的字符是否是空字符’\0’,若不是,p1和p2顺序后移一位,直到p1和p2指向空字符,所以fun()函数的功能是将p1指向的字符串赋值到p2指向的内存空间中。

8.3 数组与指针(345-356题)

  1. 第4题:若有定义语句: int a[10]={0,1,2,3,4,5,6,7,8,9},*p=a;以下选项中 错误引用a数组元素的是(其中0≤i<10)
    A、 * ( *(a+i))
    B、a[p-a]
    C、p[i]
    D. * (&a[i])
    【解析】 * p-a,将数组a的首地址赋给指针p。a+i表示数组a中第个元素的地址,引用其中元素为 * (a+i),A选项引用错误。
    p-a=0,B选项引用的元素为a[0]。
    C选项中p [ i ]表示p后i个地址的元素a[ i ]。
    D选项中&a[i]取a[ ]地址, *(&a[i])取这个地址内的元素,即为a[i]。本题选择A选项。

  2. 设有定义: int a[10],*p=a,k;
    以下为数组a的10个元素依次读入数据的程序段中错误的是( C )
    A、for(k=0; k<10;k+ +) scanf(“%d” ,p++);
    B、for(k=0; k<10;k++) scanf(“%d” ,a+k);
    C、for(k=0; k<10;k+ +) scanf(“%d”,a++);
    D、for(;p-a<10; p++) scanf(“%d”,p);
    【解析】题意定义一个整型数组a,它包含10个整型元素,另外定义一个整型指针p;将数组的首地址赋给p,选项C中,a++是错误的,因为a是数组名,它是一个常量,不能执行自增运算,选项A、B、D都可以对数组a的10个元素完成赋值,本题答案为C。

  3. 设有以下说明和语句: int a[3][4],(*p)[4]; p=a;则与表达式*(*p+2)等价的选项是( A )
    A、a[0][2]   B、 * (a+2)[0]   C、 * (*a+2)[0]   D. a[2][0]
    【解析】 (*p)[4]是数组指针,指向含有4个int元素的一维数组,为二维数组首地址,赋值给数组指针p。
    题目中表达式*(*p+2)是对数组a第1行第3列元素的引用。
    a[0][2]是数组第 1行第3列元素,与题目中等价,A选项正确。
    *(a+2)[0]是对数组第3行第1列元素的引用,B选项错误。
    (*a+2)[0]是对数组第1行第3列元素的引用,C选项错误。
    a[2][0]是数组第 3行第1列元素,D选项错误。

  4. char p[]={'1','2','3'},*q=p; 以下不能计算出一个char型数据所占字节数的表达式是( C )
    A、sizeof(*q)   B、sizeof(char)   C、sizeof( p)   D、sizeof(p[0])
    【解析】变量p, q均是指针,因此sizeof( p)=4.而*p,*q,p[0]的类型都是char, 因此长度为1,故A、D选项均正确。
    选项B直接计算char的字节数也正确,故答案为C选项。

  5. 有以下程序段:int m[2][3],(*p)[3]; p=m;则以下对m数组元素的引用正确的是( C )
    A、(p+1)[0]   B、* ( * (p+2)+1)   C、*(p[1]+1)   D、p[1]+2
    【解析】数组元素a[ i ][ j ]可表示为*(a[i]+j),因此,在定义数组m和指针变量p后,* (p[1]+1)表示指向数组m[1][1],因此答案为C选项。

#include <stdio.h>
main( )
{ int a[10]={0},i=0,*p=a;
while( p<a+9 )
{ *p=++i;
p+=2;
}
for(i=0; i<9;i++)
printf("%d ",a[i]);
print("\n");
}

执行后的输出结果是1 0 2 0 3 0 4 0 5(✔)
【解析】main()函数首先定义一个整型数组a,它包含10个元素,元素值都是0,定义整型变量,初值为0,定义整型指针p,指向数组a,接着通过while循环,使用指针p对数组a中下标为偶数的元素赋值++i,所以while循环执行完后,a[0]=1、a[2]=2、 a[4]=3、 a[6]=4、 a[8]=5, 其他元素保持0值。

 #include <stdio.h>
main()
{
int a[10]={ 11,12,13,14,15,16,17,18,19,20 },*p=a,i=9;
printf( "%d,%d,%d\n",a[p-a], p[i],*(&a[i]));
}

程序运行后的输出结果是11,20,20。(✔)
【解析】*p=a,将数组a的首地址赋给指针p。p-a=0, 待输出变量为a[0]。p[i]表示p后i个地址的元素,待输出变量为a[9]。&a[i]取a[i]地址, *(&a[i])取这个地址内的元素,待输出变量为a[9]。最后输出为11,20,20

#include <stdio.h>
int *f(int *s)
{ s+=1;
s[1]+=6;
*s++ += 7;
return s;
}
main( )
{ int a[5]= {1,2,3,4,5},*p=a;
p= f(p);
printf("%d,%d,%d,%d", a[0], a[1], *p, p[1]);}

程序执行后的输出结果是1,2,1,2。(✘)
【解析】main()函数首先定义一个整型数组a,它包含5个元素1,2,3,4,5,定义整型指针p,指向数组a,将p传给f()函数; f()函数接收整型指针s,此时s指向数组a的第一个元素1, 语句s+=1将s指向下一个元素2,此时s[1]的值是3,语句s[1]+=6表示将数组a中第三个元素的值累加6,此时s[1] (即a[2])的值为9。语句*s++ += 7表示将s指向的元素2累加7,此时s[0] (即a[1])的值为9,再将s指向下一个元素,此时指向数组a中的元素3,最后函数将指针s返回赋给p,执行完f()函数的调用后,p指向数组第三个元素a[2];此时a[0]的值为1,a[1]的值为9,*p (a[2])的值为9,p[1] (a[3])的值为4,所以本题答案为1,9,9,4

#include <stdio.h>
main( )
{
int a[]= {2.4.6.8}.*p=a, i
for(i=0;i<4;i++)
a[i]=*p++; 
printf( "%d\n" ,a[2] );
}

程序的输出结果是8。(✘)
【解析】本题通过语句"*p=a”将一维数组a的首地址的值赋值给指针变量p, 即*p的值为2。执行for循环,a[i]=*p++,将*p的值赋给a[i]后,指针p再进行++操作,即指针p向后移动一个元素。
当i=0时,a[0]=*p.然后p++;移动后p指针指向元素a[1];
当i=1时,即a[1]=*p++此时p指针指向元素a[2];
以此类推,可知for循环中语句a[i]=*p++ 并没有改变数组a的值,因此a[2]的值是6。

#include <stdio.h>
main(){
char *wk[7]={"Mon.","Tus.","Wed.","Thur.","Fri.","Sat.","Sun."};
char wk1[7][6]={"Mon.","Tus.","Wed.","Thur.","Fri.","Sat.","Sun."};
printf("%d %d %d %d\n",sizeof(wk),sizeof(*(wk+3)),sizeof(wk1),sizeof(*(wk13)));
printf("\n");
}

假设在32位编译器下,程序运行后的输出结果是28 4 42 6(✔)
【解析】wk为字符指针数组,指针占用4个字节,数组包含7个元素,所以sizeof (wk) =28
*(wk+3) 指向第4个字符串"Thur."的指针,指针占用4个字节,sizef(*(wk+3))=4
字符数组wk1包含7个元素,每个元素有6个字符,一共位42个字节,sizeof(wk1)=42
*(wk1+3)为第4行字符数组,一共包含6个元素, 6个字节,sizeof(*(wk1+3))=6.

#include <stdio.h>
main( ){
char v[4][10]={"efg"," abcd"," mnopq","hijkl"}.*p[4],t;
int i,j; 
for (i=0;i<4; i++)
p[i]=v[i]:
for(i=0;i<3;i++)
for (j=i+1;j<4;j++)
if(*p[i]> *p[j])
{ t= *p[i]; *p[i]= *p[j]; *p[j]=t;}
for (i=0;i<4; i++)
print("%s ", v[i]);
}

程序执行后的输出结果是abcd efg hijkl mnopq。(✘)
【解析】程序首先定义二维字符数组v,使用四个字符串初始化,另外定义字符指针数组p,通过第一个for循环,将v的四个字符串的首地址赋给p,第二个for循环通过两层内嵌循环将p中元素指向的字符串首字母进行排序交换,规则是:将指向的字符串的首字母字符按照字母表中的顺序排序后交换,注意,这里交换的是首字母,而不是整个字符串,所以程序输出: afg ebcd hnopq mijkl

#include <stdio.h>
#include <stdlib. h>
void fun( double *p1,double *p2,double *s)
{ s= (double *)calloc( 1,sizeof(double) );
*s=*p1 + *(p2+1);
}
main()
{ double a[2]={ 1,1,2,2 }, b[2]={ 10.0, 20.0}, *s=a;
fun(a,b,s);
printf( "%5.2f\n", *s);

程序的输出结果是21.1(✘)
【解析】本题考查把数组名作为函数参数,执行fun函数后, s的值并没有发生变化,仍然是指向a,所以输出结果为1.10

8.4 字符串与指针(357-384题)

char str[4 ][ 12 ]={"aaa","bbb","ccc","ddd" },*p[4];
int i;
for( i=0; i<4; i++ ) p[i]=str[i];

以下选项中不能正确引用字符串的是( A )
A、*p[3]    B、p[3]    C、str[2]    D、*p
【解析】*p[3]是一 个字符,不是字符串,选项A错误。p[3]str[2]*p分别代表了ddd,ccc,aaa, 答案为A选项。

  1. char *ps[]= {"aa", "b", "cc", "dd"};
    则以下叙述正确的是( A )
    A、*ps[0]是字符a    B、*ps[0]是字符串”aa”
    C、ps[0]是字符’a’    D、ps是字符串"aa"
    【解析】指针数组ps[ ]定义后,ps[0]代表数组首个元素的地址, 即"aa”的地址,同时也是"a"第一 个字符a的地址,所以*ps[0]代表字符a,答案为A选项。

  2. 设有定义:char *c;
    以下选项中能够使c正确指向一个字符串的是( A )
    A、char str[ ]=“string”; c=str;
    B、scanf(“%s”,c);
    C、c=getchar( );
    D、*c=“string”;
    【解析】A选项为正确用法,先将字符串存于字符数组中,然后将数组名赋给字符指针。( 数组名代表数组首地址,定义数组时为其分配确定地址)。
    C选项错误,getchar( )函数输入字符给字符型变量,而不是字符指针。
    B选项和D选项有类似的错误,两个选项并无语法错误,但运行时可能会出现问题。因为在B选项和D选项中,字符指针没有被赋值,是个不确定的值,指向一个不确定的内存区域,这个区域可能存放有用的指令或数据。在这个不确定的区域重新存放字符串,可能会发生无法预知的错误。因此A选项正确。

  3. 以下选项中正确的语句组是( B )
    A. char *s; s={“BOOK!”};
    B、char *s; s=“BOOK!”;
    C、char s[10]; s=“BOOK!”;
    D、char s[ ]; s=“BOOK!”;
    【解析】A选项去掉大括号就正确了; C选项和D选项应在定义时赋初值。因此B选项正确。

  4. 以下能正确定义字符串的语句是( B )
    A、char str=“\x43”;
    B、char str[ ]=“\0”;
    C、char str=’ ‘;
    D、char str[ ]={’\064’};
    【解析】C语言中,字符串是用一对双引号括起来的字符序列,并用字符型数组来存放,故C选项和D选项不属于字符串,A选项定义的是一个字符变量str,却用来存放字符串,显然也不正确,因此B选项正确。

  5. char str1[10] = "computer", str2[10]; str2= str1;会出现编译错误。(✔)
    【解析】不能将两个字符数组直接互相赋值。

  6. C语言字符串必须包含'\0'字符,用来表示字符串结束标志。(✔)

  7. 两个字符串中的字符个数相同时才能进行字符串大小的比较。(✘)
    【解析】字符串比较大小是以第1个不相同字符的大小为标准的,跟长度没有关系。

  8. 空串比空格打头的字符串小。(✔)
    【解析】空串的长度为0,而以空格打头的字符事的长度至少为1。

int aaa(char *s)
{
char *t=s;
while(*t++);
t--;
return(t-s);
}

aaa函数功能是求字符串的长度。(✔)
【解析】本题重点考查的知识点while循环语句的应用。aaa()函数中,首先定义了一个字符指针指向形参s,然后通过一个while循环让指针t不断递增,直到指向字符串结束标识处。当指向结束标识处时,由于后缀+ +运算符的原因,它还会被再递增1,所以接下来的–;语句让它回到结束标识处。最后返回t-s,s还是指向字符串第1个字符处,而t指向了字符串结尾,故返回值为字符串的长度值。

  1. 下列函数的功能是将所指字符串赋给b所指空间。(✔)
void fun(char *a,char *b){
while((*b=*a)!="\0)
{ a++; b++;}

【解析】 While循环条件为: (*b=*a)!='\0'; 执行时先把指针a所指向的字符赋给指针b所在内存单元,如果该字符不是结束标识’\0’,执行循环体a++;b++;指针a、b分别指向下一个字符单元。再判断循环条件,如果成立,继续把指针a所指向的字符赋给指针b所在内存单元,直到遇到结束标识为止。

  1. strlen函数统计字符串长度,遇到’\0’统计结束。(✔)

  2. char str[]= "string", *ps; *ps= str;是错误的。(✔)
    【解析】定义了指针ps后,*ps表示指针ps指向地址的内容,是取值而不是地址,所以*ps = str无法将数组st的首地址赋给一 个非地址值,语法错误应该改成ps=str 。

  3. sizeof()求数组a所占空间的大小,包括字符串最后的’ \0’。(✔)

#include <stdio.h>
main()
{ char str[ ]={"123456"};
str++;
printf( "%c\n", str[1]);
}

程序编译或运行时将会输出字符3(✘)
【解析】程序中定义了字符数组str, str是字符数组名,它是一个常量,不能执行自增运算。因此会产生错误信息

  1. char* str = "0\n0123\4";printf("%d", strlen(str));程序输出结果是7。(✔)
    【解析】该字符串中的字符分别
    是: ‘0’、‘n’、‘0’、1’、2’、‘3’、‘4’、’\0’。 其中 \4表示菱形符号’◆’ ,除了“0’,其他字符都属于strlen()函数的计算字符,结果为7。

#include <stdio.h>
void fun(char *a,char *b){
char *s=a;
while(*s) s++;
s--;
while(s>=a)
{ *b=*s;s--; b++; }
*b='\0';
}
main(){
char s1[]=" abc",s2[6];
fun(s1,s2);
puts(s2);
}

程序运行后的输出结果是cba。(✔)
【解析】函数fun()实现的功能是:将第一个参数指向的字符串逆序的赋值给第二个参数,fun()首先循环至第一个参数的末端,再从后至前,循环的赋值给第二个参数,因此第二个参数里的内容和第一个参数内容的逆序。因此结果是cba。

  1. \01是一个转义字符。(✔)
#include <stdio.h>
#include <string.h>
void fun(int a[ ],char *b){
int size,len;
size=sizeof(a);
len=strlen(b);
printf("size=%d len=%d\n" ,size,len);
}
void main( ){
int size,len;
int a[20]={1,2,3};
char s[]="a1b2c3d4e5f6g7";
size=sizeof(a);
len=strlen(s);
prinf("size=%d len=%d\n",size,len);
fun(a+2,s+7);
}

程序运行后的输出结果是
size=20 len=14
size=18 len=7(✘)
【解析】因为int a[20]={1,2,3};变量size=4x20=80;
因为char s[]="a1b2c3d4e5f6g7";变量len=14。 输出变量size和len的值。
在main函数中接着调用函数fun,实参为a+2, s+7, 因为数组名表示的是数组的首地址,则形参a为数组a的第3个元素“3”的地址,形参b为数组s第8个元素“4”的地址,则 len=strlen (b) =7。 因为形参a指针类型,占用4个字节,所以函数fun内变量size=4,打印输出变量len和size。所以输出结果为:
size=80 len=14
size=4 len=7

#include <stdio.h>
main(){
{
char s[10]="verygood", *ps=s;
ps+=4;
ps="nice";
puts(s); 
}

程序的运行结果是nice(✘)
【解析】将字符指针变量初始化为一个字符串有两种方式:
其中的一种通过赋值运算使一个字符指针指向一个字符串常量: char *ps;ps="nice"这种形式只是将字符串"nice"首地址赋给指针,而不是将指针原本指向的单元元素改变成"nice"。 程序执行过程为:定义字符数组并且初始化为"verygood",定义指针ps使其指向数组,使ps指向数组第5个元素,使指针指向字符串"nice",这并不影响s数组任何元素值,故输出字符串s为verygood

#include <stdio.h>
#include <string.h>
void fun(char *s){
int i=0;
while (s[i]!='\0') s[i++]= getchar();
}
main(){
char t[80]="yes!";
fun(t);
puts(t);
}

程序运行时输入: Good_ luck!<回车>, 则输出结果是yes!。(✘)
【解析】题意中函数fun的功能是读入字符串,逐个存放到s指向的存储单元,直到遇到空字符为止; main函数定义字符数组t,它包含80字节存储空间,存放字符串"yes!", 所以从第5个字符开始,后续字符默认都是空字符,调用函数fun,将t传入,由fun函数对t中的前4个字符重新输入(第5个字符是空字符),再将新输入的字符串输出,所以输出结果为输入的前4个字符,当输入为Good_ luck! 输出为: Good

#include <stdio.h>
int disp(char* str){
while (*str) putchar(*str++);
return *str;
}
main()
{
printf("%d\n", disp("NAME"));
}

程序运行后的输出结果是NAME。(✘)
【解析】 程序执行过程为:调用函数disp,将字符串“NAME首地址传给指针st,在while循环中,依次判断字符串中字符是否为’\0’,不是’\0’则输出字符,否则结束循环。当(*str)=‘\0’时 ,结束循环,返回字符’\0’的ASCII码0,并输出。程序运行后的输出结果是: NAME0。

#include <stdio.h>
main()
{ char str[80]="one start", *ps=&str[3];
scanf("%s" ,ps);
printf("%s\n",str);
}

程序运行时输入: two end<回车>,则运行结果是onetwo。(✔)
【解析】程序main()函数定义一个字符数组str,并使用"one start”初始化,另外定义字符指针ps,指向st的第四个字符,即空格符,然后调用scanf()函数,从ps指向的位置开始读入一个字符串,题意输入“two end",由于scanf()函数输入字符串时,遇到空格输入结束,所以本题中ps指向的位置只接收了“two"字符串,覆盖了原str中的“s”,并在字符o后面添加字符串结束符”0",所以str中的字符串为: “onetwo\0rt”, print函数 只输出”0’前的字符,所以输出字符串:“onetwo"。

#include <stdio.h>
int fun(char*p){ 
if(*p==0) return 0;
fun(p+1);
putchar(*p);
return 0;}
main()
{ char ch[ ]="ABCD";fun(ch);}

程序运行后的输出结果是BCD。(✘)
【解析】fun()函数是递归函数,当形参p指向的字符不是空字符’\0’(ASCII码为0)时,递归调用fun(p+1),然后输出*p,由于putchar()函数在递归调用自身语句之后,所以函数的功能是逆序输出p指向的字符串;main()函数中,ch指问的字符串为"ABCD",所以程序输出结果为:DCBA

#include <stdio.h>
void fun(char *a,char b){ 
while(*(a++)!='\0');
while(*(a-1)<b)
*(a--)=*(a-1);
*(a--)=b;
}
main(){
{ char s[8]="pmfc" ,c;c=getchar( );
fun(s,c);puts(s);
}

程序运行时输入:k<回车>,则输出结果为pmkfc(✔)
【解析】main()函数定义一个字符数组s,使用字符串"pmfc”初始化,然后通过getchar()读取一 个字符k到字符变量c,然后将字符串s和字符c传入fun()函数,函数fun()首先通过while()循环遍历字符s,直到指针a指向字符串结束符’\0’后的一个字符,如下图所示:
在这里插入图片描述

接着通过while()循环逆序遍历字符串s,首先a-1 (字符’\0’)的ASCII码0小于b (字符K)的ASCII码107, 那么将’\0’赋给下标为5的位置,接着继续向前遍
历,同理;将’c’ (ASCII码99)赋给下标为4的位置,将f (ASCII码102)赋给下标为3的位置,由于’m’ (ASCII码109)大于b,所以循环结束,将b (字符K’)赋给下标为2的位置,此时st字符串如下:
在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <ctype.h>
void fun(char p[ ]){
int len;
len=strlen(p);
while(*p){
	if(isupper(*p))  tolower(*p);
		else if(islower(*p))  toupper(*p);
	else (*p)++; 
	p++;
	}
}
void main( ){
char a[20]="Ab1Cd2eF3";
fun(a);
puts(a);
}

程序运行结果是aB1cD2Ef3。(✘)
【解析】 函数fun()的功能为:判断当前字符,如果当前字符为大写字母,调用tolower函数, 如果当前字符为小写,字母,调用toupper函数, 需要特别注意的是这里调用tolower、toupper函数并没有 改变*p的值,只是调用执行了一下函数,并没有返回值所以字符不改变; 如果是其他字符,此字符ASCII值加1。在main函数中,定义了字符串a= “Ab1Cd2eF3”,所以调用函数fun后,字符串改变为“Ab2Cd3eF4"。

#include <stdio h>
int fun(char *s,char *t){
int c=0;
char *p.*q; 
while(*s){
p=s;q=t;
while(*p && *q && *p++ == *q++);
if(!*q) c++;
s++;
}
return c;
}
void main(){
char *str1="celebration meeting",*str0= "ti";
printf("%d\n".fun(str1 ,str0));
}

程序执行后的输出结果是2。(✔)
【解析】 fun()函数的功能是以第二个字符串作为第一个字符串的子串, 判断第一个字符串含有几个子串。
首先将两个字符串首字母地址传给对相应的形参,将第一个第二 个字符串的首字母地址分别赋给p; q, 为计数变量,当第一个字符串中的字母跟第二个字符串中的字母相同时,两个指针都加一,即都往后移动位继续比较,直到第二个字符串的指针为空指针,即第二个字符串结束,此时代表找到第一个子串, c加1,然后第一个字符串的指针继续往后加一,第二个字符串的指针回到第一个,继续比较。输出结果是2

#include <stdio.h>
#include <string.h>
void fun( char *s, int m1, int m2 ){
char t, *p; 
p=s+m1; s= s+m2;
while( s<p )
{t=*s; *s=*p; *p=t; s++; p--;}
}
main(){
char ss[10]="012345678";
int n=6;
fun( ss,0,n-1 );
fun( ss,9,n); 
fun( ss,0,9 );
prinf("%s\n", ss );
}

程序运行后的输出结果是012345(✔)
【解析】 fun(*ss, m1, m2 )的作用是,如果m1>m2交换数组元素ss[m1], ss[m2]。
因此,fun(ss,0,5)后ss的0,1,2,3,4,5,6,7,8,\0
fun(ss,9,6) 后ss的0,1,2,3,4,5, \0,8,7,6。
fun(ss,0,9)后ss的0,1,2,3,4,5,\0,8,7,6。 因此打印结果012345

8.5 指向函数的指针(385-386题)

  1. 设有定义语句: int(*f)(int);f是指向函数的指针变量,该函数具有一个int类型的形参。(✔)
    【解析】int(*f)(int); 为指向函数的指针变量的定义方法,其中为指向函数的指针变量,第一个int为函数返回值类型,第二个int为函数的形参类型。

386.设有函数说明语句: int fun(int,int);
以及函数指针定义语句:int (*f)(int,int);
若要使函数指针指向函数fun的入口地址,以下选项中正确的是( C )
A、f=fun( );    B、*f=fun;    C、f=fun;    D、*f=fun();
【解析】C语言中,函数名也是一个指针,是函数的入口地址,所以要使函数指针f指向函数fun的入口地址,直接将函数名fun赋给即可,本题答案为C。

8.6 返回指针的函数(387-389题)

  1. 设有某函数的说明为: int* func(int a[10], int n);说明中的a[10]写成a[ ]或*a效果完全一样。(✔)

#include <stdio.h>
int* sum(int data)
{
static int init= 1;
init += data;
return &init;
}
main( ){
int i,*p;
for (i=1;i<=3; i++) sum(i);
p= sum(1);
printf("%d\n", *p);
}

程序运行后的输出结果是7。(✘)
【解析】 static定义一个静态分布变量,变量只会初始化一次。在for函数的循环体中调用sum (i)函数,循环3次,每次都把值累加在init中,再执行计1操作,因此,退出循环后,init=1+1+2+3=7, 再执行次sum(1),init=8后, 把init的地址赋给指针p,输出指针p指向的init的值,答案为8

#include <stdio.h>
int *f(int *s,int *t)
{ if(*s< *t)
*s=*t;
return s;
}
main({
int i=3,j=5, *p=&i, *q=&j, *r, 
r=f(p,q);
printf("%d.%d,%d.%d,%dn",i,j, *p, *q,*r); 
}

程序的运行结果是3,5,3,5,5。(✘)
【解析】程序执行过程为: p指向i, q指向j,调用函数f,将与j地址传递给s与t,判断堤否小于j,成立则将j=5赋值给i,则i=5,返回指向的指针并赋给r,则指向j,最后输出5,5,5,5,5

8.7 指针数组和指向指针的数组(390-392题)

  1. 若有说明语句: int *ptr[10];ptr是一个具有10个指针元素的一维数组,每个元素都只能指向整型变量。(✔)

  2. 若有定义,inta=3,*p=&a, **q=&p; 则以下叙述中错误的是( A )。
    A、q是指针变量,* q就是变量a
    B、p是指针变量, p指向变量a
    C、q指向变量p,所以* q指向变量a
    D、*p与 * *q都代表变量a
    【解析】由题意可知:指针变量p指向变量a, p的值是a的地址;指针变量q指向变量p, q的值是p的地址,所以q是指针变量,g指向p,*q是变量p,选项A错误;
    p也是指针变量,p指向a,选项B正确;
    由于g指向p,所以*q指向a,选项C正确;
    *p**q都是代表变量a,选项D正确,本题答案为A。

#include <stdio.h>
main()
char s[3][5]={{'G','O','O','D';'-'},{'M','O','R','N','T'},{'N','G','!'}}; 
int i;
for(i=0;i<2;i++)
printf("%s ",*(s+i));
printf("\n");
}

程序运行后的输出结果是GOOD-MORNING!。(✘)
【解析】在C语言中,二维数组是连续存放的,格式控制符 %s输出字符串时,遇到字符串结束标志字符0"结束。
在main函数的for循环,当i=0时,s+0指向数组第一行,第一行没有字符串结束标志,继续输出第二行,直到第三行,所以输出“GOOD-MORNING!“;
当=1时,s+1指向数组第二行,第二行数据没有字符串结束标志,输出第3行,输出为“MORNING!”。本题答案为GOOD-MORNING!MORNING!

8.8 指针作为函数参数(393-399题)

#include <stdio.h>
void sub(double a,double *pb);
int main()
{
double x,y;
scanf("%lf%lf" ,&x,&y);
sub(x,&y);
printf("x= =%f y=%fn",x,y);
}
void sub(double a,double *pb){
a=a-*pb;
*pb=*pb-a;
}

程序运行时输入: 10.2 3.5<回车>, 则输出结果为x=6.700000 y=-13.00000。(✘)

【解析】sub()函数接收两个参数: double类型变量a, double指针变量pb,首先将与pb指向的变量值相减,结果存放a中,然后再将pb指向的变量值与a的新值相减,结果存放pb指向的内存空间。sub函数不会修改实参x的值,但会修改实参y的值,当输入10.2 3.5时,实参x的值为10.2,y的值为3.5,执行sub()函数后,x的值不变,y的值变成-3.2,本题答案为x=10.200000 y=-3.200000

#include <stdio.h>
void sp(int *a){ 
int b=2;
*a=*a* 2; printf("%d,",*a);
a=&b;*a =*a*2;
printf("%d,",*a);
}
main(){ 
int k=3;sp(&k);
printf("%d\n", k);
}

则程序的输出结果是6,4,3。(✘)
【解析】首先在主函数中给整型变量k赋值为3,调用sp函数,将变量k的地址作为实参传递给形参指针变量a;在sp函数中,*a=*2*2;即结果为6,通过printf()函数输出。整型变量b的地址赋给指针变量a,再执行*a=22;,即结果为4,通过printf()函数输出。返回主函数,输出k的值6。因此输出结果为6,4,6

#include <stdio.h>void f(int *p,int *q);main)
{
int m=1,n=2,*r=&m;f(r, &n);
printf("%d,%d" ,m,n);}
void f(int *p,int *q){
p=p+1;*q=*q+1;}

程序运行后的输出结果是2,3。(✘)
【解析】在f(int *p.int*q)函数中,执行p=p+1是将p所对应的地址加1,而*q=*q+1是将q所指向的的地址所对应的值加1,所以m的得知所对应的值没有变,而n的值则为3了。因此输出结果是1,3

#include <stdio.h>
void fun( int *a,int *b)
{ int*c;
c=a,a=b;b=c;
}
main(){
int x=3,y=5, *p=&x, *q=&y ;
fun(p.q); printf("%d,%d,",*p,*q); 
fun(&x ,&y); printf("%d,%d\n",*p,*q);
}

程序运行后的输出结果是3,5,3,5。(✔)
【解析】fun函数的功能是交换形式参数的值,即交换指针变量a和b的值,但是fun函数并不能够交换实参的值,因此fun(p,q)不能交换p和g的值,所以第一个print语句的输出为3,5。第二个fun函数对x和y的地址进行了操作,同样不能交换x和y的值,并不能影响p和q指针指向的数据,因此第二个 printf语句的输出也是3,5。因此输出结果为3,5,3,5。

#include <stdio.h>
int k=5;
void f(int *s)
{ *s=k; }
main(){
int m=3,*p=&m;
f(p);
printf("%d,%d", m, *p);
}

程序的运行结果是5,5。(✔)
【解析】本题程序执行过程为: m=3, p指向m,调用函数f,将实参p中m的地址传递给形参s,s指向m,则赋值给m, m=5, p依然指向m,故输出5,5

#include <stdio.h>
int k=5;
void f(int *s)
{ s=&k; }
main(){
int m=3,*p=&m;
f(p);
printf("%d,%d\n", m, *p);
}

程序的运行结果是3,3。(✔)
【解析】程序执行过程为: p指针指向变量m,调用函数,将m地址传给指针s,然后再让s指向变量k,而p指针所指并没有改变,输出为3,3

#include <stdio.h>
void swap(int *a. int *b)
{
int *tp,t;
t=*a; *a=*b; *b=t;
tp=a; a=b; b=tp:
printf("%d,%d,", *a, *b);
main( )
{
int i=3,j=7, *p=&i, *q=&j;
swap(&i, &j);
printf("%d.%d", *p, *q);
}

程序执行后的输出结果是 3,7,7,3。(✔)
【解析】程序定义两个整型变量i, j,初值为3,7,另外定义两个整型指针变量p,q, 其中p指向j,q指向j,将i, j的地址传给swap函数,在swap函数中,a指向i, b指向j,通过临时变量交换a和b指向的值,此时a指向的实参i, b指向的实参j的值发生了交换,即a指向i的值为7,b指向j的值为3;再通过临时变量tp交换a和b的指针值,使得a指向j,b指向i,所以swap中输出a指向的值为3 (j),b指向的值为7 (i) ;swap函数调用结束后,输出p和q指向的值,即i, j的值7,3,所以程序输出: 3,7,7,3

第九章 编译预处理和动态存储分配

9.1 宏定义(400-404题)

#include <stdio.h>
#define F(x) 2.84+x
#define PR(a) printf("%d" .(int)(a))
#define PRINT(a) PR(a);putchar('\n')
main(){
PRINT( F(5)*2);
}

程序运行后的输出结果是15(✘)
【解析】带参数的宏的调用格式:宏名(实参表),替换过程是,用宏调用提供的实参字符串,直接置换宏定义命令行中相应形参字符串,非形参字符保持不变。将PRINT( F(5)*2 )PR(F(5)*2);putchar("n)替换,将PR(F(5)* 2)print("%d",(int)( F(5)*2)替换,再将F(5)用2.84+5替换,最后替换结果为printf("%d",(int)( 2.84+5*2));putchar("n),运行结果为: 12<回车>。

  1. 宏替换不具有计算功能,宏替换不具有类型,宏名必须用大写字母构成,宏替换不占用运行时间。(✔)

  2. 宏替换没有数据类型限制。(✔)

#include <stdio.h>
#define S(x) x/x*x
main( ){
int k=6,j=3;
printf("%d,%d\n", S(k+j), S(j+k));
}

程序运行后的输出结果是9,9(✘)
【解析】 定义一个带参数的宏时,字符串内的形参通常要用圆括号括起来,以避免出错,本题中,S (k+j)相当于执行运算k+j/k+j*k+j,将k,j值代入运算后取整为27,S(j+k)同理 ,因此答案为27,29

#include <stdio.h>
#define PT 3.5;
#define S(x) PT*x*x;
main(){
int a=1,b=2;
printf("%4.1fn"S(a+ b)); 
}

程序运行后的输出结果是7.5(✘)
【解析】宏定义不是C语句,末尾不需要有分号。 所以语句printf("%4.1f\n", S(a+ b));展开后为printf("%4.1f\n" ,3.5; *a+ b*a+b; );所以程序会出现语法错误

9.2 文件包含#include(405-407题)

#include <stdio. h>
main(){
printf("%d\n", NULL );
}

程序运行后的输出结果是0(✔)
【解析】NULL是在stdio.h头文件中定义的预定义符,NULL的代码值为0,如果以整型格式输出则输出0。

  1. 凡是以#号开头的行,都被称为编译预处理命令行。(✔)

  2. #include命令行不能出现在程序文件的中间。(✘)
    【解析】#include可以出现在程序文件的中间

9.3 关于动态存储的函数(408-411题)

  1. 动态分配函数malloc()的头文件是stdlib.h。(✔)

  2. 若有语句: void* p=malloc(80);,则可以通过指针p直接访问用malloc开辟的这块内存。(✘)
    【解析】题意中使用malloc()函数分配了80个字节的内存单元,void指针p指向该内存单元,在C语言中,void *不能直接使用,必须利用强制类型转换将其转成所需的类型才能使用。

#include <stdio.h>
#include <stdlib. h>
void fun(int *p1, int *s){
int *t;
t=(int *)malloc(2 * sizeof(int));
*t=*p1 + *p1++;
*(t+1)=*p1+ *p1;
s=t;
}
main(){
int a[2]={1,2},b[2]={0};
fun(a,b);
printf("%d,%d\n",b[0],b[1]);
}

程序运行后的输出结果是2,4。(✘)
【解析】malloc函数的原型为: malloc ( size) ;函数的作用是在内存的动态存储区分配一个长度为size的连续空间。
程序执行过程为:定义数组a={1.2},b= {0,0},b,调用函数fun,将数组地址传入函数,指针p1指向a,s指向b;定义指针t并使其指向开辟的两个整型内存,为第一个内存赋值为数组a第以个元素的2倍, 即2,然后指针p1指向数组第二个元素,为第二个内存赋值为数组a第二个元素的2倍,即4,最后使指针s指向动态开辟的两个内存的首地址。整个过程中数组b没有发生变化,依次输出b中元素为0,0

#include <stdio h>
#include <stdlib h>
main()
{
int *a,*b,*c;
a=b=c=(int *)malloc(sizeof(int));
*a=1;*b=2,*c=3;
a=b;
printf("%d,%d,%d\n".*a,*b,*c);
}

程序运行后的输出结果是1,2,3。(✘)
【解析】malloc函数动态分配一个整型的内存空间,然后把函数返回的地址用(int )强制类型转换为整型指针,再把它赋给a, b, c,即让指针变量a, b, c都指向刚申请的内存空间。所以只有最后一个赋值语句*c=3的值保留在 了该空间内,因为a, b, c三个指针变量均指向该空间,所以打印该空间内的数值为3。程序运行后的输出结果是3,3,3

第十章 结构体与共用体

10.1 用typedef说明一种新类型(412-418题)

  1. 只要是用户定义的标识符,都有一个有效的作用域。(✔)

  2. 只有在函数内部定义的变量才是局部变量。(✘)
    【解析】局部变量也称内部变量,是指一个函数内部或复合语句内部定义的变量。

  3. 可以通过typedef增加新的类型。(✘)
    【解析】关键字typedef的作用只是将C语言中的已有的数据类型作了置换,并不是增加新的类型。

  4. 设有以下语句:

typedef struct TT
{ char c; int a[4];} CIN;

则下面叙述中正确的是( D )。
A、CIN是struct TT类型的变量
B、TT是struct类型的变量
C、可以用TT定义结构体变量
D、可以用CIN定义结构体变量
【解析】本题考查typedef重新声明一种结构体类型,其中CIN为结构体类型名,而不是结构体变量,所以D选项正确。

  1. 使用typedef说明新类型名时,后面不能加分号。(✘)

typedef int *INTEGER;
INTEGER p,*q;

则以下叙述正确的是( C )
A. q是基类型为in的指针变量
B、p是int型变量
C. p是基类型为int的指针变量
D.程序中可用INTEGER代替类型名int
【解析】题意使用typedef定义新类型名INTEGER,它代表int *类型,使用INTEGER定义p,相当于int *p;使用INTEGER定义*q,相当于int **q;所以p是基类型为int的指针变量,q是基类型为int *的指针变量,选项A、B、D错误;本题答案为C。

typedef struct
{
int bookID;
double price;
} ND;
typedef ND NDA[100];

NDA是一个类型名,该类型的变量具有100个元素,每个元素的类型是结构体类型ND(✔)
【解析】程序定义了结构体ND,关键字typedef的一个含义是为复杂的声明定义一个新的简单的别名。typedef ND NDA[100]中NDA是一个类型名, 该类型的变量具有100个元素,每个元素的类型是结构体类型ND.

10.2 结构体数据类型(419-424题)

  1. 下面结构体的定义语句中,错误的是( A )。
    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; }a;
    D、struct {intx ; inty ; intZ; }a;
    【解析】 A选项struct ord {intx; inty; int z} struct orda;错误,不能在定义结构体的同时,又用结构体类型名定义变量。应该写成B选项或者D选项的格式。

typedef struct Date{
int year;
int month;
int day;}DATE;

则以下叙述中错误的是( A )。
A、DATE是用户定义的结构体变量
B、struct Date是用户定义的结构体类型
C、DATE是用户说明的新结构体类型名
D、struct是结构体类型的关键字
【解析】C语言允许用typedef说明一种新类型名,其一般形式如下:typedef 类型名 新类型名;,题目中定义了新类型Date,这种类型变量包含3个成员,DATE是这种新类型的名字。
DATE是用户说明的新结构体类型名,不是结构体变量,C选项叙述正确;
A选项叙述错误,选择A选项。
struct Date是用户定义的结构体类型,B选项叙述正确。
struct是结构体类型的关键字,D选项叙述正确。

  1. 即使结构体变量中有字符串成员,该字符串也与结构体变量一并返回。(✔)

  2. 结构体中可以含有指向本结构体的指针成员。(✔)

  3. 结构体类型的大小为其所有成员所占内存空间之和。(✔)

  4. 结构体类型中的成分只能是C语言中预先定义的基本数据类型(✘)
    【解析】结构体类型中的成分可以是结构体。

10.3 结构体类型变量的定义(425-432题)

typedef struct data1 {int x,y;}data2;
typedef struct {float x, y;}data3;

则以下不能作为类型名使用的是( A )。
A、data1        B、data2
C、data3        D、struct data1
【解析】类型定义符typedef的作用是为数据类型名取"别名",即: typedef类型名 新类型名﹔使用新类型名声明变量时,相当于使用类型名去修饰。所以本题中: data2相当于struct data1类型; data3相当于struct {float x,y;}类型,选项B、C正确;另外根据结构体struct的定义,必须使用struct data1来声明变量,选项D正确;而data1是不合法的,答案为A。

  1. struct { int num; char name[12];} PER;PER std;不能定义结构体变量。(✔)
    【解析】PER是一个变量,不能用变量名声明变量。

  2. struct {char mark[12]; int num1; double num2;} t1,t2;若变量均已正确赋初值,则以下语句中错误的是( C )。
    A、t1=t2;
    B、t2.num1=t1.num1;
    C、t2.mark=t1.mark;
    D、t2.num2=t1.num2;
    【解析】本题考查结构体变量的引用,C选项中mark为结构体中的数组,不能直接赋值

struct student{
char g;char nm[10];}
rec, *ptr;
ptr = &rec;

若要输出结构体变量rec的nm成员,写法错误的是( C )。
A、printf(“%s”, rec.nm);
B、printf(“%s” , ptr->nm);
oc、printf(“%s” , rec->nm);
D、printf(“%s”,(*ptr).nm);
【解析】在C语言的结构体中,
引用结构体成员时,结构体变量使用"."运算符,
结构体指针变量使用"->”运算符或者(*指针变量)结构体成员。
在本题中,pt为指针变量,选项B和C引用正确,rec为结构体成员,选项A正确,选项C错误。本题答案为C选项。

  1. 结构体定义时,其成员的数据类型可以是本结构体类型。(✘)

  2. 即使是同类型的结构体变量,也不能进行整体赋值。(✘)
    【解析】可以进行整体赋值。

  3. 结构体变量可以作为函数的参数和返回值。 作为函数的实参时,可以实现函数的传值调用。 当使用结构体变量作为函数的形参时,实参也应该是结构体变量名以实现传值调用,实参将拷贝副本给形参,在被调用函数中改变形参值对手调用函数中的实参没有影响

#include <stdio.h>
#include <string.h>
struct s{
char name[10];};
main(){
struct S s1, s2;
strcpy(s1.name, "10\0");
printf("%s=", s1.name);
strcpy(s2.name, "000");
printf("%s=", s2.name);
s1 = s2;
printf("%s=", s1.name);
}

程序运行后的输出结果是10=000=000=(✔)
【解析】定义结构体S,包含成员name。main函数中,定义结构体变量s1和s2,s1.name="10\0"输出s1.name为10。s2.name=“000”,输出s2.name为000。执行语句s1=s2,将s2的值赋给s1,则s1.name=“000”,并打印输出s1.name为000。

10.4 结构体变量引用(433题)

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
struct stu {
char *name,gender;int score;
};
main(){
struct stu a={NULL, 'm',290}, b;
a.name=(char *)malloc(10);
strcpy(a.name, "Zhao");
b=a; b.gender = 'f'; b.score = 350;
strcpy(b.name, "Qian");
printf("%s,%c,%d," , a.name, a.gender, a.score );
printf("%s,%c,%d\n", b.name, b.gender, b.score );
}

则程序的输出结果是Qian,m,290,Qian,f,350
【解析】本题中考查结构体中变量的引用。
结构体赋值语句b=a是浅拷贝,一个结构体的值完全赋给另一个结构体。但当结构体含有指针时,浅拷贝只会拷贝指针所指向的空间地址值,而不会深层的自动外分配空间并拷贝空间内的值。
所以当b=a执行后,因为结构体中成员变量name是指针,所以结构体变量a和b中的name指针会指向同一存储空间,执行strcpy(a.name, “Qian”);语句后,a结构体中name被修改为Qian。

10.5 结构体数组(434题)

struct st
{ char name[12]; int age; char sex; } std[10],*p=std;

以下语句错误的是( A )。
A、scanf(“%d”;,p->age);
B、scanf(“%s”,std[0].name);
C、scanf(“%d” ,&std[1].age);
D、scanf(“%c” ,&(p->sex));
【解析】A选项中,p->age是结构指针访问结构成员的方式,如果为结构体内变量进行赋值,应该对指针地址指向的单元进行赋值,因此在p->age前面应该加入取地址符&,A选项语句错误,答案为A选项。

第十一章 文件

11.1 C语言文件的概念(435-441题)

  1. 文件由数据序列组成,可以构成二进制文件或文本文件。(✔)

  2. 文件指针是指针类型的变量。(✔)

  3. 文件指针变量的值是文件的当前读取位置。(✘)
    【解析】文件指针指向的是文件缓冲区,而不是文件本身位置。

  4. 表达式sizeof(FILE*) = sizef(int*)的值为真。(✔)
    【解析】sizeof(FILE*)=4,因为file* 为指针,指针的大小4 ,sizef(int*)=4。

  5. 文件指针的值是一个整数, 它的值一定小于文件字节数。(✘)
    【解析】文件指针的值是地址,是一个16进制的数,它的值不一定小于文件字节数

  6. 当对文件的读(写)操作完成之后,必须将它关闭,否则可能导致数据丢失。(✔)

  7. 在一个程序中当对文件进行了写操作后,必须先关闭该文件然后再打开,才能读到第1个数据。(✘)
    【解析】在一个程序中当对文件进行了写操作后,不用先关闭该文件然后再打开,才能读到第1个数据,可以用fseek()函数进行重新定位即可。

11.2 文件的打开与关闭(442-448题)

  1. 只有对文件进行输出操作之后,才能调用fclose§函数关闭文件。(✘)
    【解析】只要对文件进行操作后,都要调用fclose文件关闭文件。

  2. fprintf()与fwrite()函数功能相同; fscanf()与fread()函数功能相同。(✘)
    【解析】fprintf()函数和fscanf()函数读写文本文件,而fwrite()和fread()函数读写二进制文件。

  3. 文件以"r”方式打开后,可以存储文本类型的数据。(✘)
    【解析】只可读取文本类型的数据。

  4. fp=fopen(" person. dat",________ );
    要求文本文件person. dat可以进行信息查找和信息的补充录入,若文件不存在还可以建立同名新文件,则下划线处应填入的是( A )。
    A. “a+”    B、“w”     C、“w+”    D、“wb”
    【解析】 “a+” 表示在文件后面添加数据,如果指定的文件不存在,系统将用在fopen调用中指定的文件名建立新文件,正确;
    “w” 表示以写的方式打开文本文件,如果指定的文件不存在,系统将用fopen调用中指定的文件名建立一个新文件,不满足数据追加;
    “w+” 同样不满足数据追加;
    “wb” 是以写的方式打开二进制文件,也不满足数据追加。

  5. “a+” 方式打开文件时,原有文件内容不被删除,可以进行添加和读操作。(✔)

  6. 关于文件的使用方式,以下叙述中错误的是( A )。
    A. "w"为写而打开文本文件,指定文件不存在时则写文件出错
    B、"r为读而打开文本文件,指定文件不存在时则读文件出错
    C、"a为续写数据打开文本文件,原有内容得以保留
    D、"r+”为读和写而打开文本文件
    【解析】C语言中,打开文件使用fopen函数,打开文件时需要指定打开方式,其中:
    “w” 表示为写而打开文本文件,如果指定的文件不存在,系统将用在fopen调用中指定的文件名建立一个新文件;
    “r” 表示为读而打开文本文件,若指定的文件不存在,则会出错;
    “a" 表示为在文件后面添加数据而打开文本文件,如果文件存在,则文件中原有的内容将被保存,新数据写在原有文件之后;
    “r+” 表示为读和写而打开文本文件。

FILE *fp;
if( (fp=fopen("test.txt","w")) == NULL)
{
printf("不能打开文件! ");
exit(0);}
else
printf("成功打开文件! ");

若文件test.txt已存在,则以下叙述正确的是( A )。
A、程序运行后,文件test.txt中的原有内容将全部消失
B、程序运行时,会因文件存在而出错
C、对文件test.txt进行写操作后,可以随机进行读取
D、对文件test.tx写入的内容总是被添加到文件尾部
【解析】 fopen函数 以一定方式打开指定文件,返回一个指向文件的文件指针。
如果不能实现打开指定文件的操作,则返回一个空指针NULL
如果指定文件不存在创建一个文件名为指定文件名的新文件,然后打开它
指定文件有错误或者指定文件不存在却不能创建新文件的情况下,打开文件操作错误,返回空指针
本题程序中,文件test.txt已存在,程序运行后,文件test.txt中的原有内容将全部消失,A选项正确。
文件原本就存在,不会导致程序出错,会按照指定的方式打开文件,B选项错误。
对文件进行写操作,只能对指针指向的位置内容进行写操作,不能随机读写,C选项错误。
对文件test.txt写入的内容写到指针所指向的位置,而不是添加在文件尾部,D选项错误。

11.3 文件的读写(449-460题)

  1. fopen函数的调用形式为: fopen(文件名)。(✘)
    【解析】C语言中打开一个文件通过系统函数open实现,其调用的一般形式为: FILE *fopen("文件名","操作方式");

  2. 以下不能对文件进行输出的库函数是( C )。
    A. fwrite     B、fputc    C、fpout    D. fprintf
    【解析】选项A中,fwrite函数用来输出数据到指定二进制文件中;
    选项B中,fputc函数用来把字符输出到指定文件中;
    选项D中fprint函数用来按格式将数据输出到指定文本文件中。
    只有选项C中fpout不是库函数,本题答案为C选项。

  3. fread ()函数用法是fread ( void *buffer, int size,int n,FILE *fp)其中buffer为指针类型,应该传入指针类型的值。(✔)

  4. fwrite ()函数用法是fwrite (void *buffer int size, int n,FILE *fp)其中buffer为要输出的数据的首地址。(✔)

  5. fputs(str, fp)的功能是将字符串str输出到文件指针p指向的文件中。(✔)

 #include <stdio.h>
main( )
{
int i;
FILE* fp:
for(i=0;i<3; i++)
{
fp = fopen("res.txt", "w");
fputc('K'+i, fp);
fclose(fp);
}
}

程序运行后,在当前目录下会生成一个res.txt文件,其内容是KLM。(✘)
【解析】for循环中,每次都执行打开文件res.txt、写入文件、再关闭文件的操作,由于fopen函数使用w模式写文件,所以每次打开res.xt后,都删除文件中的原有数据,再重新写入新数据。所以文件最终的内容只与最后一次for循环有关,最后一次fo循环是向文件res.txt写入‘K’+2,即M

#include <stdio.h>
main( )
{ FILE *fp;
int i, a[6]={ 1,2,3,4,5,6}, b[6]}; 
fp = fopen("d.dat", "w+b");
fwrite(a, sizeof(int), 6, fp):
for(i=0;i<6;i++)
fwrite(&a[2], sizeof(int), 1, fp);
rewind(fp);
fseek(fp, sizeof(int)*2, SEEK_CUR);
fread(b, sizeof(int), 6, fp):
fclose(fp);
for (i=0;<6; i++)
printf("%d,", b[i]);
}

程序执行后的输出结果是3,4,5,6,3,3。(✔)
【解析】程序首先以读二进制文件的方式打开d.dat,然后使用fwrite()函数将数组a中6个元素写入d.dat中,接着调用for循环将a[2]元素(值为3) 6次写入d.dat文件中, 再使用rewind()函数将文件指针fp移动到文件头,再使用fseek()函数将fp以当前位置向后移动2个整数位置,再使用fread()函数从fp指向的位置向后读取6个整数,由此可知这6个整数分别是:3,4,5,6,3,3

#include <stdio.h>
main()
{
FILE*fp;
int i, a[6]={1,2,3,4,5,6}, k;
fp= fopen("data.dat" , "w+");
fprintf(fp, "%d\n" , a[0]);
for (i=1; i<6; i++)
{rewind(fp);
fprintf(fp, "%d\n", a[i]);}
rewind(fp);
fscanf(fp, "%d" ,&k);fclose(fp);
printf("%d\n", k);}

程序运行后的输出结果是6(✔)
【解析】本题首先定义文件指针变量fp和一个数组a,再打开一个文件"data.dat",随后先给文件写入数据a[0],由于rewind函数是将文件指针从当前位置重新指向文件开始位置,所以for循环依次将数组a中的数据写入文件开始位置。第一次循环写入1,第二次循环时位置指针指向开始位置写入2,覆盖上一次循环写入的数字。退出循环后,文件中的数据为6。重新使指针指向文件开始位置,将此时fp指向的数据〈即文件中数据6)写入变量k中,关闭文件,输出k值。

#include <stdio.h>
main( )
{ FILE *fp;
int i, a[6]={6,5,4,3,2,1};
fp = fopen("d.dat", "w+b");
fwrite(a, sizeof(int),6,fp);
rewind(fp);
fread(&a[3], sizeof(int), 3, fp);
fclose(fp);
for (i=0;<6; i++)
printf("%d,", a[i]);
}

执行后的输出结果是3,2,1,6,5,4(✘)
【解析】函数fwrite ( bffer,size,count,fp) fread(buffer sze,count,fp), buffer为数据库指针 , size每个数据块的字节数,count每读写一次,数据块的个数。
语句fwrite(a, sizeof(int), 6, fp),将数组a写入到文件fp中。再执行rewind语句使指针指向文件开头。执行语句fread(&a[3], sizeof(int), 3, fp),读入数据6,5,4存储与数组a[3]a[4],a[5]中, 则数组a的值为{6,5,4,6,5,4},输出打印数组a的值。

#include <stdio.h>
main( ){
FILE *fp;
inti, a[6]={ 1,2,3,4,5,6};
fp = fopen("d.dat", "w+b");
for (i=5;j>=0;--)
fwrite(&a[i],sizeof(int), 1, fp);
rewind(fp);
fread(&a[3],sizeof(int),3, fp);
fclose(fp);
for (i=0;i<6; i++)
printf("%d,",a[i]);
}

程序执行后的输出结果是6,5,4,6,5,4(✘)
【解析】程序定义数组a,使用6个元素对其初始化,接着以写二进制方式打开文件d dat,调用fwrite函数将a的6个元素逆序写入文件(654321),接着调用rewind函数,将文件指针移动到文件开始位置,调用fread函数从文件开始位置读入3个整数6、5、4, 逐个存放到数组元素a[3]开始的三个地址,即a[3]=6,a[4]=5,a[5]=4, 关闭文件,再次调用for循环输出a,输出结果为: 1,2,3,6,5,4。

 #include <stdio.h>
#include <stdlib. h>
main( )
{
FILE *fp;
char ch,str[5];
if(fp=fopen("file.txt","wb+"))== NULL)
{printf(" error!\n"); exit(0);}
ch=getchar0;
while( ch!='!')
{
fputc(ch,fp);
ch=getchar();
}
rewind(fp);
do{
fgets(str,4,fp);
puts(str);
while(!feof(fp));
fclose(fp);
}

【解析】分析程序可知,程序是首先以可写方式打开文件file .txt,然后使用getchar()逐个读入输入的字符,写到文件file.txt中,直到输入的字符是!,停止写入文件;然后使用rewind()将文件指针定位到文件开头位置,再调用fgets()函数,将文件中的内容读入str字符数组中,再用puts()输出,直到遇到文件结尾符,关闭文件。
其中写入文件时是逐个写入的,而读出时调用fgets(str,4,fp);可知fgets至多 读取3个字符到str,然后在结尾自动加上’\0’字符,作为字符串的结尾标志,使用puts输出时,输出三个字符并完成换行,当输入c:\test!<回车>时,输出为:

c:
\te

st

11.4 文件的定位(461-465题)

  1. EOF只能作为文本文件的结束标志,其值为-1。(✔)
    【解析】文件结束或者错误,则返回符EOF是在头文件stdio h中定义的宏,一般值为-1,在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放,由于不可能出现-1,因此可以用EOF作为文件结束标志。

  2. 设f为指向某二进制文件的指针,且已读到此文件末尾,则函数feof(f)的返回值为非0值(✔)
    【解析】本题考查文件的定位, feof函数的用法是从输入流读取数据,如果到达文件末尾(遇文件结束符),eof函数值为非零值,否则为0

  3. EOF是在库函数文件中定义的符号常量(✔)

  4. 若fp已定义为指向某文件的指针,且没有读到该文件的末尾,则C语言函数fef(fp)的函数返回值为0(✔)

#include <stdio.h>
main()
{ FILE *fp;
int i a[6]={1,2,3,4,5,6},k; 
fp = fopen(" data.dat", "w+");
for (i=0; i<6; i++)
{ fseek(fp,0L,0);fprint(fp, "%d\n", a[i]); }
rewind(fp);
fscanf(fp,"%d", &k);
fclose(fp);
printf("%d\n", k);
}

则程序的输出结果是6(✔)
【解析】本题考查文件操作函数,fseek 用于二进制方式打开的文件移动文件读写指针位置。将文件内部的位置指针重新指向一个流(数据流文件)的开头。所以最后只保留了6

  • 20
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算机二级C语言复习中,需要了解计算机中数据的存储形式以及相关的函数和库。 首先,计算机在电脑中保存数据采用二进制形式,由0或1构成的二进制称为位(bit),八个位构成一个字节(Byte),1个Byte=8个bit。这是计算机存储数据的基本单位。 其次,对于文件的读写操作,需要使用相关的函数来处理。在C语言中,可以使用stdio.h文件中的库函数来进行文件的输入和输出操作。其中,printf函数用于输出格式化的数据,而scanf函数用于从输入中读取数据。这两个函数是stdio.h文件中的库函数,它们是printf和scanf函数的简化版本。 在进行复习时,需要理解这些函数的用法和应用场景,并且清楚是用于二进制文件还是文本文件。建议仔细复习教材中关于文件操作的章节,以免在考试时将这些文件函数搞混。 综上所述,计算机二级C语言复习需要了解计算机数据的存储形式以及相关的函数和库,包括二进制数据的存储和文件的输入输出操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [计算机二级C语言知识点复习资料,精简版](https://blog.csdn.net/qq_51607668/article/details/119567831)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值