2.2 二级C语言程序设计选择题高频考点

2.2.1 C语言概述

【考点1】 C语言基础知识
1.C语言的构成

(1)源程序由函数构成,每个函数完成相对独立的功能。

(2)每个源程序中必须有且只能有一个主函数,其可以放在任何位置,但程序总是从主函数开始执行。

(3)函数体是在函数后面用花括号({})标识起来的部分。

(4)每个语句以分号(;)结束,但预处理命令、函数头之后不能加分号。

(5)注释在“/*”与“*/”之间,没有空格,允许出现在程序的任何位置。

(6)预处理命令是以“#”开头的语句。

2.C程序的生成过程

(1)C程序的生成过程为先由源文件经编译生成目标文件,然后经过链接生成可执行文件。

(2)源程序的扩展名为.c,目标程序的扩展名为.obj, 可执行程序的扩展名为 .exe 。

【考点2】 标识符、常量、变量和数据类型
1.标识符

(1)标识符的命名规则。

只能由字母、数字或下划线组成。

第1个字符必须是字母或下划线,不能是数字。

区分字母的大小写。

(2)标识符的分类。

C语言的标识符可以分为3类。

①关键字:C语言规定专用的标识符,它们有着固定的含义,不能更改。

②预定义标识符:在C语言中预先定义并具有特定含义的标识符。允许把这样的标识符重新定义,但建议不要这样做。

③用户标识符:由用户根据需要定义的标识符。

命名应注意做到 “见名知义”。

不能与关键字同名。

2.常量

定义:在程序运行中,其值不能被改变的量。

常量的类型:整型常量、实型常量、字符常量、字符串常量及符号常量。

(1)整型常量。

①表示形式:十进制整型常量、八进制整型常量和十六进制整型常量。

②书写形式。

十进制整型常量:基本数字范围为0~9。

八进制整型常量:以0开头,基本数字范围为0~7。

十六进制整型常量:以0x开头,基本数字范围为0~15,其中 10~15写为A~F或a~f。

(2)实型常量。

①表示形式:小数形式和指数形式。

②书写形式。

十进制小数形式。

指数形式:e前必须有数字,e后必须为整数。

(3)字符常量。

一个字符常量代表ASCII字符集里的一个字符,在程序中用单撇号(“)标识,区分大小写。

转义字符以“\”开头,后面跟不同的字符表示不同的意思。

\n:换行。

\\:反斜线字符“\”。

\ddd:1~3位八进制数所代表的一个ASCII字符。

\xhh:1~2位十六进制数所代表的一个ASCII字符。

(4)字符串常量。

字符串常量是用双撇号(“ “)标识的一个或一串字符。

(5)符号常量。

符号常量是由预处理命令“#define”定义的常量,在C程序中可用标识符代表一个常量。

3.变量

定义:值可以改变的量。

变量要有变量名,在使用前必须先定义。

在内存中占据一定的存储单元,不同类型的变量占据的存储单元大小不同。

存储单元里存放的是该变量的值。

变量的类型:整型变量、实型变量、字符变量。

(1)整型变量。

①分类:基本整型(int)、短整型(short int 或short)、长整型(long int 或 long)和无符号型(unsigned int、unsigned short、unsigned long)。

②数值范围。

基本整型[signed]int,占16位;短整型[signed]short[int],占16位;长整型[signed]long[int],占32位;无符号整型unsigned[int],占16位;无符号短整型unsigned short[int],占16位;无符号长整型unsigned long[int],占32位。

(2)实型变量。

①分类:单精度型(float)和双精度型(double)。

②定义方法:float a;,double m;。

③所占字节:单精度型在内存中占4字节(32位),双精度型占8字节(64位)。单精度实数提供7位有效数字,双精度实数提供15~16位有效数字。

④实型常量:不分单精度型和双精度型,一个实型常量可以赋给一个单精度型或双精度型变量,但变量根据其自身类型截取实型常量中相应的有效数字。

(3)字符变量。

①作用:用来存放字符常量。

②定义:用关键字char定义,每个字符变量中只能存放一个字符。

③定义形式:char cr1, cr2;。

④赋值:cr1=ˈmˈ,cr2=ˈnˈ;。

⑤存储方法:存储字符对应的ASCII到内存单元中。

字符型数据与整型数据之间可以通用,一个字符能用字符的形式输出,也能用整数的形式输出。

字符型数据进行算术运算,相当于对它们的ASCII进行运算。

4.类型的自动转换和强制转换

(1)类型的自动转换。

①当同一表达式中各数据的类型不同时,编译程序会自动把它们转变成同一类型后再进行计算。

②转换优先级为char < int < float < double ,左边的类型向右边转换。

③当进行赋值运算时,若赋值运算符左右两边的类型不同,则赋值运算符右边的类型向左边的类型转换;若右边的类型高于左边的类型,则在转换时对右边的数据进行截取。

(2)类型的强制转换。

表示形式:( 类型 )(表达式);。

2.2.2 运算符与表达式

【考点1】 常考的C语言运算符
1.C语言运算符简介

算术运算符:+、-、*、/、%。

关系运算符:>、>=、==、!=、<、<=。

位运算符:>>、<<、~、&、|、∧。

逻辑运算符:!、||、&&。

条件运算符:? ∶。

指针运算符:&、*。

赋值运算符:=。

逗号运算符:,。

字节运算符:sizeof。

强制运算符:(类型名)(表达式)。

初等运算符:圆括号(())、下标运算符([])及结构体成员运算符(->)。

2.运算符的结合性和优先级

(1)结合性。所有的单目运算符、条件运算符、赋值运算符及其扩展运算符,结合方向都是从右向左,其余运算符的结合方向是从左向右。

(2)优先级比较。初等运算符>单目运算符>算术运算符(先乘除后加减)>关系运算符>逻辑运算符(不包括“!”)>条件运算符>赋值运算符>逗号运算符。

3.强制类型转换运算符

(1)可以利用强制类型转换运算符将一个表达式转换成所需类型。

(2)一般形式:

(类型名)(表达式)

4.逗号运算符和逗号表达式

(1)逗号表达式:用逗号运算符将几个表达式连接起来。

(2)一般形式:表达式1,表达式2,…,表达式n。

(3)求解过程:先求解表达式1,然后依次求解表达式2到表达式n的值。表达式n的值就是整个逗号表达式的值。

【考点2】 算术运算符和算术表达式
1.基本的算术运算符

(1)分类:加法运算符或正值运算符(+)、减法运算符或负值运算符(-)、乘运算符(*)、除运算符(/)和求余运算符(%)。

其中,求余运算符的两端必须都是整型,其余运算符的对象可以是整型或者实型。

(2)双目运算符两边的数值类型必须一致才能进行运算,如果不一致,系统会先进行一致性转换。

转换规则:char->short->int->unsigned->long->float->double。

(3)所有实数的运算都是以双精度方式进行的,若是单精度实数,则需要在尾数后面补0转换为双精度实数。

2.算术表达式和运算符的优先级与结合性

(1)定义:用算术运算符和圆括号将运算对象连接起来的、符合C语言语法规则的表达式。

(2)运算对象:函数、常量和变量等。

(3)运算规则。

可使用多层圆括号,但圆括号必须配对。运算时由内向外依次计算各表达式的值。

对于不同优先级的运算符,按其优先级由高到低进行运算,若优先级相同,则按结合方向进行运算。

若运算符两侧的运算对象类型不同,则先利用自动转换或强制类型转换,使其类型相同然后进行运算。

3.自增、自减运算符

(1)作用:自增运算符(++)使运算变量的值增1,自减运算符(--) 使运算变量的值减1。

(2)均是单目运算符。运算对象可以是整型或实型变量,但不可以是常量和表达式。

(3)均可作为前缀运算符,也可作为后缀运算符构成一个表达式。

++i,--i:在使用i之前,先使i的值自增1(自减1),再使用变化后的变量值参加表达式运算。

i++,i--:i的值先参加表达式运算,再执行自增1(自减1)。

(4)结合方向:自右向左。

【考点3】 赋值运算符和赋值表达式
1.赋值运算符和赋值表达式

(1)“=”称作赋值运算符,作用是将一个数值赋给一个变量或将一个变量的值赋给另一个变量,由赋值运算符组成的表达式称为赋值表达式。

(2)一般形式:变量名=表达式。

赋值运算符的优先级高于逗号运算符。

赋值运算符(=)和等于运算符(==)有很大差别。

赋值运算符的左侧只能是变量,而不能是常量或者表达式。赋值运算符的右侧可以是表达式,包括赋值表达式。

规定最左侧变量所得到的新值就是整个赋值表达式的值。

2.复合赋值运算符

在赋值运算符之前加上其他运算符可以构成复合赋值运算符。例如,+=、-=、*=、/=、%=等。

两个符号之间不可以有空格。

复合赋值运算符的优先级与赋值运算符的优先级相同。

3.赋值运算中的类型转换

如果赋值运算符两侧的类型不一致,在赋值前系统将自动先把右侧表达式求得的数值按赋值运算符左侧变量的类型进行转换(也可以用强制类型转换的方式)。

【考点4】 位运算
1.C语言提供6种位运算符

按位与(&):若两个相应的二进制位都为1,则该位的结果为1,否则为0。

按位或(|):若两个相应的二进制位中有一个为1,则该位的结果为1,否则为0。

按位异或(∧):若两个二进制位相同,则结果为0,不同则为1。

按位求反(~):按位取反,即0变1,1变0。

左移(<<):将一个数的二进制位全部左移若干位。

右移(>>):将一个数的二进制位全部右移若干位。

2.说明

位运算中除按位求反以外,均为双目运算符,要求两侧各有一个运算对象。

运算对象只能为整型或字符型数据,不能为实型数据。

2.2.3 基本语句

【考点1】 单个字符的输入与输出
1.字符输出函数putchar()

putchar()函数的作用是向终端输出一个字符。

2.字符输入函数getchar()

getchar()函数的作用是接收终端输入的一个字符。

getchar()函数没有参数,函数值就是从输入设备得到的字符。

【考点2】 数据格式的输入与输出
1.格式化输出函数printf()

printf()函数是C语言提供的标准输出函数,它的作用是向终端(或系统隐含指定的输出设备)按指定格式输出若干个数据。

(1)printf()函数的一般形式:

printf(格式控制字符串,输出列表);

①格式控制字符串:用双撇号标识的字符串是格式控制字符串,它包括两种信息。

格式说明,由“%”和格式字符组成。

需要原样输出的字符也写在格式控制字符串内。

②输出列表:需要输出的一些数据,可以是常量、变量或表达式。输出列表中的各输出项用逗号隔开。

(2)格式字符。

可在“%”与格式字符之间插入“宽度说明”、左对齐符号“-”、前导零符号“0”等。

d格式字符,用于输出十进制数。

o格式字符,以八进制数形式输出整数。

x格式字符,以十六进制数形式输出整数。

u格式字符,用于输出无符号型数据,即输出无符号的十进制数。

c格式字符,用于输出一个字符。

s格式字符,用于输出一个字符串。

f格式字符,用于输出实数(包括单精度型、双精度型),以小数形式输出,使整数部分全部输出。

e格式字符,以指数形式输出实数。

g格式字符,用于输出实数。

(3)使用printf()函数时的注意事项。

在格式控制字符串中,格式说明与输出项从左到右在类型上必须一一对应。

在格式控制字符串中,格式说明与输出项个数要相等。

在格式控制字符串中,可以包含任意的合法字符(包括转义字符),这些字符在输出时将被“原样输出”。

如果要输出“%”,则应该在格式控制字符串中用两个连续的百分号“%%”来表示。

2.格式化输入函数scanf()

(1)scanf()函数的一般形式:

scanf(格式控制字符串,地址列表);

其中,scanf是函数名,格式控制字符串的含义同printf()函数中格式控制字符串的含义,地址列表由若干个变量地址组成,既可以是变量的地址,也可以是字符串的首地址。

(2)格式说明。

scanf()函数中的格式说明也是以“%”开始,以一个格式字符结束,中间可以加入附加的字符。

对无符号型变量的数据,可以用“%d”“%o”“%x”格式输入。

在scanf()函数中,格式字符前可以用一个整数指定输入数据所占宽度,但若输入的是实型数据,则不能指定其小数位的宽度。

在格式控制字符串中,格式说明的个数应该与输入项的个数相等,且类型要匹配。

(3)使用scanf()函数时的注意事项。

scanf()函数中的输入项只能是地址表达式,而不能是变量名或其他内容。

如果在格式控制字符串中,除了格式说明以外还有其他字符,则在输入数据时应输入与这些字符相同的字符。

当用 “%c”格式输入字符时,空格字符和转义字符都可作为有效字符输入。

当输入数据时,若实际输入数据少于输入项个数,scanf()函数会等待输入,直到满足条件或遇到非法字符才结束等待;若实际输入数据多于输入项个数,多余的数据将留在缓冲区备用,作为下一次输入操作的数据。

当输入数据时,若遇到以下情况则认为输入结束:空格、“回车”(“Enter”键)或“跳格”(“Tab”键),上述字符可统一称为“间隔符”。

2.2.4 选择结构

【考点1】 关系运算符和关系表达式
1.关系运算符及其优先次序

C语言提供了6种关系运算符:小于(<)、小于等于(<=)、大于等于(>=)、大于(>)、等于(==)、不等于(!=)。

(1)结合性:自左向右。

(2)优先级。

前4种关系运算符(<、<=、>=、>)的优先级相同,后两种关系运算符(==、!=)的优先级相同。

前4种关系运算符的优先级高于后两种。

关系运算符的优先级低于算术运算符,高于赋值运算符。

2.关系表达式

(1)定义:由关系运算符连成的表达式。关系运算符的两边可以是C语言中任意合法的表达式。

(2)关系运算符的结果是一个整数值——“0或者非0”,用非0值来表示“真”,用0值来表示“假”。

(3)当关系运算符两边值的类型不一致时,系统将自动转换使其一致。

【考点2】 逻辑运算符和逻辑表达式
1.逻辑运算符及其优先级

C语言提供了3种逻辑运算符:逻辑与(&&)及逻辑或(‖)及逻辑非(!)。其中&&和‖是双目运算符,而!是单目运算符,且要求其必须出现在运算对象的左边。

(1)结合性:自左至右。

(2)优先级:! > && > ‖ 。

! >算术运算符>关系运算符> && > ‖ >赋值运算符。

2.逻辑表达式

(1)逻辑表达式由逻辑运算符和运算对象组成。

(2)参与逻辑运算的对象可以是一个具体的值,还可以是C语言中任意合法的表达式。

(3)逻辑表达式的运算结果为1(真)或者为0(假)。

A&&B运算中,只有A、B同为真时才为真。

A‖B运算中,只有A、B同为假时才为假。

关系运算符不能连用,即不能使用0<x<10,可改写成“0<x&&x<10”。

【考点3】 if语句和用if语句构成的选择结构
1.if语句的几种形式

形式1:

if(表达式)语句

if是C语言的关键字。

表达式两侧的括号不可少,并且只能是圆括号。

紧跟着的语句,称为if子句,如果在if子句中需要多个语句,则应该使用花括号标识,使一组语句构成复合语句。

形式2:

if(表达式)语句1

else语句2

形式3:

if(表达式1)语句1

else if(表达式2)语句2

else if(表达式3)语句3

else if(表达式m)语句m

else 语句m+1

“语句1”是if子句,“语句2…语句m”是else子句。这些子句在语法上要求是一条语句,当需要执行多条语句时,应该使用花括号把这些语句标识为复合语句。

else必须与if配对,共同组成if-else语句。

2.if语句的嵌套

在if语句中又包含一个或多个if语句结构,称为if语句的嵌套。

3.条件运算符构成的选择结构

(1)条件运算符:? ∶。

(2)条件表达式的一般形式:表达式1?表达式2∶表达式3。

(3)求解过程:先求表达式1的值,当表达式1的值非0时,以表达式2的值作为整个条件表达式的值;当表达式1的值是0时,以表达式3的值作为整个条件表达式的值。

4.优先级

条件运算符高于赋值运算符,但低于逻辑运算符、关系运算符及算术运算符。

【考点4】 switch语句

switch语句是C语言提供的多分支选择语句,用来实现多分支选择结构。

一般形式:

switch(表达式)

{

 case 常量表达式1 :语句1

 case 常量表达式2 :语句2

  …

 case 常量表达式n :语句n

 default : 语句n+1

}

switch后面用花括号标识的部分是switch语句体。

switch后面用圆括号标识的“表达式”,可以是C语言中任意合法表达式,但表达式两侧的圆括号不能省略。

case与其后面的常量表达式合称case语句标号,常量表达式的类型必须与switch后面的表达式的类型相匹配,且各case语句标号的值各不相同,不能重复。

default也是关键字,起标号的作用,代表除了以上所有case语句标号之外的那些标号,default标号可以出现在语句体中任何标号位置上,当然,也可以没有。

case语句标号后的语句1、语句2等,可以是一条语句,也可以是若干条。在必要时,case语句标号后的语句可以省略不写。

2.2.5 循环结构

【考点1】 while 语句

(1)一般形式。

while(表达式) 循环体

while是C语言的关键字。

紧跟其后的表达式可以是C语言中任意合法的表达式。该表达式是循环条件,由它来控制循环体是否执行。

循环体只能是一条可执行语句,当多条语句需要多次重复执行时,可以使用复合语句。

(2)执行过程。

①计算紧跟while后圆括号中表达式的值,当表达式的值非0时,则接着执行while语句中的内嵌语句;当表达式值为0时,则跳过该while语句,执行该while结构后的其他语句。

②执行循环体内嵌语句。

③返回执行步骤①,直到条件不满足,即表达式的值为0,退出循环,while循环结束。

(3)特点。

先对表达式进行条件判断,后执行语句。

【考点2】 do-while 语句

(1)一般形式。

do{

循环体

}while(表达式);

do是C语言的关键字,必须和while联合使用,不能独立出现。

do-while 循环由 do 开始,至while结束。

while后面的圆括号中的表达式,可以是C语言中任意合法的表达式,由它控制循环是否执行,且圆括号不可省略。

按照语法规则,do和while之间只能有一条语句,如需要执行多条语句,须使用复合语句。

while(表达式)后的分号不可省略。

(2)执行过程。

①先执行一次指定的循环体语句。

② 执行完后,判别while后面的表达式的值,当表达式的值非0(真)时,程序流程返回,重新执行循环体语句。

③ 如此反复,直到表达式的值为0(假)为止,此时循环结束。

(3)特点。

先执行循环体一次,然后判断循环条件是否成立。

【考点3】 for语句

(1)一般形式。

for(表达式1;表达式2;表达式3)

圆括号中通常是3个表达式。for语句中的表达式可以部分或者全部省略,但两个分号是不可省略的。

各个表达式之间用分号隔开,且圆括号不可省略。

按照语法规则,循环体只能包含一条语句,如需要执行多条语句,须使用复合语句。

(2)执行过程。

①求表达式1的值。

②求表达式2的值,若其值非0(真),则执行for语句中指定的内嵌语句,然后执行下面步骤③;若其值为0(假),则退出循环,执行 for语句以下的其他语句。

③求表达式3的值。

④重复执行步骤②。

【考点4】 循环的嵌套

(1)定义:在某一个循环体内部又包含了另一个完整的循环结构,称为循环的嵌套。

(2)前面介绍的3种类型的循环都可以互相嵌套。循环的嵌套可以多层,但要保证每一层循环在逻辑上必须是完整的。

【考点5】 几种循环的比较

while和do-while 循环,只在while后面指定循环条件,循环体内应包含使循环趋于结束的语句。for中使循环趋于结束的操作可以包含在“表达式3”中。

由while完成的循环,用for循环都能完成。

【考点6】 break语句和continue语句
1.break语句

(1)在break后面加上分号就可以构成break语句。break语句还可以用于从循环体内跳出,即提前结束循环。

(2)说明。

break语句只能出现在循环体内及switch语句内,不能用于其他语句。

当break语句出现在循环体的switch语句体内时,其作用只是跳出该switch语句体。当break出现在循环体中,但并不在switch语句体内时,则在执行break后,跳出本层循环,当然也不再进行条件判断。

2.continue语句

(1)一般形式。

continue;

(2)作用。结束本次循环,即跳过循环体中continue语句下面尚未执行的语句,转而去重新判定循环条件是否成立,从而确定下一次循环是否继续执行。

2.2.6 数组

【考点1】 一维数组
1.一维数组的定义

一维数组是指数组中的每个元素只带有一个下标的数组。一般形式:

类型说明符 数组名[常量表达式];

2.一维数组元素的引用

一维数组元素的引用形式:

数组名[下标表达式];

一个数组元素实质上是一个变量名,代表内存中的一个存储单元,一个数组占据的是一连串连续的存储单元。

引用数组元素时,数组的下标可以是整型常量,也可以是整型表达式。

数组必须先定义后使用。

只能逐个引用数组元素而不能一次引用整个数组。

3.一维数组的初始化

当数组定义后,系统会为该数组在内存中开辟一串连续的存储单元,但这些存储单元中并没有确定的值。可以在定义数组时为所包含的数组元素赋初值,例如:

int a[6]={ 0,1,2,3,4,5 };

所赋初值放在一对花括号中,数据类型必须与所定义类型一致。

所赋初值之间用逗号隔开,系统将按这些数值的排列顺序,从a[0]元素开始依次给数组a中的元素赋初值。

不能跳过前面的元素给后面的元素赋初值,但是允许将前面元素赋值为0。

当所赋初值个数少于所定义数组的元素个数时,将自动给后面的其他元素补初值0。

可以通过赋初值来定义一维数组的大小,定义数组时方括号中可以不指定数组的大小。

【考点2】 二维数组
1.二维数组的定义

(1)在C语言中,二维数组中元素排列的顺序是按行存放,即在内存中先顺序存放第1行的元素,再顺序存放第2行的元素。二维数组元素的存储总是占用一块连续的内存单元。

(2)一般形式。

类型说明符 数组名[常量表达式1][常量表达式2];

2.二维数组元素的引用

二维数组元素的引用形式:

数组名[下标表达式1][下标表达式2];

数组的下标可以是整型表达式。

数组元素可以出现在表达式中,也可以被赋值。

3.二维数组的初始化

可以在定义二维数组的同时给二维数组的各元素赋初值。

全部初值放在一对花括号中,每一行的初值又分别标识在一对花括号中,之间用逗号隔开。

当某行一对花括号内的初值个数少于该行中元素的个数时,系统将自动地给后面的元素赋初值0。

不能跳过每行前面的元素而给后面的元素赋初值。

4.通过赋初值定义二维数组的大小

对于一维数组,可以在数组定义语句中省略方括号中的常量表达式,通过所赋初值的个数来确定数组的大小;对于二维数组,只可以省略第1个方括号中的常量表达式,而不能省略第2个方括号中的常量表达式。

【考点3】 字符数组
1.字符数组的定义

字符数组就是数组中的每个元素都是字符。定义方法同普通数组的定义方法相同,即逐个对数组元素赋值。

2.字符数组的初始化及引用

(1)初始化。对字符数组初始化,可逐个元素地赋值,即把字符逐个赋给数组元素。

如果花括号中提供的初值个数(字符个数)大于数组长度,则编译时会按语法错误处理。

如果初值个数小于数组长度,则将这些字符赋给数组中前面那些元素,其余的元素赋值为空字符(\0)。

(2)引用形式。采用下标引用,即数组名[下标]。

3.字符串和字符串结束标志

C语言中,将字符串作为字符数组来处理。为了测定字符串的实际长度,C语言规定了一个字符串结束标志,即字符“\0”。也就是说,遇到字符“\0”,表示字符串结束,由它前面的字符组成字符串。

4.字符数组的输入/输出

字符数组的输入/输出有以下两种方法。

用“%c”格式符,将字符逐个输入或输出。

用“%s”格式符,将整个字符串一次输入或输出。

5.字符串处理函数

C语言没有提供对字符串进行整体操作的运算符,但在C语言的函数库中提供了一些用来处理字符串的函数。在调用这些函数前, 须在程序前面的命令行中包含标准头文件“string.h”。

puts():调用形式为puts(字符数组),将一个字符串(以’\0’结束)输出到终端设备。

gets():调用形式为gets(字符数组),从终端输入一个字符串到字符数组中,并且得到一个函数值。

strcpy():调用形式为strcpy(字符数组1,字符数组2),把字符数组2所指字符串的内容复制到字符数组1所指存储空间中。函数返回字符数组1的值,即目标字符串的首地址。

strcat():调用形式为strcat(字符数组1,字符数组2),该函数将字符数组2所指字符串的内容连接到字符数组1所指的字符串后面,并自动覆盖字符数组1字符串末尾的’\0’。该函数返回字符数组1的地址值。

strlen():调用形式为strlen(字符数组),此函数计算出以“字符数组”为起始地址的字符串的长度,并将其作为函数值返回。

strcmp():调用形式为strcmp(字符数组1,字符数组2),该函数用来比较字符数组1和字符数组2所指字符串的大小。若字符数组1大于字符数组2,则函数值大于0(正数);若字符数组1等于字符数组2,则函数值等于0;若字符数组1小于字符数组2,则函数值小于0(负数)。

2.2.7 函数

【考点1】 函数概述

在C语言中,子程序的作用是由函数实现的。一个C程序可由一个主函数和若干个其他函数构成,且只能有一个主函数。由主函数来调用其他函数,其他子函数之间也可以互相调用。

C程序的执行总是从main()函数开始。调用其他函数完毕后,程序流程回到main()函数,继续执行main()函数中的其他语句,直到main()函数结束,则整个程序的运行结束。

从用户使用的角度看,函数分类如下。

标准函数,即库函数。这些函数由系统提供,可以直接使用。

自定义的函数,用于解决用户需要时设计并定义的函数。

从函数的形式看,函数分为无参函数和有参函数。

【考点2】 函数参数和函数返回值
1.形式参数和实际参数

当定义函数时,函数名后面圆括号中的变量称为“形式参数”(简称“形参”)。

在主调函数中,函数名后面圆括号中的参数(可以是一个表达式)称为“实际参数”(简称“实参”)。

2.函数的返回值

(1)定义:函数的返回值就是通过函数调用使主调函数得到一个确定的值。

(2)表达形式。

return 表达式;

或者

return(表达式);

或者

return;

return 语句中的表达式值的类型必须与函数首部所说明的类型一致。若类型不一致,则以函数值的类型为准,由系统自动进行强制转换。

当函数没有指明返回值,或没有返回语句时,函数返回一个不确定的值。为了使函数不返回任何值,可以使用void定义无类型函数。

【考点3】 函数的调用
1.函数调用的一般形式

函数名(实参列表);

函数的调用可分为调用无参函数和调用有参函数两种。

调用无参函数,不用“实参列表”,但圆括号不能省略。

调用有参函数时,若实参列表中有多个实参,则各参数间用逗号隔开。实参与形参要求类型一致。

2.函数的说明

C语言中,除了主函数外,对于用户定义的函数要遵循先定义后使用的规则。若把函数的定义放在调用之后,则应该在调用之前对函数进行说明(或函数原型说明)。

函数说明的一般形式:

类型名 函数名(参数类型1 ,参数类型2 ,…,参数类型n);

或者

类型名 函数名(参数类型1 参数名1,参数类型2 参数名2 ,…,参数类型n参数名n);

【考点4】 函数的嵌套调用与递归调用
1.函数的嵌套调用

C语言函数定义都是独立的、互相平行的,C语句不允许嵌套定义函数。一个函数内不能定义另一个函数,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。

2.函数的递归调用

在调用一个函数的过程中又出现直接或间接地调用该函数本身的,称为函数的递归调用。

使用递归法解决问题,需符合的条件如下。

可以把要解决的问题转化为一个新的问题。而这个新的问题的解决方法仍与原来问题的解决方法相同,只是所处理的对象有规律地递增或递减。

可以应用这个转化过程使问题得到解决。

必须有一个明确的结束递归的条件。

【考点5】 数组元素和数组名作为函数实参
1.数组元素作为函数实参

数组元素可以作为函数实参,与变量作为实参一样,按照单向值传递的方式传递。

2.数组名作为函数实参

可以用数组名作为函数实参。此时函数的形参是与数组类型一致的指针变量,这里的数组名是整个数组的首地址。

【考点6】 全局变量和局部变量

在函数内部定义的变量称为局部变量,只能在本函数内部使用。

在函数外部定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其他函数所共用,它的有效范围从定义变量开始到本文件结束。

如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用。

【考点7】 变量的存储类别
1.auto变量

当在函数内部或复合语句内定义变量时,如果没有指定存储类别,或使用了auto说明符,系统就认为所定义的变量具有自动类别。

2.register变量

register变量也是自动类变量。它与auto变量的区别仅在于:用register说明变量是建议编译程序将变量的值保留在CPU的寄存器中,而不是像一般变量那样占用内存单元。

3.static变量

当函数体(或复合语句)内部用static来说明一个变量时,可以称该变量为静态局部变量。它与auto变量、register变量的本质区别如下。

在整个程序运行期间,static变量在内存中的静态存储区中占据“永久”性的存储单元。即使退出函数,下次再进入该函数时,static变量仍使用原来的存储单元。由于不释放这些存储单元,这些存储单元中的值得以保留,因此可以继续使用存储单元中原来的值。

static变量的初值是在编译时赋予的,在程序执行期间不再赋以初值。对未赋值的局部变量,C语言编译程序自动给它赋初值0。

2.2.8 指针

【考点1】 地址和指针

在C语言中,将地址形象地称为“指针”。一个变量的地址称为变量的指针。用来存放另一个变量的地址的变量(指针),称为指针变量。

【考点2】 变量的指针和指向变量地址的指针变量
1.指针变量的定义

定义指针变量的一般形式:

类型名 *指针变量名1,*指针变量名2,… ;

例如:

int *p,*t;

2.指针变量的引用

指针变量中只能存放地址(指针),与指针相关的两个运算符是“&”(取地址运算符)和“*”(指针运算符)。

3.指针变量作为函数参数

指针类型数据可以作为函数参数来进行传递。

作用:将一个变量的地址传送到另一个函数中,参与该函数的运算。

【考点3】 数组与指针
1.指向数组元素的指针

C语言规定数组名代表数组的首地址,也就是数组中第0号元素的地址。

定义指向数组元素的指针变量的方法,与定义指向变量的指针变量相同。

2.通过指针引用数组元素

如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。

3.数组名作为函数实参

当数组名作为参数被传递时,若形参数组中各元素发生了变化,则原实参数组各元素的值也随之变化。

如果用数组元素作为实参,情况就与变量作为实参时一样,是值传递的方式。

4.指向多维数组的指针和指针变量

多维数组可以看作一维数组的延伸,多维数组的内存单元也是连续的内存单元。C语言实际上是把多维数组当成一维数组来处理的。

【考点4】 字符串与指针
1.字符串的表示形式

可用字符数组存放一个字符串,然后输出该字符串。

可用字符指针指向一个字符串,也可用字符指针指向字符串中的字符。

2.字符串指针作为函数参数

将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法,即用字符数组名作为参数或用指向字符串的指针变量作为参数来进行传递。

3.字符数组和字符指针变量的区别

字符数组由若干个元素组成,每个元素中存放一个字符,而字符指针变量中存放的是地址,不是将字符串的内容存放到字符指针变量中。

赋值方式不同。

字符数组可以在定义时对其整体赋初值,但在赋值语句中不能完成整体赋值。而字符指针变量既可以在定义时赋初值,也可以在赋值语句中赋初值。

编译时不同。

在程序中,指针变量的值可以改变。而数组名虽然代表了地址,但它的值是一个固定的值,不能改变。

【考点5】 指向函数的指针

指针变量可以指向一个函数,编译时,一个函数将被分配给一个入口地址,这个入口地址就称为该函数的指针。因此,可以通过使用一个指向函数的指针变量调用此函数。

说明:

指向函数的指针变量的一般定义形式如下。

数据类型 (*指针变量名)();

当给函数的指针变量赋值时,只需给出函数名而不必给出参数。

当用函数的指针变量调用函数时,只需将(*s)代替函数名即可(s为已经定义过的指向函数的指针变量名),在(*s)之后的圆括号中根据需要写上实参。

对指向函数的指针变量,有些运算如++s、--s、s++等都是没有意义的。

【考点6】 指针数组和指向指针的指针
1.指针数组的概念

若在一个数组中,其元素均为指针类型数据,这样的数组称为指针数组。

定义一维指针数组的一般形式:

类型名 *数组名[数组长度];

2.指向指针的指针

指向指针数据的指针变量,简称为指向指针的指针,通常称为二级指针。

定义一个指向指针数据的指针变量的一般形式:

  类型名 **指针变量名;

2.2.9 编译预处理和动态存储分配

【考点1】 宏定义
1.不带参数的宏定义

(1)定义形式。

#define 宏名 替换文本

或者

#define 宏名

(2)说明。

在“define”“宏名”和“替换文本”之间要用空格隔开。

可以用 #undef 命令终止宏定义的作用域。

当进行宏定义时,可以引用已定义的宏名。

同一个宏名不能重复定义。

2.带参数的宏定义

(1)定义形式。

#define宏名(参数列表) 字符串

宏定义不仅进行简单的字符串替换,还可进行参数替换。

(2)执行过程。

如果程序中有带实参的宏,则按#define命令行中指定的字符串从左到右进行置换。

如果字符串中包含宏中的形参(如 x、y),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。

如果宏定义的字符串中的字符不是参数字符(如 (x*y)中的“*”),则保留。这样就形成了置换的字符串。

【考点2】 关于动态存储的函数

malloc()函数的原型:void * malloc(unsigned int size);。

malloc()函数的作用:在内存的动态存储区中,系统自动分配长度为size的一段连续空间。若此函数执行成功,则函数返回值为指向被分配域的起始地址的指针(该函数的返回值的基本类型为void)。若该函数执行失败(如内存空间不足的情况),则函数返回值为空指针(NULL)。

2.2.10 结构体和共用体

【考点1】 用typedef说明一种新类型

(1)一般形式。

typedef 类型名 标识符;

其中,“类型名”一定是在此语句之前已有定义的类型标识符。“标识符”是一个由用户定义的标识符,用来标识新的类型名。

(2)typedef语句的作用:用标识符来代表已存在的类型名,并没有产生新的数据类型,因此,原有的类型名依然有效。

(3)声明一个新的类型名的具体步骤如下。

按定义变量的方法写出定义的主体(如float a;)。

将变量名换成新类型名(如将a换成FLO)。

在最左侧加上关键字typedef(如 typedef float FLO;)。

用新类型名去定义其他的变量(如FLO b;)。

【考点2】 结构体数据类型

(1)声明一个结构体类型的一般形式如下。

struct 结构体名

{ 成员列表 };

(2)结构体类型可以用以下形式说明。

struct 结构体标识名

{

 类型名1 结构体成员名表1;

 类型名2 结构体成员名表2;

 …

 类型名n 结构体成员名表n;

};

说明:

“结构体标识名”和“结构体成员名表”都必须是合法的用户定义的标识符。

每个结构体成员名表中都可以含有多个同类型的成员名,它们之间以逗号分隔。

结构体类型说明中的“类型名1”~“类型名n”,不仅可以是简单数据类型,也可以是某种结构体类型。当结构体类型说明中又包含结构体时,称为结构体的嵌套。

美国国家标准学会(American National Standards Institute,ANSI)的C语言标准规定结构体至多允许嵌套15层,并且允许内嵌结构体成员的名字与外层成员的名字相同。

【考点3】 结构体类型变量的定义
1.先声明结构体类型再定义变量名

例如,已经定义了一个结构体类型struct time,则:

struct time    time1,time2;

结构体类型名  结构体变量名;

time1和time2为struct time类型变量,即它们都具有struct time类型的结构。

2.在声明类型的同时定义变量

一般形式:

struct 结构体名 { 成员列表 } 变量名列表;

3.直接定义结构体类型变量

一般形式:

struct { 成员列表 } 变量名列表;

即不出现结构体名。

【考点4】 结构体类型变量的引用

引用结构体变量时应注意如下几点。

对结构体变量中的数据可以逐步引用成员进行操作。结构体变量中的成员用以下方式引用:结构体变量名.成员名。

如果结构体的某个成员本身又是一个结构体类型,则可以使用若干个成员运算符“.”,一级一级地找到最低的一级成员。只能对最低一级的成员进行赋值、存取及运算。

结构体变量的初始化,是指逐个对结构体变量的各个成员进行初始化的过程。

【考点5】 结构体数组

(1)一般形式:

struct 结构体变量名 { 成员列表} 数组名[常量表达式];

(2)结构体数组的初值应顺序地放在一对花括号中。

【考点6】 指向结构体类型数据的指针
1.指向结构体变量的指针

“->”称为指向运算符。

“结构体变量.成员名”“(*结构体指针变量名).成员名”“结构体指针变量名->成员名”这3种形式是等价的。

2.指向结构体数组的指针

结构体数组及其元素也可以用指针变量来指向。当使用指针变量指向结构体数组时,只要把该结构体数组中的每个元素当作普通的结构体变量使用即可。

3.结构体变量和指向结构体的指针作为函数参数

将一个结构体变量的值传递给另一个函数,有如下方法。

结构体变量的成员作为实参传递给主调函数。

可以用结构体变量作为一个整体实参。

C语言中,允许将结构体变量的地址作为实参传递,这时,对应的形参应该是一个类型相同的结构体类型的指针。

【考点7】 链表
1.链表的概念

(1)定义:链表是一种常见的、重要的数据结构,也是一种动态地进行存储单元分配的结构。

(2)说明。

链表中的各元素在内存中不一定是连续存放的。

一个节点中应包含一个指针变量,用于存放下一个节点的地址。

链表最后一个节点的指针域置成空值,标志着链表的结束。

每一个链表都用一个“头指针”变量来指向链表的开始,该指针称为HEAD指针。在HEAD指针中存放了链表第1个节点的地址。

2.顺序访问链表中各节点的数据域

所谓“访问”,可以理解为读取各节点的数据域中的值以进行各种运算、修改各节点的数据域中的值等一系列的操作。

输出单向链表各节点数据域中内容的算法比较简单,只需利用一个工作指针(p),从头到尾依次指向链表中的每个节点。当指针指向某个节点时,就输出该节点数据域中的内容,直到遇到链表结束标志为止。如果是空链表,就只输出提示信息并返回调用函数。

3.删除链表中的节点

为了删除单向链表中的某个节点,首先要找到待删除的节点的前趋节点(当前要删除节点的前面一个节点),然后将此前趋节点的指针指向待删除节点的后续节点(当前要删除节点的下一个节点),最后释放被删除节点所占的存储空间即可。

2.2.11 文件

【考点1】 C语言文件的概念

C程序把文件分为ASCII文件和二进制文件。ASCII文件又称文本文件。

在C语言中,文件是一个字节流或二进制流,也就是说,对于输入/输出的数据都按“数据流”的形式进行处理。

文件输入/输出方式也称“存取方式”。C语言中,文件有两种存取方式:顺序存取和直接存取。

【考点2】 文件类型指针

可以用结构体类型来定义文件类型的指针变量,一般形式:

FILE *fp;

fp是一个指向FILE结构体类型的指针变量。

【考点3】 文件的打开与关闭
1.fopen()函数

(1)调用形式。

fopen(文件名,文件使用方式);

函数返回一个指向FILE类型的指针。

无论使用哪种方式,当打开文件时出现了错误,fopen函数都将返回NULL。

(2)最常用的文件使用方式及其含义如下。

r:为读而打开文本文件。

rb:为读而打开一个二进制文件。

w:为写而打开文本文件。

wb:为写而打开一个二进制文件。

a:为在文件后面添加数据而打开文本文件。

ab:为在文件后面添加数据而打开一个二进制文件。其余功能与“a”相同。

r+:为读和写而打开文本文件。

rb+:为读和写而打开一个二进制文件。

w+:首先建立一个新文件,进行写操作,随后可以从头开始读。如果指定的文件已存在,则文件原有的内容将全部消失。

wb+:功能与“w+”相同,只是在随后的读和写时,可以由位置函数设置读和写的起始位置。

a+:功能与“a”相同,只是在文件尾部添加新的数据之后,可以从头开始读。

ab+:功能与“a+”相同,只是在文件尾部添加新的数据之后,可以由位置函数设置读的起始位置。

2.fclose()函数

调用形式:

fclose(文件指针);

若对文件的操作方式为“读”方式,则经以上函数调用之后,要使文件指针与文件脱离联系,可以重新分配文件指针去指向其他文件。

若对文件的操作方式为“写”方式,则系统首先把该文件缓冲区中的剩余数据全部输出到文件中,然后使文件指针与文件脱离联系。

在完成了对文件的操作之后,应当关闭文件,否则文件缓冲区中的剩余数据就会丢失。

当执行了关闭操作后,若关闭成功则函数返回0,否则返回非0。

【考点4】 文件的读写
1.fread()函数和fwrite()函数

当要求一次性读写一组数据时,如一个实数或一个结构体变量的值,就可以使用fread()函数和fwrite()函数,它们的一般形式:

fread(buffer,size,count,fp);

fwrite(buffer,size,count,fp);

其中,buffer代表的是一个指针变量;size代表的是要读写的字节数;count用来指定每读写一次,输入/输出数据块的个数(每个数据块具有size个字节);fp是文件类型指针。

2.fscanf()函数和fprintf()函数

fscanf()函数和fprintf()函数都是格式化的读和写函数,与scanf()和printf()函数作用相似,但fscanf()函数和fprintf()函数读写对象是磁盘文件上的数据。

它们的一般调用形式:

fscanf(文件指针,格式字符串,输入列表);

fprintf(文件指针,格式字符串,输出列表);

3.fputs()函数

fputs()函数是用来把字符串输出到文件中,调用形式:

fputs(str,fp);

其中,str是要输出的字符;fp是文件指针,字符串末尾的“\0”不输出。

【考点5】 文件的定位

rewind()函数的调用形式:

rewind(fp);

该函数的功能是使文件的位置指针重新返回到文件的开头,其中fp为文件指针,且该函数没有返回值。