第1章 C语言概述
1.1 重点内容提要
1.1.1 C程序的组成
1.C程序组成
C程序是由函数构成的,一个C源程序至少有一个函数,即main函数,也可以由一个main函数和若干个其他函数构成。
2.C程序中函数之间的关系
构成C程序的函数有两大类:一类是主函数,另一类是子函数。在主函数和子函数之间,主函数可以调用子函数,而子函数不能调用主函数;
在子函数之间可以彼此调用,没有层次之分。
1.1.2 函数的组成
1. 函数的首部
函数首部包括函数名、函数类型、函数属性、函数参数(形参)名、参数类型。
2.函数体
函数体,即函数首部下面的大括号{……}内的部分。它由两部分组成:
(1)声明部分:在声明部分中定义函数所用到的变量,以及对该函数所需要调用的函数进行声明。
(2)执行部分:执行部分由若干语句组成。C程序允许无执行部分,即是一个空函数,表明它什么也不做。
1.1.3 几点说明
(1)一个C程序,无论main函数在程序中的什么位置,程序的执行都将从main函数开始,在main函数中结束。
(2)程序书写格式自由,一行内可写几个语句,一条语句也可以分写在多行上。
(3)每个语句和数据定义的最后必须有一个分号。分号是C语言的必要组成部分。
(4)C语言本身没有输入输出语句,输入输出操作是由库函数scanf和printf等来完成的。
(5)可以用/*……*/对C程序中的任何部分进行注释,在执行程序时,系统不会执行注释部分。
(6)也可以用//对C程序中某一行进行注释,“//”所在行后的全部内容不会被系统执行。
1.2 考点
(1)C程序组成
(2)正确识别C语言的标识符。
第2章 程序的灵魂—算法
2.1 重点内容提要
2.1.1.算法的概念
1.算法
算法即是一套操作方案,是为解决一个问题而采取的方法和步骤。
2.算法分类
算法可分为数值运算算法和非数值运算算法两大类。
数值运算算法:目的是求数值解。
非数值运算算法:包括面十分广泛,主要用于事物管理领域。
2.1.2 算法的特性
1.有穷性
有穷性是指一个算法应包含有限的操作步骤,而不能是无限的。
2.确定性
确定性是指算法中的每一个步骤都应当是确定的。
3.有零个或多个输入
一个算法可以没有输入,也可以有多个输入,所谓输入是从外界取得必要的信息。
4.有一个或多个输出
输出即一个算法所得的结果。
5.有效性
有效性是指算法中的每一个步骤都应当有效地执行,并得到确定的结果。
2.1.3. 算法的表示方法
1.自然语言表示算法用语言表示各种操作。
2.用流程图表示算法
用流程图表示算法:用一些图框表示各种操作。这种方法直观形象,易于理解。
3.三种基本结构
(1)顺序结构;
(2)选择结构;
(3)循环结构:a)当型循环结构;b)直到性循环结构。
4.用N—S流程图表示算法
5.用伪代码表示算法
6.用计算机语言表示算法
2.1.4 结构化程序设计方法
1.自顶向下、逐步细化的方法
2.模块化程序设计方法
3.结构化编码
2.2 考点
(1)了解结构化程序的三种基本结构,并在程序设计过程中正确应用三种基本结构。
(2)了解算法的表示方法。
第3章 数据类型、运算符和表达式
3.1 重点内容提要
3.1.1 C的数据类型
1.基本类型
(1)整型
(2)字符型
(3)实型
(4)枚举类型
2. 构造类型
(1)数组类型
(2)结构体类型
(3)共同体类型
3.指针类型
4.空类型
3.1.2 常量与变量
1.常量
常量:在程序运行过程中其值不变的量。
(1) 整型常量——三种表示形式:
a)十进制整数,例:12;
b)八进制整数,例:012;
c)十六进制整数,例:0x12。
(2) 字符型常量——包括两类:
a)用单引号括起来的单个字符,例: ‘a’ , ‘2’;
b)转义字符常量,例; ‘\n’ m’\r’ ,’\376’。
(3) 实型常量——两种表示形式:
a)十进制小数形式,例:123.456;b)指数形式,例:1e3,2.3e-3。
(4) 字符串常量——用一对双引号括起来的字符序列。例: “abc”,“123”,“A” 。
(5) 符号常量——用一个标识符代表一个常量。其定义格式为:
#define 标识符 字符串
例: #define PI 3.1415926
2. 变量
(1) 整型变量——分类:
有符号基本类型(int、内存中占2个字节)
无符号基本类型(unsigned int、内存中占2个字节)
有符号短整型(short int、内存中占2个字节)
无符号短整型(unsigned short、内存中占2个字节)
有符号长整型(long int、内存中占4个字节)
无符号长整型(unsigned long、内存中占4个字节)
(2) 实型变量——分类:
单精度实型(float、内存中占4个字节)
双精度实型(double、内存中占8个字节)
长双精度实型(long double、内存中占10个字节)
(3) 字符变量——char
3.1.3 变量赋初值
变量赋初值即在定义变量的同时对变量预先设置初值,即变量的初始化。
例: int a=3,b=3;
char c= 'a ’;
3.1.4 各类数值数据间的混合运算
整型、实型和字符型数据间可以进行混合运算,在运算时,不同类型的数据要先转换成同一类型,然后进行运算。
转换规则按下图所示箭头方向进行。
(高)double ← float
↑
long
↑
unsigned
↑
(底)int ← char, short
3.1.5 算术运算符和算术表达式
1. C语言运算符
(1) 算术运算符:+、-、*、/、%
(2) 关系运算符:>、<、==、>=、<=、!=
(3) 逻辑运算符:!、&&、||
(4) 位运算符:>>、<<、~、|、^、&
(5) 赋值运算符:=及其扩展赋值运算符
(6) 条件运算符:?:
(7) 逗号运算符: ,
(8) 指针运算符:*、&
(9) 求字节数运算符:sizeof
(10) 强制类型转换运算符:(类型)
(11) 分量运算符: . 、->
(12) 下标运算符: [ ]
(13) 其他: 如函数调用运算符( )
2.算术运算符和算术表达式
(1) 基本算术运算符:+、-、*、/、%
1) 算术运算符的优先级为先乘除后加减。
2) 算术运算符的结合方向:自左向右。
3) 利用强制类型转换运算符可以将一个表达式转换成所需的类型,通常是从精度高的类型向精度低的类型转换,其优先级高于算术运算符。
一般格式: (类型名) 表达式
(2) 自增、自减运算符:++ (自增)、-- (自减)
1) 一般格式:
++i, --i (在使用i之前先使i的值加(减)1)
i++,i-- (在使用i之后使i的值加(减)1)
2) 自增、自减运算符的优先级高于算术运算符,与强制类型转换运算符同级。
3) 自增、自减运算符的结合方向为自右向左。
4) 自增、自减运算符只能用于变量,而不能用于常量或表达式。
(3) 算术运算符:用算术运算符和括号将运算对象连接起来的、符合C语法规则的式子。
3.1.6 赋值运算符和赋值表达式
1. 赋值运算符:=
(1) 优先级:低于算术运算符
(2) 结合方向:自右向左。
2.复合的赋值运算符:+=、-=、*=、/=、%=等
(1) 优先级:与赋值运算符“=”同级。
(2) 结合方向:自右向左。
3.赋值表达式
一般格式:<变量><赋值运算符><表达式>
4.赋值运算时的类型转换
如果赋值运算符两侧的类型不一致,在赋值时要进行类型转换,其规则如下:
左 右 转换说明
float int 将整型数据转换成实型数据后再赋值;
int float 将实型数据的小数部分截去后再赋值;
ling int int,short int 值不变;
int,short int ling int 右侧的值不能超过左侧数据值的范围,否则将导致意外的结果;
unsigned signed 按原样赋值,但如果数据范围超过相应的整型范围,将导致意外的结果;
signed unsigned 按原样赋值,但如果数据范围超过相应的整型范围,将导致意外的结果。
3.1.7 逗号运算符和逗号表达式
1.逗号运算符: ,
(1) 优先级:是C语言运算符中优先级最低的运算符。
(2) 结合方向:自左向右。
2.逗号表达式:用逗号运算符将两个表达式连接起来的式子。
一般格式: 表达式1,表达式2,…,表达式n
运算结果:是整个逗号表达式最右边的表达式“表达式n”的值。
3.2 考点
(1) C语言中各种类型数据所占内存空间的规定。
(2) C语言中有关整型常量表示方法的规则。
(3) C语言中,逻辑“真”与逻辑“假”的表示方法。
(4) 字符常量可作为整型常量来处理。
(5) 自增、自减运算符的结合方向及其使用。
(6) 逗号运算符及逗号表达式的求值顺序和结果。
(7) 混合类型表达式的计算。
第4章 最简单的C程序设计——顺序程序设计
4.1 重点内容提要
4.1.1 C语言的语句
1. 控制语句:完成一定控制功能。
(1) if( ) —— else —— 条件语句
(2) for(;;;) —— 循环语句
(3) while( ) —— 循环语句
(4) do —— while( ) 循环语句
(5) continue 结束本次循环语句
(6) break 终止执行switch或循环语句
(7) switch 多分支选择语句
(8) goto 转向语句
(9) return 从函数返回语句
2.函数调用语句:由一次函数调用加一个分号构成的一条语句。
3.表达式语句:由一个表达式构成的语句。例:a=3
4.空语句:只有一个分号的语句,表示什么都不做。
5.复合语句:用一对花括号“{}”把一些语句括起来所构成的语句。
4.1.2 赋值语句:由赋值表达式加上一个分号构成。
一般格式: 变量=表达式
4.1.3 数据的输入输出
1.字符输出函数putchar
一般格式: putchar(c),其中:c可以是字符变量,也可以是整型变量。
功能:向终端输出一个字符。
2.字符输入函数getchar
一般格式:getchar( )
功能:从终端(或系统隐含指定的输入设备)输入一个字符。
3.格式输出函数printf
一般格式:printf(格式控制,输出表列)
格式控制:
(1)格式说明:由%和格式字符组成。其作用是将输出的数据转换为指定格式输出
(2)普通字符:原样输出的字符
输出表列:需要输出的一些数据。
功能:将输出表列中的参数按给定的格式输出。
常用的格式字符有:
(1)d格式符。用来输出十进制整数。
1)%d 按整型数据的实际长度输出。
2)%md m为指定输出字段的宽度。M为正整数,左补空格。
3)%ld 输出长整型数据。
(2)o格式符。以八进制整数形式输出数据。
(3)x格式符。以十六进制整数形式输出数据。
(4)u格式符。以十进制整数形式输出无符号数据。
(5)c格式符。用以输出一个字符。
(6)s格式符。用以输出一个字符串。
1)%s 输出一个字符串。
2)%ms 输出字符串占m列,左补空格。
3)%-ms 输出字符串占m列,右补空格。
4)%m.ns将字符串左端n个字符以占m列输出,左补空格
5)%-m.ns将字符串左端n个字符以占m列输出,右补空格
(7)f格式符。用来输出实数。
1)%f 按系统默认格式输出,整数部分全部输出,小数保留6位。
2)%m.nf 指定输出的数据共占m列,小数占n列,左补空格
3)%-m.nf 指定输出的数据共占m列,小数占n列,右补空格
4.格式输入函数scanf
一般格式:scanf(格式控制, 地址表列)
格式控制:
(1)格式说明:由%和格式字符组成
(2)普通字符:原样输出的字符
地址表列:由若干个地址组成的表列,可以是变量的地址,或字符串的首地址。
功能:按指定格式形式输入数据。
第5章 逻辑运算和判断选取控制
5.1 重点内容提要
5.1.1 关系运算符和关系表达式
1.C语言提供的关系运算符
(1)关系运算符
优先级相同(高):
1) < (小于)
2) <= (小于等于)
3) > (大于)
4) >= (大于等于)
优先级相同(低):
5) == (等于)
6) != (不等于)
(2)关系运算符的优先级
(高) 算术运算符 > 关系运算符 > 赋值运算符(低)
(3)关系运算符的结合方向:自左向右。
2.关系表达式
(1)关系表达式:用关系运算符将两个表达式连接起来的式子。
(2)关系表达式的运算结果是一个逻辑值,即“真”(1)或“假”(0)。
5.1.2 逻辑运算符和逻辑表达式
1.C语言提供的逻辑运算符
(1)逻辑运算符:
1)!(逻辑非)
2)&&(逻辑与)
3)||(逻辑或)
(2)逻辑运算符的优先级:
! ↑
算术运算符 ↑ (高)
关系运算符 ↑
&&、|| ↑
赋值运算符 ↑ (低)
(3)逻辑运算符的结合方向:自左向右。
2.逻辑表达式
(1)逻辑表达式:用逻辑运算符将两个表达式连接起来的式子。
(2)逻辑表达式的运算结果是一个逻辑值,即“真”(1)或“假”(0)。
5.1.3 if语句
1.If语句的三种形式
(1)单分支:
.一般格式: if(表达式) 语句
.功能:先计算表达式的值,若值为非0,执行内嵌语句,若值为0,则执行if语句下面的第一条语句。
(2)双分支:
.一般格式: if(表达式) 语句1
else 语句2
.功能:先计算表达式的值,若值为非0,执行内嵌语句1,若值为0,则执行内嵌语句2。
(3)多分支:
.一般格式: if(表达式1) 语句1
else if (表达式2) 语句2
else if (表达式3) 语句3
┇
else if (表达式m) 语句m
else 语句n
2.if语句的嵌套
if(表达式1)
if (表达式2) 语句1
else 语句2
else
if (表达式3) 语句3
else 语句4
5.1.4 条件运算符
1.条件运算符
(1)条件运算符: ? :
(2)条件运算符的优先级:仅优于赋值运算符。
(3)条件运算符的结合方式:自右向左。
2.条件表达式
.一般格式:表达式1?表达式2:表达式3
.执行顺序:先求解表达式1,若值为非0,求解表达式2,并将该值作为表达式的值;若值为0,则计算表达式3的值,并将该值作为表达式的值。
5.1.5 switch语句
.一般格式:
switch (表达式)
{
case 常量表达式1:语句1
case常量表达式2: 语句2
.
.
.
case常量表达式n: 语句n
default: 语句n+1
}
.执行顺序:先求解表达式,当表达式的值与某个case后面的常量表达式的值相等时,就执行此case后面的语句,
之后,流程控制转移到下一个case继续执行;若所有的case中的常量表达式的值都没有与表达式的值匹配的,就执行default后面的语句。
第6章 循环控制
6.1 重点内容提要
6.1.1 C语言中可实现循环的四种语句
(1)while语句,属于当型循环控制语句。
(2)do – while语句,属于直到型循环控制语句。
(3)for语句,属于当型循环控制语句。
(4)go to语句和if语句构成的循环语句,根据不同的结合方式既可构成当型循环,也可构成直到型循环。
6.1.2 C语言种四种循环语句的一般格式及执行步骤
1.while语句:
.一般格式:while(表达式) 语句
.执行步骤:
(1)求出表达式的值,若值为非0,执行步骤(2);若值为0,执行步骤(4)。
(2)执行内嵌语句。
(3)转向执行步骤(1)。
(4)结束while循环,执行while语句下面的语句。
2.do – while语句:
.一般格式:
do 语句
while(表达式)
.执行步骤:
(1)执行内嵌语句。
(2)求出表达式的值,若值为非0,执行步骤(1);若值为0,执行步骤(3)。
(3)结束do – while循环,执行do – while语句下面的语句。
3.for语句
.一般格式: for(表达式1;表达式2;表达式3) 语句
.执行步骤:
(1)计算表达式1。
(2)计算表达式2,若值为非0,执行步骤(3);若值为0,执行步骤(6)。
(3)执行内嵌语句。
(4)计算表达式3。
(5)转向执行步骤(2)。
(6)结束for循环,执行for语句下面的语句。
4.goto语句
.一般格式: goto 语句标号
6.1.3 循环体内使用的break语句和continue语句
1.break语句
.一般格式:break;
.功能:
(1)在switch语句中用来使流程跳出switch结构,执行switch后面的语句。
(2)在循环体内,迫使所在循环立即终止,既跳出所在循环体,继续执行循环体后面的语句。
2.continue语句
.一般格式:continue
.功能:结束本次循环,即跳过循环体中尚未执行的语句。在while和do—while循环中,continue语句将使控制直接转向条件判断部分。
在for循环中,遇到continue语句后,先计算for语句中表达式3的值,然后再执行条件判断(表达式2)。
6.1.4 循环的嵌套
一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。内嵌的循环中还可以嵌套循环,这就构成多层循环。
C语言中的四种循环语句可以互相嵌套。
第7章 数组
7.1 重点内容提要
7.1.1 一维数组的定义和引用
1.一维数组的定义一般格式: 类型说明符 数组名[常量表达式]
2.一维数组元素的引用格式:数组名[下标]
3.一维数组的初始化
(1)在定义数组时对数组元素赋予初值。例如:
int a[10]={0,1,2,3,4,5,6,7,8,9};
(2)可以只给一部分元素赋值。例如:
int a[10]={0,1,2,3,4};
(3)在对全部数组元素赋初值时,可以不指定数组长度。例如
int a[5]={1,2,3,4,5};
可以写成:int a[ ]={1,2,3,4,5};
7.1.2 二维数组的定义和引用
1.二维数组的定义一般格式: 类型说明符 数组名[常量表达式][常量表达式]
2.二维数组元素的引用格式:数组名[下标][下标]
3.二维数组的初始化
(1)分行给二维数组赋初值。例如:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
(2)可以将所有数据写在一个花括号内,按数组排列的顺序对各元素赋初值。例如:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}
(3)可以对部分元素赋初值。
例1: int a[3][4]={{1},{5},{9}};
赋初值后数组各元素为: 1 0 0 0
5 0 0 0
9 0 0 0
例2: int a[3][4]={{1},{0,6},{0,0,11}};
赋初值后数组各元素为: 1 0 0 0
0 6 0 0
0 0 11 0
例3: int a[3][4]={{1},{5,6}};
赋初值后数组各元素为: 1 0 0 0
5 6 0 0
0 0 0 0
例4: int a[3][4]={{1},{},{9}};
赋初值后数组各元素为: 1 0 0 0
0 0 0 0
9 0 0 0
(4)如果对全部元素赋初值,在定义数组时,对第一维的长度可以不指定。例如:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
可以写成:int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12};
7.1.3 字符数组
1.字符数组的定义格式: char 数组名[常量表达式]
2.字符串常量
字符串常量是用双引号括起来的一串字符,实际上也是被隐含处理成一个无名的字符型一维数组。
C语言中约定用’\0’作为字符串的结束标志,它占内存空间,但不计入串的长度。
3.字符数组的初始化
(1)将字符逐个赋给数组中各元素。
例:char c[10]={‘c’,‘ ’,‘p’,‘r’, ‘o’,‘g’,‘r’,‘a’,‘m’};
(2)直接用字符串常量给数组赋初值。
例:char c[10]= “c program”;
(3)通过赋初值隐含确定数组长度。
例:char c[]= “c program”;
4.字符数组的输入输出
(1)逐个字符输入输出:
例:char c[10];
int i=0;
for(i=0;i<10;i++) scanf(“%c”,&c[i]);
for(i=0;i<10;i++) printf(“%c”,c[i]);
(2)将整个字符串一次输入或输出:
例:char c[10];
scanf(“%s”,c);
printf(“%s”,c);
7.1.4 字符串处理函数
1.puts(字符数组名)
功能:将一个字符串输出到终端。
2.gets(字符数组名)
功能:从键盘上输入一个字符串赋给字符数组。
3.strcat(字符数组1,字符数组2)
功能:将字符串2连在字符串1后面,其结果放在字符串1中。
4.strcpy(字符数组1,字符数组2)
功能:将字符串2赋值到字符数组1中。
5.strcmp(字符数组1,字符数组2)
功能:将字符串1和字符串2进行比较,比较结果为:
字符串1=字符串2,函数返回值为0
字符串1>字符串2,函数返回值为正数
字符串1<字符串2,函数返回值为负数
6.strlen(字符数组)
功能:测试字符串长度函数,返回值为一整数。
7.1.5 难点
(1)C语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值,所以下面的定义是错误的。
int n;
scanf(“%d”,&n);
int a[n];
(2)数组元素的下标。
1)C语言中数组元素下标的下限是固定的,总是为0。
2)C语言程序在执行过程中并不自动检验数组元素的下标是否越界。
(3)数组在内存中的存储形式:
一维数组:数组元素以下标从小到大的顺序依次存放于内存中。
二维数组:逻辑上可以看成一个矩阵结构,第一个下标代表行,第二个下标代表列。
根据C语言规则,数组元素在内存中的排列是按照行优先原则:即先存放第1行,再存放第2行,依次类推。
(4)字符串结束标志。
在字符数组中的有效字符后面加上’\0’,这时字符数组可作为字符串变量,字符’\0’可以通过赋初值或输入字符串时,由系统自动添加。
但在许多操作过程中要求人为添加,因此,在C语言中,字符数组可以用作字符串变量,但并不就是字符串变量。
(5)在C语言中,只要给数组部分赋初值,系统将会对数值数组的未赋初值部分自动补初值0;而对字符数组的未赋初值部分自动补初值’\0’,
但如果在定义语句中没有进行初始化,系统将不会给数组元素赋初值。
第8章 函数
8.1 重点内容提要
8.1.1 C语言中函数的特点及分类
1.C程序的构成
一个C源程序文件由一个或多个函数组成。一个源程序文件是一个独立的编译单位。
2.C语言中函数的特点
(1)一个C程序由一个或多个源程序文件组成,在C程序中必须至少有一个、也只能有一个主函数,即main函数,其余函数均为子函数。
(2)C程序的执行总是从main函数开始,在main函数中结束。
(3)所有函数(除主函数)都是平行的,即在定义函数时是相互独立的故不能嵌套定义。
(4)每个函数都将完成一个特定的功能。
(5)main函数可以调用子函数,而子函数不能调用主函数。
8.1.2 函数定义的一般格式
类型标识符 函数名(形式参数表列)
{声明部分
语句
}
8.1.3 函数返回值:通过函数中的return语句获得。
8.1.4 函数的调用:函数名(实参表列)
函数调用方式:
(1)把函数调用作为一个语句。例: printf( );
(2)函数调用出现在一个表达式中,函数返回一个确定的值参加表达式的运算。例: m=2*max(a,b);
(3)函数调用作为一个函数的实参。例: m=2*max(a,max(b,c));
8.1.5 函数的嵌套调用:是指在调用一个函数的过程中,又调用了另一个函数。
8.1.6 函数的递归调用:是指在调用一个函数的过程中,又出现直接或间接地调用该函数本身。
8.1.7 数组作为函数参数
1.数组元素作函数参数:值传递方式。
2.数组名作为函数参数:地址传递方式。
8.1.8 局部变量和全局变量
1.局部变量:是指在一个函数内部定义的变量,它只在本函数返回内有效,在此函数之外不能使用该变量。
2.全局变量:是指在函数之外定义的变量,它可以为本文件中其他函数所共用,它的有效范围为从定义变量的位置开始到本源文件的结束。
8.1.9 变量的存储类型
1.存储方法分为静态存储类和动态存储类,具体包括:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)
2.以静态存储方式存储的数据包括全局变量和静态局部变量。
以动态存储方法存储的数据包括函数的形参、自动变量、函数调用时的现场保护和返回地址等。
3.在函数中定义的变量,如不特别声明为static存储类别的都属于auto变量。
第9章 预处理命令
9.1 重点内容提要
9.1.1 预处理的概念
对程序进行编译之前所做的处理为预处理。
预处理命令不是C语言语句,为区别,以“#”开头。
C提供的预处理功能有三种:(1)宏定义;()文件包括;(3)条件编译
9.1.2 宏定义
1.不带参数的宏定义
作用:用一个指定的标识符来代表一个字符串。
一般形式:#define 标识符 字符串
宏定义只作字符替换,不分配内存空间。
2.带参数的宏定义
作用:既要进行字符串替换,还要进行参数替换。
一般形式: #define 宏名(参数表) 字符串
宏展开:程序中如有带参数的宏,则按#define命令行中指定的字符串从左到右进行替换。
如果字符串中包含宏中的形参,则用相应的实参替换形参,如果字符串中的字符不是参数字符,则保留。
3.带参数的宏定义和函数的区别:
1) 函数调用时,先求出实参数表达式的值,然后带入形参,而使用带参数的宏只是进行简单的字符替换;
2) 函数调用是在程序运行时处理的;而宏展开则在编译时进行。
3) 函数中的实参和形参都要定义类型,且类型要求一致;而宏定义不存在类型问题,宏名及参数均无类型,只是一个符号代表;
4) 调用函数可得到一个返回值,而用宏可设法得到几个结果;
5) 宏展开后源程序增长,而函数调用不使程序增长;
9.1.3 “文件包含”处理
(1)“文件包含”处理:指一个源文件可以将另外的文件包含到本文件之中。
(2)一般格式: #include <文件名>
或 #include “文件名”
9.1.4 条件编译几种形式:
1.#ifdef 标识符 /*若标识符已用#define命令定义过*/
程序段1
#else
程序段2
#endif
2.#ifndef 标识符 /*若标识符已用#define命令定义过*/
程序段1
#else
程序段2
#endif
3.#if 表达式
程序段1
#else
程序段2
#endif
第10章 指针
10.1 重点内容提要
10.1.1 指针或指针变量的概念
1.指针的概念
程序经过编译以后,将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。
由于通过地址能找到所需的变量单元,因此一个变量的地址就称为该变量的指针。
2.指针变量的概念
如果把一个变量的地址存放在另一个变量中,此变量称为指针变量。指针变量的值是指针(地址)。
10.1.2 变量的指针和指向变量的指针变量
1.指针变量的定义
(1)定义的一般形式:基类型 *指针变量名
指针变量前面的“*”表示该变量的类型为指针型变量。
例如:
int *pointer1;
float *pointer2;
(2)指针变量所指向的类型:指针变量的“基类型”,指定该指针变量可以指向的变量类型,一个指针变量只能指向同一个类型的变量。
2.指针变量的引用
(1)引用指针变量用到的饿两个运算符:
1)取地址运算符& 例如:&a为变量s的地址;
2)指针运算符* (或称“间接访问”运算符):例如:*p为指针变量p所指向的变量。
(2)应用指针变量的步骤:
1)定义指针变量;
2)定义指针变量要指向的变量;
3)建立两者的指向关系。
例如:
float a;
float *pointer;
……
pointer=&a;
(3)“*”所处的语句不同含义也不同:说明语句中,*pointer表示pointer是指针变量;执行语句中,*pointer表示pointer所指向的变量。
3.指针变量作为函数参数
(1)用指针变量作为函数参数的作用:在函数调用时,将实参指针变量的值传送给形参指针变量。
在被调用函数中,通过形参指针变量,改变其所指的变量,这个改变了的变量值能被调用函数所用。
(2)什么情况下用指针变量作函数参数?如果希望函数调用结束后,一些变量值的变化能被保留下来,就可以考虑用指针变量作为函数参数。
以实现“通过调用函数改变变量的值,在主调函数中使用这些改变了的值”的目的。
(3)如果想通过函数调用得到n个要改变的值,可以:
1)在主调函数中设n个变量,用n个指针变量指向他们;
2)将指针变量作实参,将这n个变量的地址传给所调用的函数的形参;
3)形参也定义成指针变量,通过形参指针变量,改变该n个变量的值;
4)在主调函数中就可以使用这些改变了值的变量。
(4)注意:
1)由于“值传递”方式为单向传递,只能由实参传递到形参,所以,不能通过改变形参指针变量的值而改变实参指针变量的值。
2)虽然调用函数不可能改变实参指针变量的值,但可以改变实参指针变量所指变量的值。
10.1.3 数组的指针和指向数组的指针变量
1.数组的指针和指向数组的指针变量的概念
(1)数组的指针:数组占据内存的连续存储单元,通过数组的起始地址可以找到数组的每个元素,因此数组的指针是指数组的起始地址。
数组元素的指针是指数组元素的地址,相当于变量的指针。
(2)指向数组的指针变量:把数组的指针存入一变量中,该变量就是指向数组的指针变量。
(3)数组名是指向数组的常量指针:C语言规定,数组名代表数组的首地址,因此数组名是一个指向数组的常量指针,
而不是一个指向数组的指针变量,两者不可混合。
2.指向数组元素的指针变量的定义及指向赋值
已知数组a,包含10个整型数据,定义一个指针变量指向该数组。
有以下几种定义格式:
(1)int a[10;
int *p;
……
p=&a[0];
(2)int a[10];
int *p;
……
p=a;
(3) int a[10];
int *p=&a[0];
(4)int a[10];
int *p=a;
3.通过指针引用数组元素
(1)p+i的含义:如果指针变量p已指向数组中的一个元素,则p+i指向同已数组中的向下第i个元素(而不是将p值简单地加i)。
p+i所代表的地址实际上是p+i×d,d是一个数组元素所占的字节数。
(2)如果p的初值为&a[0],则:
1)p+i和a+i就是a[i]的地址,或者说,他们指向a数组的第i个元素。
2)*(p+i)或*(a+i)是p+i或a+i所指向的数组元素。
(3)引用一个数组元素可以用:
1)下标法:例如a[i]。
2)指针法:*(a+i)通过数组名计算数组地址,找出元素的值。
*(p+i)用指针变量指向数组元素。
(4)指针变量的运算:
如果先使p=&a[i],则:
p++ p指向下一个元素
*p++ 先取*p值,后使p加1
*(++p) 先使p加1,再取*p
*(p--) 先取*p值,后使p减1
*(--p) 先使p减1,再取*p
(*p)++ p所指向的元素值加1
4.数组名作函数参数
(1)数组名可以用作函数的形参和实参。用数组名作实参,在调用函数时是把数组的首地址传送给形参,实参数组和形参数组的首地址相同,
实参数组与形参数组共占同一段内存。如果在函数的调用过程中,使形参数组中各元素的值发生变化,
也就是使实参数组元素的值发生变化。这种值的变化并非是从形参传回实参的,而是由于形参数组与实参数组共享一段内存而造成的。
(2)如果有一实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下4中情况:
实参 形参
数组名 数组名
数组名 指针变量
指针变量 指针变量
指针变量 数组名
5.指向多维数组的指针和指针变量
设有一个二维数组a,它的定义为:
int a[4][5];
a是一个数组名。可以这样理解:a数组包含4行:a[0],a[1],a[2],a[3],而每一行又是一个一维数组,它包含5个元素,
例如,a[0]所代表的一维数组又包含5个元素:a[0][0],a[0][1],a[0][2],a[0][3],a[0][4]。
1)行地址:&a[i]和a+i等价,代表第i行的首地址。A是二维数组名代表整个二维数组的首地址,也就是第0行的首地址。
2)第i行第j元素:*(a[i]+j)=*( (a+i)+j)=a[i][j]
10.1.4 字符串的指针和指向字符串的指针变量
1.字符串的表示形式
(1)用字符数组实现,如
char string[]=”I love China!”;
(2)用字符指针实现,如
char *string= “I love China!”;
2.字符数组和字符指针变量的区别
(1)字符数组:由若干个元素组成,每个元素中放一个字符。
字符指针变量:存放的是字符串的首地址,而不是将字符串放到字符指针变量中。
(2)赋值方式。字符数组只能对各个元素赋值,不能用以下方式赋值。
char str[14];
str=“I love China!”;
字符指针变量赋值可用如下方式赋值:
char *a;
a=“I love China!”;
(3)字符数组名虽代表地址,但其值是常量,不能改变;指针变量是变量,其值可以改变。
10.1.5 函数的指针和指向函数的指针变量
1. 用函数指针变量调用函数
(1) 函数的指针:一个函数在编译时被分配给一个入口地址,这个入口地址称为函数的指针。
可以用一个指针变量指向函数,然后通过该指针变量调用此函数。
(2) 指向函数的指针变量的一般定义形式:数据类型(*指针变量名)( );
这里的“数据类型”是指函数返回值的类型。
(3) 函数指针变量的使用方法:
1) 说明一个指向函数的指针变量,例: int(*p)();
2) 将函数的入口地址符给指针变量p:p=max; 函数名代表函数的入口地址。
3) 调用函数:(*p)(a , b);max(a , b)
注意:p只能指向入口地址处,而不能指向函数中间的某条指令处,故不可用*(p+1)来表示函数的下一条指令。
(4) 说明:
1) 函数的调用可通过函数调用,也可通过函数指针调用。
2) (*p)( )只表示定义了一个指向函数的指针变量,并不固定指向哪一个函数,必须赋一确定的函数的入口地址才可使用。
3) 在给函数指针变量赋值时,只须给出函数名而不必给出参数,如:p=max;因为只将入口地址赋给p。
4) 用函数指针变量调用函数时,只需将(*p)代替函数名即可,后面根据需要带入实参。
5) 对指向函数的指针变量,像p+n,p++,p—等运算是无意义的。
2.把指向函数的指针变量作函数参数
指向函数的指针变量作函数参数通常用在需调用的函数是不固定的情况下。
使用方法:
1) 实参用函数名;
2) 形参用指向函数的指针变量;
3) 调用时实参给形参传递函数地址,这样在函数中就可以调用实参函数了。
注意:作为实参的函数名,在其所在函数中的说明部分应作函数说明。
10.1.6 返回指针值的函数
返回指针值的函数定义的一般形式:类型标识符 *函数名(参数表);
如: int *a(int x,int y);
a的两侧分别是*和( )运算符,而( )优先级高于*,a先与( )结合,是函数形式;函数前有*表示是指针型函数,函数值是指针。
10.1.7 指针数组和指向指针的指针
1. 指针数组的概念
指针数组:一个数组中,其元素均为指针类型。
一维指针数组的定义形式:类型名 *数组名[数组长度];
例如: int *p[4];
说明:
(1)[]比*优先级高,表明是数组形式,p数组有4个元素,每个元素都是一指针变量,可指向一个振兴变量。
(2)* p[4]和(*p)[4]不同,后者是指向一维数组的指针变量。
应用:
1) 用来指向若干个字符串,使字符串处理更加方便灵活。
2) 作为main函数的形参。
2. 指向指针的指针
指向指针的指针:执行指针数据的指针变量。
定义形式:类型名 **指针变量名;
例如: char **p;
*运算符的结合性为从右到左,故 **p相当于*(*p)
3. 指针数组作main函数的形参
(1) main函数也可以有参数,例如:main(argc,argv)
(2) main函数是由系统调用的,实参是和命令一起给出的。即在一个命令行中包括命令名和需要传给main函数的参数。
命令的一般形式:命令名 参数1 参数2 … 参数n
例如:file1 China Beijing
目标文件名为file1,把两字符串“China”,”Beijing”作为传送给main函数的参数。
(3) 参数1 … 参数n与main函数中形参的关系:
argc: 指命令行中参数的个数(文件名也作为一个参数)。
argv: 一个指向字符串的指针数组。
带参数的main函数原形应为:main(int argc ,char *argv[]);
其中:命令行参数应当都是字符串,这些字符串的首地址构成一个指针数组。
10.1.8 有关指针的数据类型和指针运算的小结
1. 有关指针的数据类型的小结
为便于比较,下面把其他一些类型的定义也列出。
定义 含义
int i; 定义整型变量;
int *p; P为指向整型数据的指针变量;
int a[n]; 定义整型数组a,它有n个元素;
int *p[n]; 定义指针数组p,它由n个指针整型数据的指针元素组成;
int(*P)[n]; P为指向含n个元素的一维数组的指针变量;
int f(); P为带回整型函数值的函数;
int *p(); P为带回一个指针的函数,该指针指向整型数据;
int (*p)(); P为执行函数的指针,该函数返回一个整型值;
int **p; p是一个指针变量,它指向一个指向整型数据的指针变量.
2. 指针运算的小结
(1) 指针变量加减一个整数:
p+i代表地址计算:p+d*i
其中,d是指针变量所指向的变量所占用的内存单元字节数之和。
(2) 指针变量赋值(p为指针变量,i为整型变量):
合理的赋值,如:
p=&a; (将变量a的地址赋给p)
p=array; (将数组array首地址赋给p)
p=&array[i]; (将数组array第i个元素的地址赋给p)
p=max; (max为一已定义的函数,将max的入口地址赋给p)
p1=p2; (p1和p2都是指针变量,将p2的值赋给p1)
不允许的赋值,如:
p=1000; (只能将变量已分配的地址赋给指针变量)
i=p; (不允许将指针变量的值赋给整型变量)
(3) 指针变量可以有空值,即该指针变量不指任何变量。
如: p=NULL;
(4) 两个指针变量可以相减,前提是若两指针变量指向同一数组的元素,则两个指针变量值之差是两指针之间的元素个数。
(5) 两个指针变量比较,前提是两个指针指向同一个数组元素,方可比较。
3. void指针类型
(1) void指针类型:可定义一个指针变量,但不指定它是指向哪一种类型数据的。
(2) 指针定义为viod类型:ANSI C标准规定用动态存储分配函数时返回void指针,用以指向一个抽象类型的数据,再将它赋值给另一指针变量时,要进行强制类型转换,使之适合于被赋值的变量类型。
例如:
char *p1;
void *p2;
……
p1=(char )p2;/强制类型转换*/
(3)函数定义为void类型:函数返回的是一地址,它指向void类型。如需要引用此地址,要根据具体情况对其进行类型转换。
10.2 考点
(1) 指针与指针变量的概念,指针与地址运算符。
(2) 变量、数组、字符串、函数、结构体的指针以及指向变量、数组、字符串、函数、结构体的指针变量。通过以上各种类型指针引用相同类型的数据。
(3) 用变量、数组、字符串、函数、结构体的指针作函数参数。
(4) 返回指针值的指针函数。
(5) 指向指针的指针的定义及使用,指针数组。
(6) main函数的命令行参数。
第11章 结构体
11.1重点内容提要
11.1.1 声明一个结构体类型的一般形式
struct 结构体名{ 成员表列};
11.2.3 定义结构体类型变量的方法
1. 先声明结构体类型再定义变量名
2. 在声明类型的同时定义变量
3. 直接定义结构体类型变量而不出现结构体名
11.1.3 结构体变量的引用规则:
(1) 引用结构体变量中成员的方式为:结构体变量名.成员名
(2) 成员可以像普通变量一样进行各种运算。
(3) 可以引用结构体变量成员的地址和结构体变量的地址。
11.1.4 结构体变量的初始化
结构体变量可以在定义时指定初值,其一般形式:在定义数组之后加={初值表列};
第12 章 位运算
12.1.1 C语言中实现位运算的6种运算符
(1)“按位与“运算符(&);
(2)“按位或“运算符(|);
(3)“按位异或“运算符(^);
(4)“取反“运算符(~);
(5)右移运算符(>>)
(6)左移运算符(<<)。
[来源:个人QQ空间]
以上内容,来源自网络