C语言知识点总结(最全版)快快收藏
杨恒昌 2021-02-23 10:05:37


C语言知识点总结(最全版)快快收藏


第一部分 "C 语言基础知识"知识点

1、C 程序的基本结构 C程序是由函数构成的。每个程序由一个或多个函数组成,其中必须有且仅有一个主函数main( )。 main 函数是一个可执行 C 语言程序的入口和正常出口,而不论其在整个程序中书写的位置如何。 在 C 语言中,大小写字母是有区别的。(例如习惯使用小写字母定义变量,用大写字母定义常量)。 C 程序的注释有两种方法,一种是行注释,使用"//";另外一种是块注释,使用"/* */",注意

"/*"与"*/"不能嵌套使用。 C 语言书写较为灵活,但是提倡采用缩进格式进行程序书写,以体现语句之间的层次感。 C 程序每条语句以"分号"作为结束标志。以下几种情况不得使用分号:

(1) 所定义的函数名称后不得使用分号; (2) if…else…语句是一个整体,中间不能使用分号将其分隔开; (3) 预编译命令后不能使用分号。

2、C 程序开发步骤

C 语言在计算机上的开发过程主要由以下四个步骤组成: 第一步:编辑。生成后缀名为".c"的源文件 第二步:编译。生成后缀名为".obj"的目标文件 第三步:连接。生成后缀名为".exe"的可执行文件 第四步:运行。

3、VC++6.0 开发工具的使用

按下功能键 Ctrl+F7 编译程序;按下功能键 F7 连接程序;按下功能键 Ctrl+F5 运行程序;若程序在编译和连接过程中有语法错误,则按下功能键 F4 定位错误所在行并根据错误提示信息改正错误(原则是先解决 error,再解决 warning)。

4、C 语言中标识符的命名规则

标识符由字母、数字、下划线组成;规定第一个字符必须为字母或下划线。 标识符定义的变量名、函数名、常量名等最好做到"见名知义";大小写代表不同含义;不能使

用关键字;最好不要与 C 语言的库函数同名。

5、C 语言的数据类型

C 语言的数据类型由基本类型和复杂类型构成。其中基本数据类型包括字符型(char)、整型(int,short,long)、实型(float,double);复杂数据类型包括指针类型、数组、结构体、联合体。

char 型占 1 个字节、short 型占 2 个字节、long 型和 float 型占 4 个字节、double 型占 8 个字节。

6、常量

(1) 字符型常量(用单引号括起来的一个字符) 两种形式——普通字符、转义字符(掌握'\n'、'\0'、'\t'、'\\'、'\''、'\"'、'\ddd'、'\xhh') 不论普通字符,还是转义字符,都等价于 0-127 之间的某个整数,即 ASCII 码表。

(2) 整型常量 三种表示形式——十进制形式、八进制形式(加前导 0)、十六进制形式(加前导 0x) 注意:C 语言的整型常量没有二进制表示形式。

(3) 实型常量 两种表现形式——小数表示形式、指数表示形式(由"十进制小数"+"e 或 E"+"十进制整数"组成,注意:e 或 E 的两侧必须有数,其后必须为整数)

(4) 字符串常量(用双引号括起来的零个或者若干多个字符) 编译系统会在字符串的最后添加'\0'作为字符串的结束符。比较'a'和"a"的不同。

(5) 符号常量:例如 #define PI 3.14159

7、变量

变量必须"先定义、后使用"。变量代表计算机内存中一定大小的存储空间,具体代表多少字节的存

储空间示变量的类型而定,该存储空间中存放的数据就是变量的值。 注意:变量定义后如果未赋初值,则变量的初值是随机数。因此变量应该先赋值再使用才有意义。为

变量赋值的几种方法:①初始化;②赋值语句;③调用标准输入函数从键盘为变量赋值。 (1) 字符型变量

用"char"定义字符型变量,字符型变量存放 1 个字节的数值。对于无符号字符型变量,取值范围是 0~255,对于有符号字符型变量,取值范围是-128~+127。

(2) 整型变量 用"int"、"short"、"long"定义整型变量,其中 int 型和 long 型占用 4 个字节的存储空间,short型占用 2 个字节的存储空间。

(3) 实型变量 用"float"、"double"定义实型变量,其中 float 型占用 4 个字节的存储空间,double 型占用 8个字节的存储空间。

8、表达式

表达式具有广泛的含义,根据运算符不同,有赋值表达式、算术表达式、逻辑表达式、关系表达式等,甚至单独的一个常量或一个变量也是一个表达式。

9、运算符

(1) 算术运算符(+、-、*、/、%) 除号(/)——当除数和被除数都为整数时,相除的结果自动取整。 求余号(%)——要求"%"号的两侧必须是整数,不能是实数。

(2) 赋值运算符( = ) 格式"变量 = 表达式",表示将表达式的值赋值到变量对应的存储空间里。 注意:赋值号"="的左侧必须是变量,不能是常量或者表达式。

(3) 复合赋值运算符(+=、-=、*=、/=、%=) 由算术运算符和赋值运算符组成,是两个运算符功能的组合。例如:a += a + c;

*(4) 自增、自减运算符(++、- -)表达式 当自增、自减运算符单独使用时放在变量前面或者后面没有区别。

例如:++i; 等价于 i++; 等价于 i=i+1; 自增、自减运算符与其它运算符共同存在于表达式中时,放在变量前和变量后有区别。

例如:若定义 int i = 3, j; 则 j = ++i; 语句执行后 i 的值为 4,j 的值为 4。 则 j = i++; 语句执行后 i 的值为 4,j 的值为 3。

(5) 关系运算符(>、<、>=、<=、==、!=) 注意:不能混淆赋值运算符(=)和关系运算符中的等于号(==)。前者是做赋值操作,

后者是判断两个数是否相等。

关系表达式的值只有"逻辑真(用数值 1 表示)"和"逻辑假(用数值 0 表示)"两种情况。

如果表达式的值为实型,不能使用"=="或者"!="判断两个值相等还是不相等。 (6) 逻辑运算符(!、&&、||)

运算逻辑表达式时,当参与运算的数"非 0 表示真"、"0 表示假";表达式的解"1 表示真"、"0 表示假"。

注意:"短路特性"的含义。如果逻辑与"&&"运算符左侧表达式的值为 0(假),则该运算符右侧的表达式被"短路",即运算过程被计算机省略掉;如果逻辑或"||"运算符左侧表达式的值为 1(真),则该运算符右侧的表达式被"短路"。

(7) 位运算符(~、^、&、|、<<、>>) 只适用于字符型和整数型变量。是 C 语言具有低级语言能力的体现。 注意:不能混淆逻辑与运算符"&&"和按位与运算符"&";逻辑或运算符"||"和按位

或运算符"|";逻辑非运算符"!"和按位取反运算符"~"。 (8) 逗号运算符(,)

功能为从左至右依次计算由逗号隔开的各表达式的值,最后一个表达式的值即为整个逗号

表达式的值。是优先级最低的运算符。 (9) 条件运算符(? :)

这是 C 语言中唯一的一个三目运算符,其形式为:<表达式 1> ? <表达式 2> :<表达式 3> (10) 求字节运算符 sizeof

注意:不能混淆求字节运算符 sizeof 和字符串长度库函数 strlen( )。前者是运算符,后者是函数。sizeof("Hello")的值为 6,而 strlen("Hello")的返回值为 5。

(11) 各种运算符混合运算时的优先级排队口决 二、 二、 二、 与、 或、 二、 逗 ! * / % + - > >= < <= == != && || = ,

(12) 数据类型的强制转换 格式:(转换类型名)表达式。 注意:类型名两侧的小括号不能省略,表达式示情况而定可以增加小括号。

第二部分 "C 程序的三种基本结构"知识点

1、语句 C 语言的语句分为四类:①简单语句(分为表达式语句、函数调用语句);②空语句;③复合语句(由一对大括号括起来的一条或多条语句,复合语句在语法上视为一条语句);④控制语句(分为结构化语句,

如 if 语句、switch 语句、while 语句、do-while 语句、for 语句;非结构化语句,如 break 语句、continue语句、return 语句、goto 语句)。

2、程序的三种基本结构

顺序结构、选择结构、循环结构

3、顺序结构

(1) printf()函数的使用 难点

一般形式为:printf("格式控制字符串",输出项列表);

其中"格式控制字符串"包含三类字符——普通字符(即原模原样输出的字符,主要用于做

提示信息)、格式说明符(以"%"开头)、转义字符(以"/"开头) 输出项列表是可以省略的,当"格式控制字符串"中没有"格式说明符"时,输出项列表省

略;若是有"格式说明符"时,输出项列表不能省略,并且有几个格式说明符,输出项列表

就必须有几个对应数据类型的表达式,各表达式之间用逗号隔开。 需要掌握的格式说明符有:%c、%d、%f、%s、%u、%o、%x、%ld、%lf、%e、%%

(2) scanf()函数的使用 难点 一般形式为:scanf("格式控制字符串",地址列表); 其中"格式控制字符串"包含两类字符——普通字符(需从键盘原模原样输入的字符,一般

起分隔和提示作用)、格式说明符(以"%"开头) 地址列表通常是不省略的,根据"格式控制字符串"中包含多少个格式说明符,地址列表中就有几个地址。对于普通变量,需在变量名前加上取地址符"&",数组名前不需加"&"。 注意 1:scanf()函数的"格式控制字符串"中不能包含"转义字符",否则将引起输入无效。如 scanf ("%d\n", &a);是错误的。 注意 2:scanf()的格式控制字符串中的普通字符不是用来显示的, 而是输入时要求照普通字符原模原样输入。 注意 3:scanf()中参数的第二部分一定是地址列表,不能是表达式。 注意 4:字符和数值混合输入且二者中间没有分隔符,需注意何时加空格。例如:已定义

char x; int y; scanf("%c%d", &x, &y); 此时从键盘输入时,字符和整数之间需加空格; 而 scanf("%d%c", &y, &x); 此时从键盘输入时,整数和字符之间不能加空格。

(3) getchar()函数的使用 函数原型为:char getchar(void); 例如:char a; a=getchar( ); 该函数使用时关注函数的返回值。

(4) putchar()函数的使用 函数原型为:char putchar(char); 例如:putchar('A'); 该函数使用时关注函数的参数。

(5) printf( )、scanf( )、getchar( )、putchar( )这四个函数都属于标准输入输出库函数,调用时需在程序中包含头文件 stdio.h。

(6) 例如已定义:char a, b='A'; 则以下函数调用等价

4、选择结构

scanf("%c", &a); 等价于 a = getchar( ); printf("%c", b); 等价于 putchar(b);

(1) if 语句 if 语句的三种形式——单分支选择结构、双分支选择结构、多分支选择结构。 单分支选择结构: if(表达式)

注意:if 语句的表达式很多时候是关系表达式,不要将"=="号误用成"="号。 说明 1:表达式两侧的小括号不能省略,此表达式可以是 C 语言中任意合法的表达式,只

要表达式的值为非零(真),就执行其后的语句体;否则,结束 if 语句。 说明 2:由于"if(表达式)"和"语句体"是一个整体,在语法上看作一条语句,因此在"(表

达式)"后面不能加";",如果加了分号,则 if 语句的语句体就成了空语句。 说明 3:"if(表达式)"会自动结合一条语句,如果语句体有多于一条语句时,必须使用复

合语句,即用大括号将多条语句括起来。

语句体;

易错点

易错点

说明 4:为了表示语句体从属于 if,书写时,应使语句体与关键字 if 的位置有缩进。 双分支选择结构(二选一):

说明 1:表达式只写在关键字 if 的后面,不能写在 else 的后面。 说明 2:"if"、"语句 1"、"else"、"语句 2"是一个整体,在语法上看作一条语句,因此在

"(表达式)"后面不能加分号,在关键字 else 后面也不能加分号。 说明 3:如果"语句体 1"、"语句体 2"有多于一条语句,则必须使用复合语句。 说明 4:书写时,应使关键字 if 和 else 对齐,"语句体 1"和 if 之间有缩进,"语句体 2"

和 else 之间有缩进。 多分支选择结构(多选一):

说明:表达式一定是跟在关键字"if"的后面,不能跟在关键字"else"的后面。

if(表达式) 语句体 1;

else 语句体 2;

if(表达式 1) 语句体 1; else if(表达式 2) 语句体 2; … else if(表达式 n) 语句体 n; else 语句体 n+1;

(2) switch 语句 switch(表达式) { case 常量表达式 1: 语句 1; <break;> case 常量表达式 2: 语句 2; <break;> ……

case 常量表达式 n: 语句 n; <break;> 说明 1:关键字 switch 后面表达式的值必须是整型或者字符型,不能是实型。 说明 2:关键字 case 后面是"常量表达式",只能是常量或常量表达式,不能是变量或者变量

表达式。且表达式的值必须是整型或者字符型,不能是实型和字符串。书写时注意

"case"与"常量表达式"之间必须有空格;"常量表达式"后面是冒号。 说明 3:每个 case 分支后面的常量表达式必须互不相同。 说明 4:每一个分支后面的"break"可以省略,如果省略,则程序继续执行下一个 case 分支

的语句,否则执行完该 case 分支的语句就跳出 switch 语句。 说明 5:多个 case 分支可以共用一组语句,当某个 case 分支后面省略了语句,则意味着该分支

与它后面紧邻的分支共用语句。 说明 6:default 可以省略。 说明 7:书写时必须注意①switch 后面的表达式必须用小括号括起;②表达式的小括号后面不

能加分号;③case 和其后常量表达式之间必须加空格;④常量表达式以及 default 后面必须加冒号。

5、循环结构

循环结构程序编写过程中的三要素——循环的初始条件、循环的终止条件、控制循环结束条件的变化。

<default : 语句 n+1;> }

while(表达式) 循环体;

重点

(1) while 语句

while 语句构成的循环称为当型循环。当表达式的值为非零,则执行循环体,否则结束循环。 说明 1:表达式可以是 C 语言中任意合法的表达式,书写时不能省略其两侧的小括

号。 说明 2:"while(表达式)"会自动结合一条语句,如果循环体有多于一条语句时,必须使用复合

语句。 说明 3:"while(表达式)"与"循环体"是一个整体,"(表达式)"后面不应加分号,否则循环

体就成了一条空语句。 (2) do-while 语句 do

循环体;

do-while 语句构成的循环称为直到型循环。先执行循环体,再判断表达式的值是否为非零,是则继续下一次循环,否则结束循环。 说明 1:do 必须和 while 联合使用。 说明 2:如果循环体有多于一条语句时,必须使用复合语句。 说明 3:表达式可以是 C 语言中任何合法的表达式,书写时其两侧的小括号不能省略,"while(表

达式)"后面的分号也不能省略。 (3) for 语句

说明 1:小括号里有三个表达式,每个表达式之间用分号隔开。这三个表达式都可以缺省,但是应该在其它相应的位置补齐。

说明 2:"表达式 1"也称为初始表达式,在整个循环开始前执行一次;"表达式 2"也称终止表达式,每轮循环进入前执行一次,如果该表达式的值为非零,则执行循环体,否则结

束循环;"表达式 3"也称循环表达式,每次循环结束时执行一次,常用来控制循环的初始条件逐渐转变到终止条件。

说明 3:"for(…)"会自动结合一条语句,当循环体有多于一条语句时,必须使用 复合语句。

(4) break 语句 break 语句出现在循环体中的作用是提前结束本层循环。 break 语句出现在 switch 语句中的作用是跳出本层 switch 语句。

(5) continue 语句 continue 语句只能出现在循环体中,其作用是提前结束本轮循环,进入下一轮循环。即当

continue 语句被执行时,放置在该语句之后的其它语句将被略过。注意:continue 语句并没有使整个循环结束。

6、常用算法、常用库函数

(1) 交换两个变量中存放的数值——使用首尾相接的三条语句。例如:已定义 int a=3, b=4, t; 若要交换 a 和 b 中的数值,使用如下三条语句 t = a; a = b; b = t;

(2) 数学函数(需包含头文件 math.h)——sqrt( )、fabs( )、pow( )、exp( ) (3) 斐波拉契数列 (4) 素数问题 (5) N 项式求和问题 (6) 迭代法

while(表达式);

for(表达式 1; 表达式 2; 表达式 3)循环体;

重点, 难点

难点 重点, 难点

第三部分 "数组、字符串"知识点

1、一维数组 (1)一维数组的定义形式:类型说明符 数组名[常量表达式]; 注意:方括号中的"常量表达式"表示该数组的元素个数。只能是常量,不能是变量或者变量表达式。 说明 1:数组一旦定义,就在内存空间中分配连续存放的若干存储单元,每一个存储单元的大小由数

据类型决定。例如有如下定义:int a[10]; 则计算机为数组 a 连续分配 10 个存储单元,每个 存储单元占用 4 个字节,总共是 40 个字节的存储空间。

说明 2:数组一旦定义,数组名就代表了一段连续存储空间的首地址,数组名是常量,永远指向该数 组第一个元素的内存单元地址。

(2)一维数组元素的引用:数组名[下标] 与一般变量一样,数组必须先定义,后使用。数组元素的引用是指使用已定义数组中的某个指定元素,

通过"下标"来指定需要引用的元素。 注意 1:下标的下限一定是"0",上限由数组定义时的常量表达式值决定,为"常量表达式值-1"。

假设已经有如下定义:int a[10]; 则引用该数组元素的下标范围是"0~9",若引用时下标超过此范围,称为数组越界,会导致程序运行出错。

注意 2:必须区分数组定义时方括号中的"常量表达式"和数组元素引用时方括号中的"下标",二者具有不同的含义和功能。前者是指明数组的大小,后者是指明要引用数组中的第几个元素。

(3)一维数组的初始化 与一般变量一样,数组定义后,如果没有为其赋初值,则数组元素中的初值是随机数。为数组元素赋

值的方法通常有两种:一种是进行初始化;一种是使用循环结构依次为每个数组元素赋值。 数组初始化的方法分为:①全部元素赋初值;②部分元素赋初值;③全部元素赋初值时可以不指定数

组长度。 (4)一维数组元素的输入、输出 由于数组中的元素是若干个相同类型的数值,不能对其进行整体的输入或者输出,必须针对单个元素

进行输入或者输出,这时就要使用循环结构,对于一维数组来说,使用单层循环。

2、二维数组

(1)二维数组的定义形式:类型说明符 数组名[常量表达式 1][ 常量表达式 2]; 说明 1:"常量表达式 1"指明二维数组的行数,"常量表达式 2"指明二维数组的列数。 说明 2:二维数组可以看作特殊的一维数组,二维数组元素在内存中是"按行存放"。 (2)二维数组元素的引用:数组名[行下标][列下标]

说明:与一维数组一样,二维数组元素引用时的行下标和列下标不能越界。假设已经有如下定义:int a[3][4]; 则引用该数组元素时,行下标的范围是"0~2",列下标的范围是"0~3"。

(3)二维数组的初始化 二维数组初始化有以下四种方式:①分行全部元素初始化(使用两层花括号);②分行部分元素初始

化;③按照数值存放顺序不分行初始化(使用一层花括号);④按照数值存放顺序不分行初始化,当对全

部元素赋初值时,可以省略确定行数的常量值。 (4)二维数组元素的输入、输出 使用双层循环嵌套对二维数组的所有元素进行输入、输出。

3、字符数组与字符串

(1)字符数组与字符串的关系 字符数组是字符型数据的集合。定义方式为:char 数组名[常量表达式]; 与其它类型的数组一样,将

数组中的各个字符看作是独立的个体。当这些字符中有'\0'时,可以将它们视为一个整体,即字符串。 字符串有常量,但是没有字符串型的变量,字符串常量使用字符数组进行存放,前提是字符数组的大

小要能容纳整个字符串,包括字符串的结束符'\0'。 (2)字符数组的初始化 当字符数组中存放的所有字符作为独立个体时,其初始化方法与其它类型的数组一样。当字符数组中

存放的是字符串时,其初始化方法有如下几种: ① char a[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; ② char a[6] = {"Hello"}; ③ char a[6] = "Hello"; ④ char a[] = "Hello"; (3)向字符数组中存放字符串的方法 定义了字符数组后,如果要向数组中存放字符串,除了以上提到的初始化方法,还有以下方法,注意

不能使用赋值语句的方法。假设已经有定义:char a[50]; 方法 1:scanf("%s", a); 注意:a 已经代表数组的首地址,前面不再有取地址符&。 方法 2:gets("%s", a); 方法 3: int i=0;

while((a[i] = getchar()) != '\n') i++; a[i] = '\0';

重点 注意:不能用赋值语句的方法向字符数组中存放字符串。以下写法是错误的,原因是数组名是常量, 永远指向数组的首地址,字符串常量书写时,系统给出其在内存中占用的一段无名存储区的首 地址,不允许将数组名这个常量重新赋值指向另一个地址空间。

char a[50]; a = "Hello"; (错误) (4)'\0'何时系统自动添加、何时需手动添加 字符串常量的结束标志是'\0',缺少了'\0',则不能称为字符串常量。以下列出何时由系统自动添加'\0',

何时需要编程者自己手动添加'\0'的几种情况。 系统自动添加的情况:(假设已有定义: char a[50];) 调用 scanf 函数从键盘输入字符串时。例如:scanf("%s", a); 调用 gets 函数从键盘输入字符串时。例如:gets(a); 以字符串常量形式对字符数组进行初始化时。例如:char a[50] = "Hello"; 调用 strcpy 函数将字符串拷贝到字符数组中时。例如:strcpy(a, "Hello");

需手动添加'\0'的情况: 以字符形式对字符数组进行初始化时。例如:char a[ ] = {'H', 'e', 'l', 'l', 'o', '\0'}; 先定义字符数组,再将单个字符赋值到各个数组元素中时。例如:char a[50];

a[0]='H'; a[1]='e'; a[2]='l'; a[3]='l'; a[4]='l'; a[5]='\0'; 对字符数组中原来存放的字符串进行处理,破坏了原字符串的'\0',对新处理后的字符串需手动添加'\0'

(5)字符串输入、输出 第一种方法:调用 scanf、printf 函数实现,格式说明符使用"%s"。例如:

char a[50]; scanf("%s", a); //当遇到空格或者回车时系统认为字符串输入结束 printf("%s", a); //字符串输出

第二种方法:调用 gets、puts 函数实现。例如: char a[50]; gets(a); //当遇到回车时系统认为字符串输入结束

puts(a); 说明:scanf 和 gets 输入字符串时的区别是——scanf 不接收空格,该函数认为空格是字符串输入结束

标志。而 gets 接收空格作为字符串中的有效字符,该函数只认为回车是字符串输入结束标志。 (6)字符串处理函数 求字符串长度函数:strlen(s)

例如:char s[50]; int len; len = strlen(s); 说明 1:使用 strlen 求字符串长度时,计算的是第一个'\0'之前的有效字符个数,函数返回值不包

括'\0'占用的字节数。 说明 2:注意区分 strlen 和 sizeof。首先,strlen 是库函数,而 sizeof 是运算符;其次,strlen 计

算的是字符串有效字符占用的字节数,不包括'\0'占用的空间,而 sizeof 计算的是字符 数组或者字符串占用内存的字节数,包括'\0'占用的空间。例如:

char s[20]="Hello"; int x, y, m, n; x = strlen(s); y = sizeof(s); m = strlen("Hello"); n = sizeof("Hello"); 以上举例中,变量 x 和 m 的值都是 5,因为 strlen 函数仅仅统计字符串中有效字符的占 用的字节数。变量 y 的值是 20,因为 sizeof(s)计算的是数组 a 在内存中占用的字节数。 变量 n 的值是 6,因为 sizeof("Hello")计算的是字符串"Hello"在内存中占用的字节数, 包括'\0'占用的空间。

字符串连接函数:strcat(s1, s2) 例如:char s1[50] = "Hello", s2[50] = " every one";

strcat(s1, s2); //表示把字符串" every one"粘贴到字符串"Hello"的后面 strcpy(s1, "every one");

字符串比较函数:strcmp(s1, s2) 说明:该函数是从左至右依次将两个字符串的对应字符取出做比较,比的是对应字符 ASCII 码

值的大小。当字符串 s1 大于字符串 s2 时,函数返回 1;当字符串 s1 等于 s2 时,函数返 回 0;当字符串 s1 小于 s2 时,函数返回-1。

字符串拷贝函数:strcpy(s1, s2) 说明:该函数将 s2 指向的字符串拷贝到 s1 指向的存储空间里,要求 s1 指向的存储空间必须足够

大,能够容纳即将拷贝的字符串。 例如: char s1[50], s2[50] = "Hello";

strcpy(s1, s2); //表示把字符数组 s2 中存放的字符串拷贝到字符数组 s1 中 strcpy(a, "China"); //表示把字符串"China"拷贝到字符数组 a 中

4、常用算法

(1)冒泡法排序 (2)选择法排序

重点

重点

第四部分 "函数"知识点

1、库函数与自定义函数

(1) 库函数:目前已学习过的库函数有标准输入输出类库函数、数学类库函数,当程序中调用库函数时,必须包含对应的头文件。例如标准输入输出类库函数对应的头文件是<stdio.h>,数学类库

函数对应的头文件是<math.h>。 (2) 用户自定义函数:用户自己编写的完成特定功能的函数,也称子函数。 (3) 一个 C 程序由一个 main 函数和若干多个子函数组成。

2、函数定义、函数调用、函数声明的概念

(1) 函数定义——即定义函数的功能。未经定义的函数不能使用。 (2) 函数调用——即执行一个函数,调用函数时,程序跳转到被调用函数的第一句开始执行,执行

至被调用函数的最后一句,然后程序返回调用该函数处。 (3) 函数说明——即通知编译系统该函数已经定义过了。

3、函数定义的格式

<函数类型> 函数名 (<参数表>) {

重点 函数首部

<函数体语句> } 函数由函数首部和函数体构成,其中函数首部由函数类型、函数名、参数表组成。 关于函数类型的说明 说明 1:函数类型分为"空类型(关键字是 void)"和"非空类型(需指定具体的返回类型,如 int、

float、double、char、指针类型、结构体类型等)"。 说明 2:当缺省"函数类型"时,默认函数返回类型为 int 型。 说明 3:当函数类型是"非空类型"时,函数体内必须有 return 语句,写成"return(表达式);",

表达式值的类型必须与函数类型一致,否则编译系统会给出警告提示。 说明 4:当函数类型是"void"时,函数体内不需要 return 语句,或者直接写"return ;"即可。 说明 5:函数类型是 C 语言中的关键字,在 VC++6.0 编译环境中是蓝色字体。 关于函数名的说明 说明 1:函数名命名必须符合 C 语言标识符的命名规则。命名函数名最好是见名知意。 说明 2:同一段程序中的各自定义函数不允许函数名同名。 关于参数表的说明

说明 1:此时参数表中的参数称为形式参数,简称"形参"。形参必须用一对小括号括起来。 说明 2:如果参数表中没有参数,称为无参函数,此时小括号中可以写关键字 void,或者什么都

不写。 说明 3:如果参数表中有参数,称为有参函数,此时小括号中必须明确申明各个参数的数据类型。

注意:每个参数都必须有各自的类型说明符,如 int fun(int a, int b, char c) 关于函数体的说明

说明 1:函数体必须用一对大括号括起来,函数体前面是说明部分,后面是执行语句部分。 说明 2:函数首部与函数体是一个整体,不能被分离开。例如,在括起参数表的小括号与括起函数

体的大括号之间加上分号是错误的。

4、函数调用

一个已经定义的函数,只有在发生函数调用时才能被执行。函数调用的过程即是程序跳转到被调用函

数的第一句开始执行,执行至被调用函数的最后一句,然后程序返回函数调用语句处。 函数调用的一般形式: (1)有参数函数的调用形式: 函数名(参数) (2)无参数函数的调用形式: 函数名( )

函数的传值调用 函数调用时的参数称为实际参数,简称"实参"。当发生函数调用时,实参将数值传递给形参,

实现函数调用时的数值传递。 为保证函数调用时正确的数值传递,"实参"与"形参"应有严格的对应关系,可以归纳为"3

个一致和 1 个不一致"——规定:实参的个数、类型、顺序必须与被调用函数形参的个数、类型、顺序保持一致。而实参与形参的参数名称可以不相同。 C 语言中函数调用的三种方式

(1)作为独立的语句。例如:printf("Hello world!"); (2)作为表达式中的一部分。例如:y = sqrt(9); (3)作为其它函数的实参。例如:printf("y = %lf\n", sqrt(9));

5、函数声明

编辑 C 程序时,如果函数定义写在函数调用之后,则需要进行函数声明,否则可以省略函数声明。函数声明的一般形式为:

类型名 函数名(类型 1,类型 2,… ,类型 n); 说明:函数声明、函数定义、函数调用三者必须有严格的对应关系,三者的函数类型需一致,函数名

需相同,参数的个数、类型、顺序需一致。

6、函数的嵌套调用

C语言中不允许作嵌套的函数定义。因此各函数之

间是平行的,不存在上一级函数和下一级函数的问题。 但是C语言允许在一个函数的定义中出现对另一个函

数的调用。这样就出现了函数的嵌套调用。即在被调函

数中又调用其它函数。 其关系如图所示:在执行 main 函数的过程中调用

f1 函数,于是转去执行 f1 函数,在执行 f1 函数过程中又调用 f2 函数,于是转去执行 f2 函数,f2 函数执行完毕后返回 f1 函数的断点继续执行,f1 函数执行完毕后返回 main 函数的断点继续执行。

7、变量的作用域和存储类别(教材 12.1~12.3 节)

变量的作用域是指从空间上对变量的作用范围进行分类,分为全局变量和局部变量。其中全局变量的

作用范围宽,局部变量的作用范围窄。 变量的存储类别是指从时间上对变量的存在时间长短进行分类,分为动态变量、静态变量。其中动态

变量的存在时间短,静态变量的存在时间长。

(1)变量的作用域 变量的作用域是指变量的作用范围,分为全局变量和局部变量,局部变量又分为函数体的局部变量以

及复合语句的局部变量。

全局变量 函数体内的局部变量 复合语句内的局部变量 定义位置 定义在函数体外面 定义在函数体内部 定义在复合语句内部

作用域 从定义位置开始到整个.c 文件结束有效

本函数体内有效 本复合语句内有效

注意事项 (1)同一个.c 文件内的全局变量不能重名

(1)必须写在执行语句之前(2)同一函数体内的局部变

(1)必须写在执行语句之前(2)同一个复合语句内的局

重点

(2)全局变量允许与局部变量重名,重名时,局部变量

屏蔽全局变量

量不能重名 (3)当与全局变量重名时,局部变量屏蔽全局变量

部变量不能重名 (3)与前两种变量相比,这是作用范围最小的一种变量

说明 1:从此表格可以看出,作用范围最宽的是全局变量,其次为函数体内的局部变量,范围最窄的是复合语句内的局部变量。

说明 2:当全局变量、局部变量有重名时,范围较窄的变量会自动屏蔽范围较宽的变量。 说明 3:定义在函数体内的变量以及形参都属于局部变量。 (2)变量的存储类别 变量的存储类别分为 auto(动态型)、static(静态型)、register(寄存器型)、extern(外部型)。 动态变量—— 只在某一个时间段内存在。例如函数的形参、函数体内的局部动态变量,这类变

量在发生函数调用时,系统临时为它们分配存储空间,但是随着函数调用结束, 这些变量的存储空间被释放掉,变量的值也随之消失。 动态变量分为全局动态变量、局部动态变量。

静态变量—— 生存期为程序的整个执行过程,直到程序运行结束。这类变量一旦定义,系统就 为之分配存储空间,静态变量在整个程序运行过程中固定的占用这些存储空间, 因此也称永久存储。

静态变量分为全局静态变量、局部静态变量。 注意:静态变量定义后如果没有赋初值,则初值为零。这一点与动态变量不同, 动态变量定义后如果没有赋初值,则初值是随机数。

寄存器变量—— 可以将使用频率较高的变量定义为 register 型,以提高程序的运行速度。寄存 器变量属动态变量,存储空间到特定时候就自动释放。 注意:寄存器变量只限整型、字符型、指针型。

外部变量—— 如果在某个源文件(例如 a.c)中定义了一个全局动态变量 int x,在另外一个源

auto

static

register

extern

重点

重点

文件(例如 b.c)中需要引用这个全局变量 x,则在"b.c"中对变量 x 进行如下说 明"extern int a;"后,即可引用"a.c"中定义的变量 x。 注意:全局变量的定义只能有一次,但是使用 extern 对其进行说明可以有多次。 这一点与函数类似,函数定义也是只能有一次,而函数说明可以有多次。

8、函数的存储分类(教材 12.4 节)

(1)用 static 说明函数 一个函数定义后,除了被所在的源文件调用,不允许被其它的源文件调用,则在函数首部的返回值

类型前面加上 static 关键字即可达到以上目的。这样做的好处是避免不同的.c 文件定义了同名的函数而引起混乱。

(2)用 extern 说明函数 一个函数定义后,如果除了被所在的源文件调用,还能被其它源文件调用,则其它源文件在调用该函

数前,需先使用 extern 关键字进行说明,之后便可调用。

9、编译预处理(教材 13.1 节)

在 C 语言中,凡是以"#"开头的行都称为编译预处理命令行,要求掌握"#define"和"#include"。注意:每行的末尾不能加";"号。

(1) 宏替换 —— #define 不带参数的宏定义

#define 宏名 替换文本 使用说明:替换文本中可以包含已经定义过的宏名 书写说明:当宏定义分多行书写时,在行末加一个反斜线"\";宏名习惯用大写字母;宏定义一般写在程序的开头。 带参数的宏定义

#define 宏名(参数表) 替换文本 使用说明 1:参数表中只有参数名称,没有类型说明。 使用说明 2:如果替换文本中有括号,则进行宏替换时必须有括号;反之,如果替换

文件中本身没有括号,则宏替换时不能随便加括号。 书写说明:宏名和小括号必须紧挨着;小括号不能省略;

重点

(2)文件包含 —— #include 所谓文件包含是指在一个文件中去包含另一个文件的全部内容,#include 命令行的形式如下: #include "文件名" 或者 #include <文件名> 如果文件名用双引号括起来,是指系统先在源程序所在的目录查找指定的包含文件,如果找不到,再

按照系统指定的标准方式到有关目录中去找。 如果文件名用尖括号括起来,系统将直接按照系统指定的标准方式到有关目录中去寻找。

第五部分 "指针"知识点

1、指针的基本概念(教材 8.1 节) (1)计算机的内存空间是由许多存储单元构成的,每个存储单元代表一个字节的容量,每个存储单

元都有一个唯一的编号,即地址。程序运行过程中使用变量等就存放在这些存储单元中。对变量的取值有

两种方法,一种是使用变量名对其内容进行存取,称为"直接法",另一种是借助变量的地址对其内容进

行存取,称为"间接法"。 (2)指针──即地址。一个变量的地址称为该变量的指针,通过变量的指针能够找到该变量。 指针变量──专门用于存储其它变量地址的变量。指针与指针变量的区别,就是变量值与变量名的区

别。注意:指针变量存放的是地址值,而不是通常意义上的数值。

2、指针变量的定义、赋值(教材 8.2 节)

(1)指针变量的定义: 类型标识符 *指针变量名; 说明 1:此处的类型标识符称为指针变量的"基类型",即表示该指针变量应存放何种类型的变量地

址,指针变量的基类型必须与其指向的普通变量同类型,否则会引起程序运行错误。 说明 2:与普通变量的定义相比,除变量名前多了一个星号"*"外,其余一样。注意:此时的星号

仅仅是一个标识符,标识其后的变量是指针变量,而非普通变量。 说明 3:例如有定义"int *p;"表示定义了一个 int 类型的指针变量 p,此时该指针变量并未指向某个

具体的变量(称指针是悬空的)。使用悬空指针很容易破坏系统,导致系统瘫痪。 重点

重点及难点

说明 4:不论是什么类型的指针变量,在 VC++6.0 编译环境中已定义的指针变量都占用 4 个字节的存储空间,用来存放地址。这点与普通变量不一样,普通变量根据不同的数据类型,它所占用

的存储空间字节数是有差别的。 (2)指针变量的赋值 与普通变量相同,指针变量可以在定义时为其赋值,称为初始化;也可以先定义,再使用赋值语句为

其赋值,赋值方式为:指针变量名=某一地址; 通常有以下几种方法为指针变量赋值:

方法一:指针变量名 = &普通变量名 方法二:指针变量名 = 另外一个同类型并已赋值的指针变量 方法三:第三种是调用库函数 malloc 或者 calloc,当指针使用完毕后再调用 free 将其释放。例如: int *p; //以下两种写法均能实现为指针变量 p 动态分配 40 个字节存储空间的功能 p = (int *)malloc(10 * sizeof(int)); 等价于 p = (int *)calloc(10, sizeof(int));

3、指针运算(教材 8.4.2、8.4.3 节)

(1)指针运算中两个重要的运算符 * (取内容符): 取出其后内存单元中的内容。 &(取地址符): 取出其后变量的内存单元地址。 说明:此处的取内容符也是星号,外形上与指针变量定义时的标识符一样,但是二者的含义完

全不相同,前者是运算符,后者只是一个标识符。 (2)移动指针

重点

重点

移动指针就是对指针变量加上或减去一个整数,或通过赋值运算,使指针变量指向相邻的存储单元。

只有当指针指向一串连续的存储单元(例如数组、字符串)时,指针的移动才有意义。 指针移动通过算术运算(加、减)来实现,指针移动的字节数与指针的基础类型密不可分。例如已定

义:char *p1; int *p2;进行如下运算"p1++; p2++;"后,指针 p1 中存放的地址值自增一个单元,指针 p2 中存放的地址值自增 4 个单元。

(3)比较运算 比较运算是比两个指针变量中存放的地址值的大小关系。 (4)指针的混合运算 例如有定义:int a, *p; 则以下一些举例的混合运算需要仔细推敲其含义。

难点

①"&*p"的含意是什么?②"*&a"的含义是什么?③"(*p)++"的含义是什么?④"*p++"的含义是什么?⑤"*++p"的含义是什么?⑥ "++*p"的含义是什么?

4、函数之间地址值的传递(教材 8.5 节)

(1)实参向形参传送地址值 如果函数的形参为指针变量,对应的实参必须是基类型相同的地址值或者是已指向某个存储单元的指

针变量。 教材 7.5 节的内容是"函数之间数值的传递",这种方式下完成的是实参向形参的数值单向传递,即

当发生函数调用时,实参将其数值传递给形参,函数调用完毕后,形参的改变并不能影响对应实参的值,

因此把这种数值传递称为是"单向"的。 而本节的内容是"函数之间地址值的传递",其特点是实参为主调用函数中某内存单元的地址,在被

调用函数中可以通过形参对主调函数中该内存单元的值进行修改,这也就使得通过形参改变对应的实参值

有了可能,因此通过地址值的传递方式,主调函数与被调函数之间数据传递可以实现"双向"的传递。 "传地址"方式的体现的另外一个优越之处在于:可以将多个数据从被调函数返回到主调函数中。这

一点也是"传值"方式做不到的,传值方式中被调函数只能利用 return 语句向主调函数返回一个数据。 同学需仔细区分函数之间"传值"与"传地址"这两种方式各自的特点,做题时注意分析何时为传值

方式,何时为传地址方式。 (2)通过 return 语句返回地址值 当函数返回值的类型是指针类型,而非普通数据类型时,表明被调函数调用完毕后向主调函数返回的

是一个地址值,而不是一个普通的数值。此时应注意 return 语句的表达式值应是指针类型(地址值)。

重点

重点

5、一维数组和指针(教材 9.2 节)

(1)数组名是一个地址常量 (2)使用指针对数组元素进行访问是基于数组元素顺序存放的特性。

方式一:利用数组的首地址(数组名)访问数组元素。注意:由于数组名是常量,因此对数 组名不能使用自增运算,必须借助一个变量 i 来实现对数组元素的顺序访问。

例如: int a[10], i = 0; while(i < 10) scanf("%d", &a[i++]); 或者 while(i < 10) scanf("%d", a+ i++); 方式二:利用指针变量访问数组元素。 例如: int a[10], i = 0, *p = a; while(i < 10) scanf("%d", p++);

(3)引用一维数组元素的二种等价方法——下标法、指针法 假设有如下定义:int a[3], *p = a; 从上表可总结出,下标法取数组元素数值的表达式为"a[i]"或"p[i]",指针法取数组元素数值

的方法为"*(a+i)"或"*(p+i)"。下标法取数组元素地址的表达式为"&a[i]"或"&p[i]",指针法取数组元素地址的方法为"a+i"或"p+i"。

(4)假设有以下定义:int a[10], *p = a; 则 p 和 a 的相同点是:都是指针,存放数组的首地址。 不同点是:a 是地址常量,p 是指针变量。a 永远指向该数组的首地址,直到该数组

的存储空间被系统收回;p 是变量,可以重新赋值指向其它的存储空间。

6、一维数组与函数参数(教材 9.3 节)

(1)数组元素作为函数实参 由于数组元素相当于一个个独立的普通变量,当数组元素作为函数实参时,实现的是"传值"方式,即单向传递。在被调函数中只能使用数组元素的数值,不能改变数组元素的初值。 (2)数组元素的地址作为函数实参

当某数组元素的地址作为函数实参时,实现的是"传地址"方式,能够达到双向数据传递的功能。即在被调用函数中,不但可以利用形参使用该数组元素的初值,还可以达到修改该数组元素初值

的目的。 (3)数组名作为函数实参

当数组名作为函数实参时,由于数组名本身就是一个地址值,因此实现的是"传地址"方式,能够达到双向数据传递的功能,对应的形参必须是一个与数组类型一样的指针变量。在被调用函数中,

可以通过形参(指针变量)使用数组中的所有元素,还能够修改这些元素的初值。 说明 1:数组名作为函数实参时,对应的形参有如下几种写法,都代表一个与数组类型一致的指

针变量。 void fun(int a[10]) 或者 void fun(int a[ ]) 或者 void fun(int *a) { … } { … } { … }

说明 2:数组名作为实参时,对应的形参是一个与数组同类型的指针变量,发生函数调用时,系 统只是为该指针变量(形参)分配 4 个字节的存储空间,并不是分配等同于整个数组需要 占用的存储容量。 例如:

a[0] a[1] a[2] 下标法

p[0] p[1] p[2] *a *(a+1) *(a+2)

取数

组元

素的

数值 指针法

*p *(p+1) *(p+2)

&a[0] &a[1] &a[2]

下标法 &p[0] &p[1] &p[2]

a a+1 a+2

取数

组元

素的

地址指针法

p p+1 p+2

重点

重点

void main(void) void fun(int a[10]){ { int a[10]; … … printf("%d", sizeof(a)); printf("%d", sizeof(a)); …

fun(a); } …

注:fun 函数中的打印结果是"4",因为形参是一个指针变量,不论何种类型的指针变量,系统都为它分配 4 个字节的存储空间。

}

注:主函数中的打印结果是"40",因为 a 数组定义后,系统为它分配 40 个字节的存储空间。

7、二维数组和指针(教材 9.6 节) 难点

(1)二维数组"基类型"的理解 假设有定义:int a[3][4], *p;

与一维数组一样,二维数组名也是一个地址常量。 二维数组可以看作由多个一维数组组成,由以上定义可知,二维数组 a 由三个一维数组组成,每

一个一维数组中有四个元素,a[0]、a[1]、a[2]分别是这三个一维数组的数组名,它们各自代表了这三个一维数组的首地址,同样也是不可改变的常量地址。

基于以上分析,可以这样理解:①二维数组名 a 的基类型是 4 个 int 型;②一维数组名 a[0]、a[1]、a[2]的基类型是 1 个 int 型(即数组元素的类型)。 假设有定义:int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12};以下示意图表示了二维数组名、一维数组名、二维数组中各元素之间的对应关系。

以上示意图的右侧是二维数组的 12 个元素,每个元素占用一个 int 型的存储空间(4 个字节),

假设第一行第一个元素 a[0][0]的地址为 0x1000,分析可知第二行第一个元素 a[1][0]的地址为 0x1010,第三行第一个元素 a[2][0]的地址为 0x1020,这三行元素的首地址分别由 a[0]、a[1]、a[2]来存放。示意图的中部就是 a[0]、a[1]、a[2]构成的一个一维数组,这三个元素是一级指针,存放的是地址值(分别是 0x1000、0x1010、0x1020)。示意图的左侧是二维数组名 a,它是一个二级指针,存放由 a[0]、a[1]、a[2]三个元素构成的一维数组的首地址(假设是 0x1030)。

通过以上分析可知,"a[i]"是一级指针,基类型为 1 个 int 型。"a"是二级指针,基类型是 4 个int 型。例如:"a[0]"指向元素 a[0][0],则"a[0]+1"表示地址向后移动,指向元素 a[0][1],即一级指针加 1 表示地址向后移动 1 个 int 型。"a"指向元素 a[0],则"a+1"表示地址向后移动,指向元素a[1],即二级指针加 1 表示地址向后移动 4 个 int 型。

(2)二维数组每行元素的首地址 a(或者 a[0])代表二维数组中第一行元素的首地址;a+1(或者 a[1])代表第二行元素的首地址;

a+2(或者 a[2])代表第三行元素的首地址。

1030 a

1000

1010

1020

a[0]

a[1]

a[2]

该行首地址为 1000 1 2 3 4

5 6 7 8

9 10 11 12

a[0][0] a[0][1] a[0][2] a[0][3]

a[2][0] a[2][1] a[2][2] a[2][3]

该行首地址为 1010

该行首地址为 1020

该一维数组首地址为 1030

二维数组名 a (二级指针)

一维数组名 a[i](一级指针)

二维数组元素 a[i][j] (内容)

(3)二维数组每个元素的地址 二维数组中第 i 行第 j 列的某个元素 a[i][j]的地址可以由以下几种表达式求得: ①&a[i][j] ②a[i]+j ③*(a+i)+j ④&(*(a+i)[j]) ⑤a[0]+4*i+j ⑥&a[0][0]+4*i+j

(4)通过地址引用二维数组的元素 引用二维数组第 i 行第 j 列的元素的几种表达式如下所示: ①a[i][j] ②*(a[i]+j) ③*(*(a+i)+j) ④*(a+i)[j] ⑤*(a[0]+4*i+j) ⑥*(&a[0][0]+4*i+j)

(5)通过建立一个指针数组引用二维数组元素 假设有定义:int *p[3]; 则将 p 称为指针数组。 由于"[ ]"的优先级高于"*"的优先级,因此 p 首先与"[ ]"结合,构成 p[3],说明是一个数 组,"p[3]"再与"int *"结合,表示该数组中每个元素的数据类型是"整型指针"类型,于是我们将 "int *p[3]"称为指针数组——即它首先是一个数组,数组中的每个元素是指针类型。 下面我们来分析"指针数组"与"二维数组"的对应关系,假设有定义:int *p[3], a[3][2]; (注 意以上定义中,必须保证指针数组的元素个数与二维数组的行号常量一致,即 p[3]中的"3"与 a[3][2] 中的"3"要保持一致)。则以下写法表示将 p 数组中的每个元素(指针变量)指向 a 数组中的每一 行。(参看教材 P128 图 9.6) 第一种方法:p = a; 第二种方法:for(i = 0; i < 3; i++) p[i] = a[i]; 这时,可以通过指针数组 p 来引用二维数组 a 中的元素。

① p[i][j] 等价 a[i][j] ② *(p[i]+j) 等价 *(a[i]+j) ③ *(*(p+i)+j) 等价 *(*(a+i)+j) ④ *(p+i)[j] 等价 *(a+i)[j]

(6)通过建立一个行指针引用二维数组元素 假设有定义:int (*q)[2]; 则将 q 称为行指针。同学需仔细区分行指针与指针数组的区别。 由于定义时加了小括号,因此 q 首先与"*"结合,说明 q 是一个指针变量,然后再与"[3]"结 合,说明指针变量 q 的基类型是一个包含两个整型元素的数组。 下面我们来分析"行"与"二维数组"的对应关系,假设有定义:int (*q)[2], a[3][2]; (注意以 上定义中,必须保证行指针的元素个数与二维数组的列号常量一致,即(*q)[2]中的"2"与 a[3][2] 中的"2"要保持一致)。则指针变量 q 的基类型与 a 的基类型相同,q = a; 是合法的赋值语句,表示 指针 q 指向了二维数组 a 的首地址,这时可以通过行指针 q 来引用二维数组 a 中的元素。

① q[i][j] 等价 a[i][j] ② *(q[i]+j) 等价 *(a[i]+j) ③ *(*(q+i)+j) 等价 *(*(a+i)+j) ④ *(*(q+i)[j]) 等价 *(*(a+i)[j])

(7)二维数组、指针数组、行指针之间的对应关系 假设有定义:int a[3][2], *p1[3], (*p2)[2]; 则 a 是二维数组名、p1 是指针数组名,p2 是行指针名,由于二维数组的行数与指针数组的维数相同,二维数组的列数与行指针的维数相同,因此它们三

者可以产生对应关系。以下语句合法 p1 = a; p2 = a; 可以将 a、p1、p2 都视为二级指针。

难点 8、二维数组名和指针数组名作为函数实参(教材 9.7 节)

(1)二维数组名作为函数实参 首先回忆一维数组名作为函数实参的时候,对应的形参是与数组元素同类型的指针变量,形参有如下几种写法:

main() { int a[3]; … fun(a); //一维数组名作为函数实参 … }

则 fun 函数首部可以有如下几种写法:(1)void fun(int

p[3])

p[ ]) *p)

(2)void fun(int (3)void fun(int

当二维数组名作为函数实参时,对应的形参必须是一个行指针变量,形参的写法有以下几种形式:

main() 则 fun 函数首部可以有如下几种写法: { int a[2][3]; (1)void fun(int p[2][3])

(2)void fun(int p[ ][3])

… fun(a); //一维数组名作为函数实参

… (3)void fun(int (*p)[3]) } 注意以上写法,列下标不可缺省。无论是哪种方式,系统都把 p 处理成一个行指针。

(2)指针数组名作为函数实参 当指针数组作为函数实参时,对应的形参应当是一个指向指针的指针。形参的写法有以下几种形式:

main() 则 fun 函数首部可以有如下几种写法:{

(1)void fun(int *p[3]) (2)void fun(int *p[ ])

int a[2][3], *p[3] = a; … fun( p ); //指针数组名作为函数实参 … }

与一维数组名作实参时形参的写法相似(一维数组名作实参时对应的形参有三种写法),当指针数组

作为函数实参时,传送的仍然是一个一维数组名,对应的形参也有三种写法,只不过形参的类型是指针类

型而已。

9、字符串与指针(教材 10.2 节)

(3)void fun(int **p)

重点

(1)使指针指向一个字符串 由于字符串中的每一个字符在内存空间里是顺序存放的,因此使用指针操作字符串是比较便利的。以

下是几种将字符型指针变量指向字符串的正确方法: 方法一:在定义字符型指针变量时为其赋初值一个字符串(初始化)。例如: char *p = "Hello"; 方法二:先定义字符型指针变量,然后通过赋值语句让指针变量指向字符串。例如: char *p; p = "Hello"; 示例中的字符串常量"Hello"在程序中给出的是它在内存空间的首地址,因此可以通过赋值

语句将这段无名存储区的首地址赋值给指针变量,使得指针指向该字符串。 方法三:先定义字符型指针变量,然后将指针变量赋一个有效的地址值(可以将指针赋值为一个字符

数组的首地址,或者调用 malloc 函数为指针变量动态分配一段存储空间),最后调用 strcpy 函数将字符串复制到指针所指向的这段存储空间里。例如:

char *p; p = (char *)malloc(6 * sizeof(char));

strcpy(p, "Hello");

char a[6], *p; p = a; strcpy(p, "Hello");

或者

注意:在调用 strcpy 函数之前,指针 p 必须已经指向一个有效的存储空间,然后才能向这个

存储空间里存放字符串常量。如果指针只是定义,没有为其赋有效的地址值,这样的 指针是不能拿来用的。

(2)一些容易范错误的用法 错误一:使用赋值语句企图为字符数组赋一个字符串。例如: char a[6]; a = "Hello"; (错误原因是数组名是常量,不能指向另外的存储空间) 错误二:指针变量定义后就调用 strcpy 函数企图将一个字符串复制到指针所指的存储空间里。例如: char *p; strcpy(p, "Hello");

(错误原因是指针 p 中此时存放的是一个随机的地址值,即它还未指向一段有效的存储空 间,向一个随机的存储空间里赋值字符串常量是毫无意义的。)

(3)"字符数组存放字符串"与"指向字符串的指针"的比较 对于字符串的操作,既可以使用字符数组,还可以使用字符型指针变量,二者使用上有一些异同: 相同点:都可以利用初始化的方法为其赋一个字符串常量。例如: char a[6] = "Hello"; (正确) char *p = "Hello"; (正确) 不同点 1:字符数组不能使用赋值语句为其赋字符串常量;而字符型指针变量可以通过赋值语句使之

指向字符串常量;例如: char a[6]; a = "Hello"; (错误) char *p; p = "Hello"; (正确) 不同点 2:字符数组定义之后可以调用 strcpy 函数为其赋字符串常量;而字符型指针变量定义之后不

能立即调用 strcpy 函数为其赋字符串常量。例如: char a[6]; strcpy(a, "Hello"); (正确) char *p; strcpy(p, "Hello"); (错误) 不同点 3:字符数组装载字符串后,系统为数组开辟的是一段连续的存储空间(大于或等于字符串长

度),数组名代表了这段存储空间的首地址。字符型指针变量指向字符串后,系统为字符型 指针变量开辟的仅仅是 4 个字节,用来存放字符串无名存储区的首地址。例如:÷ char a[ ] = "Hello"; (系统为数组开辟了 6 个字节的存储空间用来存放字符串) char *p = "Hello"; (系统为指针变量 p 开辟了 4 个字节用来存放字符串常量的首地址) 因此 sizeof(a) 的运算结果是 6;而 sizef(p) 的运算结果是 4。

(4)字符串数组 难点

多个字符串放在一起就构成了字符串数组。可以使用一个二维数组(字符型的)来构造字符串数组,

也可以定义一个指针数组(字符型的)来构造一个类似的字符串数组。以下分别叙述: 方法一:使用二维数组来构造字符串数组。例如: char name[ ][10] = {"China", "America", "English", "France"}; 定义二维数组时,可以缺省第一维的长度,该例中,系统为二维数组 name 总共开辟了 40

个字节的存储空间,用来存放四个字符串,虽然有一些单元被浪费,示意图如下所示:

name name[0]

name[1]

name[2]

name[3]

C h i n a \0

A m e r i c a \0

E n g l i s h \0

F r a n c e \0

方法二:定义一个指针数组来构造字符串数组。例如: char *pname[4] = {"China", "America", "English", "France"};

pname pname[0]

pname[1]

pname[2]

pname[3]

C h i n a \0

A m e r i c a \0

E n g l i s h \0

F r a n c e \0

由以上示意图可以看出,指针数组 pname 中有四个元素,都是字符型的指针变量,每个指针指 向的存储空间不等长。因此用指针数组构造的字符串数组能够有效利用存储空间,根据不同的字符串 长度系统为之分配不同的存储容量,因此不会造成存储空间的浪费,这一点与二维数组构造的字符串 数组不一样。

第六部分 "函数的进一步讨论"知识点

1、main 函数的参数(教材 11.1 节) main 函数的参数通常有两个,函数首部可以写成以下形式: 第一个参数:类型必须是 int 型,参数名通常是 argc,也可以由用户自己来命名。该参数记录用户从命令行输入的字符串的个数。 第二个参数:类型必须是字符型的指针数组,参数名通常是 argv,也可以由用户自己来命名。该参数记录用户从命令行输入的各个字符串,由于多个字符串构成字符串数组,此时的形参为一个指针数组,数

组中的每一个指针指向各个字符串的首地址。 说明:从命令行输入的多个字符串中,第一个字符串必须是可执行文件的文件名。

参看教材"P158 例 11.1"对参数 argc 和 argv 的使用。

2、指向函数的指针(函数指针)(教材 11.2 节)

(1)指向函数的指针变量的定义、赋值

指向函数的指针也称"函数指针",由于 C 语言中函数名代表该函数的入口地址,因此可以定义一种指向函数的指针来存放该入口地址,将这种指针称为指向函数的指针。

void main(int argc, char **argv){ … }

难点

重点

double fun(int a, char *p){ … }

该 fun 函数定义为返回类型是 double 型,有两参数,第一个是 int 型,第二个是 char *型。

{ … } void main(int argc, char *argv[ ])

或者

void main(void){ double (*pfun)(int, char *); //定义指向函数的指针变量

char x=2, double y; pfun = fun; //将 fun 函数的入口地址赋值给指针变量 pfun …

y = (*pfun)(10, &x); //等价于 y = fun(10, &x); }

以上示意图中,在主函数内部首先定义了一个指向函数的指针变量 pfun,明确指出该指针所指向的函数返回值是 double 型,函数有两个参数,第一个参数是 int 型,第二个参数是 char *型。然后为指针变

量 pfun 赋值,通过语句"pfun = fun;"将 fun 函数的入口地址赋值给指针变量 pfun,于是对函数的调用即可通过该指针来完成。最后利用 pfun 实现对 fun 函数的调用,通过语句"y = (*pfun)(10, &x);"来完成,该语句等价于传统用法"y = fun(10, &x)"。

注意 1:定义指向函数的指针变量 pfun 时,"* pfun"的两侧必须加小括号,写成 (* pfun)。 注意 2:为指向函数的指针变量赋值时,赋值号的左侧只写指向函数的指针变量名,赋值号的右侧只

写函数名。 注意 3:利用指向函数的指针变量调用函数时,等价于使用函数名调用函数。

(2)指向函数的指针变量作为实参 函数名作实参时,对应的形参应该是函数指针。 函数指针也可以作函数实参,对应的形参应当是类型相同的指针变量。参看教材"P159 例 11.2"。

3、函数的递归调用(教材 11.3 节) 重点

一个函数如果自己调用自己,则称为直接递归调用;如果是两个函数相互调用对方,则称为间接递归

调用。 一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。在

递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身。例如有函数

fun 如下图所示:

int fun (int x) {

int y; z=fun(y);return z;

}

这个函数是一个递归函数。但是运行该函数将无休止地调用其自身,这当然是不正确

的。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的

办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。

第七部分 "结构体、共用体" 知识点 重点

1、结构体类型的说明

"结构体"是一种构造类型,是由数目固定,类型相同或不同的若干有序变量组成的集合。组成结构体的每个数据都称为结构体的"成员",或称"分量"。 结构体类型说明的形式如下: struct 结构体标识名

例如:以下定义了一个日期型的结构体类型 { struct data { int year; int month; int day; };

类型名 1 结构体成员名列表 1; 类型名 2 结构体成员名列表 2; … 类型名 n 结构体成员名列表 n;

} ; 说明 1:结构体类型的说明可以嵌套。 说明 2:struct 是关键字。"结构体标识名"可以省略。 说明 3:右侧花括号后面的分号 ; 不能省略。 说明 4:结构体类型的说明只是列出了该结构的组成情况,标志这种类型的结构模式已存在,编译程

序并没有因此而分配任何存储空间。就类似于列出"int",标志系统认可这种数据类型,但 "int"本身并不占用内存空间,只有定义了 int 型的变量后,系统才为变量分配内存空间。

2、用 typedef 定义类型

typedef 是一个关键字,利用它可以将已存在的数据类型命一个新的名称,可以理解为给已有的数据类型取一个别名。

例如:typedef int INT; INT x, y; //等价于 int x, y; 以上写法表示使用 typedef 给已有的数据类型"int"取了一个新名字"INT",于是"INT"等价于"int",

可以使用这个新类型名定义变量 x 和 y。 注意:typedef 的使用并不是定义了一种新的类型,而仅仅是将已有的数据类型取了一个新名称。 用户自己定义的结构体类型一般都比较复杂,使用 typedef 可以为结构体类型取一个较为简单的名称。 以下三种方式是使用 typedef 为结构体类型取一个别名的方法。别名为"DATE"。

方法一:先定义结构体类型,再使用 typedef 为之取一个别名。 struct date { int year; int month; int day; }; typedef struct data

方法二:定义结构体类型 方法三:定义结构体类型的同时使用 typedef 的同时使用 typedef为之 为之取一个别名,并且不省略 取一个别名,并且省略了结构体标识名。 typedef struct date { int year; int month; int day; }DATE; DATE;

结构体标识名。 typedef struct { int year; int month; int day; }

图 1 图 2 图 3

DATE;

3、定义结构体变量

以上提到结构体类型定义后,系统只是认可有这样一种用户自己构造的复杂数据类型,但并没有为之 分配存储空间,只有定义了该结构体类型的变量之后,系统才为变量分配相应的存储空间,结构体变量占

用的存储容量由结构体类型决定。以下几种是定义结构体变量的方法: 方法四:先定义结构体类

方法一:先定义结构体类型,再定义该结构体类型的变量。 struct date { int year; int month; int day; }; struct data

方法三:先使用 typedef 型,然后使用 typedef方法二:在定义结 为之构体类型的同时, 定义结构体类型的别名, 取一个别名,最后使用别

名定义结构体变量。 struct date { int year; int month; int day; }; typedef stuct date DATE;DATE x, y;

图 7

定义结构体变量。 再使用结构体类型的别struct date { int year; int month; int day; }

图 5

名定义变量。 typedef struct date { int year; int month; int day; }DATE; DATE

图 6

x, y;

x, y; x, y;

图 4 同学仔细比较"图 1"和"图 4",如果结构体类型名"struct date"前面有关键字 typedef,则 struct date

后面的是结构体类型的别名,反之如果没有关键字 typedef,则 struct date 后面的是结构体变量。 同学再仔细比较"图 2"和"图 5",同样道理,如果"struct date"前面有关键字 typedef,则右侧花

括号后面的是结构体类型的别名,反之如果没有关键字 typedef,则右侧花括号后面的是结构体变量。 以上图 4~图 7 三种方法都定义了两个结构体类型的变量 x 和 y,这两个变量各自占用 12 个字节的存

储容量,该存储容量的大小由结构体类型决定。

4、定义结构体类型的指针变量

结构体类型的指针变量定义方法与结构体类型普通变量的定义方法相同,均可使用图 4~图 7 所示的

三种方法,例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU x, *p = &x;

右图所示定义了一个 STU 结构体类型的普通变量 x,以及指针变量 p。由于该结构体类型各成员一共占用 20+30+1+4+8=63 字节的存储容量,因此系统为变量 x 分配 63 字节的存储空间,指针 p 的基类型为STU 结构体类型,即指针 p 所指向的一则段存储空间是 63 字节。

定义结构体指针变量 p的同时对它进行初始化,为之赋值为"&x",这一赋值过程很有必要,因为这使得指针变量 p 指向了一个有效的存储空间,没有指向有效存储空间的指针不能随便使用。

5、通过结构体变量或结构体指针引用成员

例如上图中定义的 STU 类型的结构体变量 x 或者结构体指针 p,它们有五个成员,如果要把某一个成员取出进行操作,不能直接使用,例如"age = 20;"这样的语句是错误的,原因是 age 现在不是一个独立的变量,它是变量 x 的一个成员,或者称之为一个属性,要取出 age 并将它赋值为 20,必须通过变量 x或者指针 p 才能将它取出。有以下三种方法,用到"."运算符或者"->"运算符。

(1)结构体变量名. 成员名 (2)结构体指针变量名->成员名

重点

(3)(*结构体指针变量名). 成员名 例如: strcpy(x.name, "LiWei"); 或者 strcpy(p->name, "LiWei"); 或者 strcpy((*p)->name, "LiWei"); x.age = 20; 或者 p->age = 20; 或者 (*p).age = 20;

6、给结构体变量赋值

方法一:初始化 定义结构体变量的同时为它的各个成员赋初值,称为初始化,例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU

右图所示在定义结构体变量 x 的同时为它的五个成员赋初值。所有初值必须要

用一对花括号括起来,各数值之间用逗号

隔开,数值的类型以及书写顺序与各成员

的类型和书写顺序保持一致。

x={"20070102001", "ZhangHua", 'M', 18, 80.0};

方法二:结构体变量的整体赋值。如果两个结构体变量类型相同,则可以对两个结构体变量进行整体

赋值。例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU x, y={"20070102001", "ZhangHua", 'M', 18, 80.0};x = y; //结构体变量的整体赋值

右图所示定义了两个结构体变量 x 和y。其中变量 y 使用初始化的方法已经为它的五个成员赋了初值,而变量 x 定义的时候各成员还没有初值。由于 x 和 y 是同类型的变量,因此可以通过赋值语句"x = y;"将变量 y 的值整体赋值给变量 x。这样做相当于将变量 y 各个成员的初值对应地赋值给变量 x 的各个成员。

方法三:结构体变量的各成员分开赋值。两个结构体变量对应成员之间可以相互赋值,例如: strcpy(x.num, y.num); strcpy(x.name, y.name); x.sex = y.sex; x.age = y.age; x.score = y.score; 注意:以上各成员分开赋值时,对于字符串类型,不能写成"x.num = y.num;"、"x.name = y.name;",

虽然此时赋值号的两侧类型相同,都是数组名(是地址),但由于数组名本身是地址常量,不能将其赋值

为另一个存储空间的首地址,因此对于字符数组类型的成员之间进行赋值,应选用 strcpy 库函数。其它基本数据类型的成员之间可以直接使用赋值语句进行赋值。

方法四:从键盘为各成员输入数值。例如: scanf("%s", x.num); //注意:成员"x.num"本身是数组名,代表地址,因此前面不加取地址符 scanf("%s", x.name); //成员"x.name"本身是数组名,代表地址,因此前面不加取地址符 scanf("%c", &x.sex); //成员"x.sex"、"x.age"、"x.score"是基本数据类型的变量,前面要加取地址符 scanf("%d", &x.age); scanf("%lf", &x.score);

7、结构体变量或成员做实参

"传值"方式——与基本数据类型一样,当结构体变量或者结构体变量的成员做实参时,实现的是"传

值"方式,只能单向传递数据。对应的形参必须与实参保持同类型。 "传地址"方式——当结构体变量的地址或者结构体变量成员的地址做实参时,实现的是"传地址"

方式。对应的形参必须是同类型的指针变量。 难点 8、利用结构体变量构成链表

当结构体类型定义时有一个自身结构体类型的指针变量作为成员,则可以利用该结构体类型的变量构

成链表。构成链表有静态方式和动态方式两种,动态方式是难点,也是考查的重点。 构成单向链表时,通常有一个头结点,若干个数据结点,以及一个末尾结点。一般来说,头结点的数

据域为空,头结点的指针域指向第一个数据结点,依次类推,每一个数据结点的指针域指向后一个数据结

点,最后一个数据结点称为末尾结点,末尾结点的指针域为空(NULL)。 有关单向链表的基本算法(参考教材 P198~P201)有:链表的建立、顺序访问链表中各结点的数据

域、在单向链表中插入结点、删除单向链表中的结点。对链表的各种操作必须考虑各个指针变量的用途。

9、共用体

共用体类型的说明以及共用体变量的定义方式与结构体相似。共用体与结构体不同的是,结构体变量

的各个成员各自占用自己的存储空间,而共用体变量的各个成员占用同一个存储空间。 说明 1:共用体变量的存储空间大小由占用字节数最多的那个成员决定。 说明 2:共用体变量初始化时只能对它的第一个成员进行初始化。 说明 3:由于共用体变量所有成员占用同一个存储空间,因此它们的首地址相同,并且与该变量的地

址相同。 共用体变量中每个成员的引用方式与结构体完全相同,可以使用如下三种方式: (1)共用体变量名.成员名 (2)共用体指针变量名->成员名 (3)(*共用体指针变量名).成员名

第八部分 "文件"知识点

1、基本概念

(1)记录在外部介质上的数据的集合称为"文件"。数据可以按文本形式或二进制形式存放在介质上,因此文件可以按数据的存放形式分为文本文件和二进制文件。二进制文件的输入输出速度较快一些。

(2)对文件的输入输出方式称为存取方式,在 C 语言中,有两种存取方式——顺序存取、直接存取。 顺序存取的特点是:每当打开这类文件进行读或写操作时,总是从文件的开头开始进行读或写。 直接存取的特点是:可以通过调用库函数指定读或写的起始位置,然后直接从此位置开始进行读或写。 (3)文件指针:是一个指向结构体类型名为 FILE 的指针。对文件的打开、关闭、读、写等操作都

必须借助于文件指针来完成。例如:FILE *fp; 即表示定义了一个 FILE 结构体类型的文件指针。 (4)文件位置指针:只是一个形象化的概念,用来表示当前读或写的数据在文件中的位置。读或写

操作总是从文件位置指针所指的位置开始。

2、文件操作类库函数

文件操作类库函数都定义在 stdio.h 头文件里。 (1) fopen 和 fclose 函数——打开、关闭文件

函数调用形式:文件指针 = fopen(文件名, 文件使用方式); fclose(文件指针); 说明 1:fopen 函数的参数文件名和文件使用方式都是字符串。该函数调用成功后即返回一个

FILE 类型的指针。常用的文件使用方式及其含义如下表所示: 文件使用方式 含义

"r"、"w" 为只读、只写而打开文本文件。总是从文件开头进行读写操作。 "r+"、"w+" 为读和写而打开文本文件。 "a" 为在文件后面添加内容而打开文本文件。文件中原有内容保持不变。

文本 文件

"a+" 在文件末尾添加内容后,可以从头开始读。

"rb"、"wb" 以只读、只写而打开二进制文件。总是从文件开头进行读写操作。 "rb+"、"wb+" 为读和写而打开二进制文件。 "ab" 为在文件后面添加内容而打开二进制文件。文件中原有内容保持不变。

二进制 文件

"ab+" 同"a+", 在文件末尾添加内容后,可以从指定位置读。 说明 2:当对文件的读、写操作完成之后,必须调用 fclose 函数关闭文件。 (2) fscanf 和 fprintf 函数——格式化输入输出。

函数调用形式:fscanf(文件指针, 格式控制字符串, 输入项列表); fprintf(文件指针, 格式控制字符串, 输出项列表); 功能:fscanf 函数是从文件读入格式化数据,fprintf 函数是将格式化数据写到文件中。 说明:这两个函数与 scanf、printf 函数的功能相似,表一比较这四个函数的区别。 函数名 功能及数据流向 函数名 功能及数据流向 scanf 键盘 内存 printf 内存 显示屏 fscanf 文件 内存

输入 格式化数据 fprintf 内存 文件

输出 格式化数据

表一

(3) fgetc 和 fputc 函数——也可写成 getc、putc。功能是输入、输出一个字符。 函数调用形式:ch = fgetc(文件指针); //ch 是一个字符型变量 fputc(ch, 文件指针); 功能:fgetc(或 getc)函数是从文件读入一个字符,fputc(或 putc)函数是将一个字符输出

到文件。

说明:这两个函数与 getchar、putchar 函数的功能相似,表二比较这四个函数的区别。 函数名 功能及数据流向 函数名 功能及数据流向 getchar 键盘 内存 putchar 内存 显示屏

fgetc 文件 内存 输入

一个字符 fputc 内存 文件 输出

一个字符 表二

(4) fgets 和 fputs 函数——输入、输出一个字符串。 函数调用形式:fgets(str, n, 文件指针); //str 是字符串的起始地址,n 表示读入字符串的长度 fputs(str, 文件指针); 功能:fgets 函数是从文件读入字符串,fputs 函数是将字符串输出到文件。 说明 1:fgets 函数最多只能从文件中读 n-1 个字符,读入结束后,系统将自动添加'\0'。 说明 2:这两个函数与 gets、puts 函数的功能相似,表三比较这四个函数的区别。 函数名 功能及数据流向 函数名 功能及数据流向

gets 键盘 内存 puts 内存 显示屏 fgets 文件 内存

输入 字符串 fputs 内存 文件

输出 字符串

表三

(5) fread 和 fwrite 函数——读、写二进制文件。 函数调用形式:fread(buffer, size, count, 文件指针); fwrite(buffer, size, count, 文件指针); 参数说明:以上函数中的参数 buffer 是数据块的指针,输入或者准备输出的数据存放在此内

存块中;size 表示每个数据块的字节数;count 用来指定每次读、写的数据块个数。 说明:fread 和 fwrite 这两个函数只能针对二进制文件进行读写,不能操作文本文件。

(6) feof 函数——用来判断二进制文件是否结束,如果是则返回 1,否则返回 0。 函数调用形式:foef(文件指针); 说明:文本文件是以 EOF(相当于-1)作为文件的结束标志。二进制文件没有明显的结束

标志,判断二进制文件是否结束必须调用 feof 函数。 (7) fseek 函数——用来移动文件位置指针到指定的位置上,接着的读或写操作就从此位置开始。

函数调用形式:fseek(文件指针, offset, origin); 参数说明:以上函数中的参数 offset 是以字节为单位的位移量,为长整型;origin 是起始点,

用以指定位移量是以哪个位置为基准,起始点既可以用标识符(表四)来表示, 也可以用数字来表示。

位置指针起始点的标识符 代表的起始点 数字 SEEK_SET 文件开始 0 SEEK_END 文件末尾 2 SEEK_CUR 文件当前位置 1

表四

说明 1:对于文本文件来说,位移量 offset 必须是 0。例如:fseek(pf, 0L, SEEK_SET); 表示 将文件位置指针移到文件开头;fseek(pf, 0L, SEEK_END); 表示将文件位置指针移 到文件末尾;

说明 2:对于二进制文件来说,如果位移量是正整数,表示位置指针从指定的起始点处向后移 动;如果位移量是负整数,表示位置指针从指定的起始点处向前移动。

(8) ftell 函数——用来获得当前文件位置指针的位置,该函数返回值是一个长整型的数,表示当前位置指针相对于文件开头的字节数。 函数调用形式:t = ftell(文件指针); //t 是一个长整型的变量

(9) rewind 函数——又称"反绕"函数,功能是使文件的位置指针回到文件开头处。 函数调用形式:rewind(文件指针);

常用库函数

1、标准输入输出函数(头文件 stdio.h) 函数名 函数原型 功能

scanf scanf(格式控制, 地址项列表) 从键盘输入格式化数据 printf scanf(格式控制, 输出项列表) 将格式化数据输出到显示屏 getchar char getchar(void) 读取键盘输入的一个字符 putchar putchar(char ch) 将一个字符输出到显示屏 gets gets(char *s) 读取键盘输入的一个字符串,可以包含空格 puts puts(char *s) 将一个字符串输出到显示屏

2、数学函数(头文件 math.h) 函数名 函数原型 功能

sqrt double sqrt(double x) 计算并返回参数 x 的平方根值 pow double pow(double x, double y) 计算并返回参数 x 的 y 次方的值 fabs double fabs(double x) 计算并返回参数 x 的绝对值 log double log(double x) 计算并返回参数 x 的对数值,即求 ln(x)的值

3、字符串处理函数(头文件 string.h) 函数名 函数原型 功能

strlen int strlen(char *str) 计算 str 所指字符串的长度,不包括'\0' strcpy strcpy(char *dest, char *sour) 将 sour 所指字符串复制到 dest 所指的存储空间里 strcat strcat(char *dest, char *sour) 将 sour 所指字符串粘贴到 dest 所指字符串的末尾

strcmp int strcmp(char *str1, char *str2) 比较 str1 和 str2 所指的两个字符串,并返回比较的结果。如果前者>后者,返回 1;如果前者<后者,返回-1;如果前者==后者,返回 0。

4、动态存储分配函数(头文件 stdlib.h) 函数名 函数原型 功能

malloc void *malloc
版权声明
本文为[杨恒昌]所创,转载请带上原文链接,感谢
https://www.seoxiehui.cn/article-296161-1.html
相似文章

2021-08-09