C语言程序设计主讲人:汪洋第一章 C语言概述
C语言的发展与特点
C语言的基本程序结构
C语言程序的开发过程
C语言的基本词法
算法
1.1 C语言出现的历史背景
汇编语言依赖于计算机硬件,程序的可读性和可移植性差;
一般高级语言难以实现汇编语言的某些功能如对内存地址的操作、位操作等。
1.2 C语言的发展史
1960年 ALGOL 60;
1963年 英国剑桥大学提出 CPL语言;
1967年 Matin Richards提出 BCPL语言;
1970年 Ken Thompson提出 B语言;
1972-1973 Dennis.M.Ritchie提出 C语言;
Brian W.Kernighan 和 D.M.Ritchie介绍标准 C;
1987年美国国家标准化协会提出 ANSI C。
1.3 C语言的特点
简洁、紧凑,使用方便、灵活;
允许直接访问地址,能进行位操作;
运算符丰富;
数据类型丰富;
结构化程序语言,便于实现程序的模块化;
程序执行效率高,可移植性好。
1.4 C语言的基本程序结构
C程序是由函数构成的,每个 C程序有且只有一个主函数( main),可包含若干其他函数;
每个函数由首部与函数体组成;
首部包括函数类型、函数名、函数参数(形参)、参数类型,
int max(int x,int y)
函数体包括声明部分和执行部分。
main函数位置任意,但总是从 main函数开始执行,在 main函数中结束;
C程序书写自由,每个语句后需加一个分号;
主函数可调用任何非主函数,非主函数之间可互相调用,但不能调用主函数;
C语言本身没有输入输出语句;
用 /*…………*/ 进行注释。
1.5 C语言程序的开发过程
编辑
编译
链接计算机只能识别和执行由 0和 1组成的二进制的指令,为了使计算机能执行高级语言源程序,必须先用
“编译程序”把源程序翻译成二进制形式的“目标程序”,然后将该目标程序与系统的函数库和其他目标程序连接成为可执行的目标程序。
1.6 C语言的基本词法
字符集:包括大小写英文字母 52个、数字
10个、键盘符号 33个、转义字符。
标识符:是用户自定义的一组字符序列,
用来表示程序中需要辨认的对象名称,如符号常量、变量、数组、函数。
规定:
标识符是由字母或下划线开头的字母、数字、下划线组成的一串符号,最长不能超过 32个字符;
大小写字母有区别,大写字母只用来定义宏名,其他都采用小写字母表示。
保留字,32个,有特殊含义,主要用于构成语句,进行存储类型和数据类型的定义,不允许用户作为自定义标识符使用;
词类:常量、变量、运算符、函数、表达示、
保留字;
语句:完成特定的操作,语句的有机组合序列完成指定的功能;
语句的种类
赋值语句;
函数调用语句;
表达式语句;
流程控制语句;
复合语句;
空语句;
1.7 算法著名计算机科学家沃思提出公式:
程序 =数据结构 +算法
数据结构:对数据的描述即指定数据的类型和数据的组织形式;
算法:对操作的描述即操作步骤。
1.7.1 简单算法举例判定 2000-2500年中的每一年是否闰年。
设定 y为被检测的年份。算法如下:
S1,2000=>y
S2:若 y不能被 4整除,则输出 y“不是闰年”,然后转至 S6
S3:若 y能被 4整除,不能被 100整除,则输出 y“是闰年”,然后转至 S6
S4:若 y能被 100整除,又能被 400整除,输出 y“是闰年”;否则输出 y“不是闰年”,然后转至 S6
S5:输出 y“不是闰年”
S6:y+1=>y
S7:当 y<=2500时,转 S2继续执行,如 y>2500,算法停止;
1.7.2 算法的特点
有穷性;
确定性;
有零个或多个输入;
有一个或多个输出;
有效性
1.7.3 算法的表示
用流程图表示算法;
用伪代码表示算法;
用计算机语言表示算法。
第二章 C语言的数据类型、运算符与表达式
C语言的数据类型;
C语言的运算符与表达式;
2.1 C语言的数据类型数据类型基本类型构造类型指针类型空类型 (void)
整型 (int)
字符型 (char)
实型(浮点型)
数组类型结构体类型 (struct)
共用体类型(联合类型) (union)
枚举类型单精度型 (float)
双精类型 (double)
2.2 常量在程序运行过程中,其值不能被改变的量称为常量。
C语言中规定的常量类型有以下五种:
整型常量、实型常量、字符常量、字符串常量和符号常量。
2.2.1 整型常量
1,整型常量的表示方法:
十进制整数:
无前缀,数码取值为 0~9,如 123,-456。
八进制整数:
前缀为 0,数码取值为 0~7,如 0123,-011 。
八进制数与十进制数的转换方法如下:
(0123)8 =1* 82+2*81+3*80=64+16+3=(83)10
十六进制整数:
前缀 0X或 0x,数码取值为 0~9,A~F或 a~f,
如 0x2A,-0x12。
十六进制数与十进制数转换方法:
(-0x12)16=-(1*161+2*160)=-(16+2)=(-18)10
2.整型常量的后缀:
加后缀 L或 l,表示长整型数。
加后缀 u,表示无符号数。
2.2.2 实型常量
实型常量即实数又称为浮点数,C语言中实数只采用十进制,有两种表示形式:
小数形式:由数码 0~9和小数点组成 (注意必须有小数点),如,123,-123.4567;
指数形式:由十进制数,加阶码标志,e”
或,E”以及阶码(只能为整数),如
-2.1e2,2.1e-2。
2.2.3 字符常量
C语言中,字符常量是用单引号括起来的单个字符,如‘ a?,‘D’,‘ $?等。
转义字符是一种特殊形式的字符常量,
它是以一个,\”开头的字符序列。
表 2.1转义字符及其含义字符形式 含义
\n 换行,将当前位置移到下一行开头
\t 水平制表(跳到下一个 tab位置)
\b 退格,将当前位置移到前一列
\r 回车,将当前位置移到本行开头
\f 换页,将当前位置移到下页开头
\\ 反斜杠字符,\”
\? 单引号字符
\” 双引号字符
\ddd 1到 3位 8进制数所代表的 ASCⅡ 字符
\xhh 1到 2位 16进制数所代表的 ASC Ⅱ 字符例 2.1转义字符的使用
main()
{printf(“?ab?c\t?de\rf\tg\n”);
printf(“h\ti\b\bj?k”);
}
例 2.1结果程序运行后在打印机上得到以下结果:
fab?cgde
hjik
注意在显示屏上最后看到结果以与上述打印结果不同,是:
fgde
hj?k
2.2.4 字符串常量
C语言中,字符串变量是由一对双引号括起来的字符序列,如,China”,“$3.232”。
注意:不要将字符常量与字符串常量混淆。
字符常量与字符串常量的区别
字符常量是由单引号括起来的,字符串常量是由双引号括起来的;
字符常量只能是单个字符,字符串常量则可是零个或多个字符;
可把一个字符常量赋予一个字符变量,但不能把一个字符串变量赋予一个字符变量,C语言中没有相应的字符串变量,可用字符数组来存放字符串常量;
字符常量占一个字节的内存,字符串常量占的内存字节数等于字符串中字节数加 1,最后一个字节存放字符‘ \0?作为字符串结束标志。
2.2.5 符号常量
C语言中,可用一个标识符来表示一个常量,称为符号常量又称为宏定义,
使用前须先定义,其定义规则为:
#define 标识符 常量例 2.2 符号常量的使用
#define PRICE 30
main()
{
int num,total;
num=10;
total=num*PRICE;
printf(“total=%d”,total);
}
使用符号常量的好处:
含义清楚;
在需要改变一个常量时能做到“一改全改”;
2.3 变量变量是指在程序运行中其值是变化的量。
一个变量应该有一个变量名,在内存中占据一定的存储单元,在该存储单元中存放变量的值。
3 变量值
a
变量名存储单元图 2.1
C语言中,要求对变量作强制定义,
即“先定义,后使用”。
便于发现错误;
为每一个变量指定确定类型,在编译时就能为其分配相应的存储单元。
整型数据在内存中的存储方式整型数据在内存中是以二进制形式存放的。若定义了一个整型变量 i:
int i=10;
图 3.2(a)是数据存放的示意图,图 3.2(b)
是数据在内存中实际存放的情况;
i
10
(a)
i 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
(b)
图 2.2
实际上,整型数值是以补码表示的。
一个正数的补码与其原码相同,求负数的补码方法:将该数的绝对值的二进制形式按位取反再加 1。例如求 -10的补码:
0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0
10的原码取反再加 1得 -10的补码
2,3.1 整型变量
有符号基本整型 [signed] int
有符号短整型 [signed] short [int]
有符号长整型 [signed] long [int]
无符号基本型 unsigned int
无符号短整型 unsigned short [int]
无符号长整形 unsigned long [int]
1,整型变量的分类:
类型说明符 数的取值范围 字节数
[signed] int -32768~32767 即 -215~(215-1) 2
unsigned int 0~65535 即 0~(216-1) 2
[signed] short [ int] -32768~32767 即 -215~(215-1) 2
unsigned short [int] 0~65535 即 0~(216-1) 2
[signed] long [int] -2147483648~2147483647 即
-231~(231-1)
4
unsigned long [int] 0~4294967295 即 0~(232-1) 4
表 2.1整型数据的所占的内存字节数与取值范围
2.整型变量的说明类型说明符 变量名标识符,变量名标识符,…...;
如,int a,b,c;
unsigned short x,y;
例 2.3 整型变量的定义和运算见教材 P34例 2.3
2.3.2 实型变量
单精度型 float
占 4个字节内存,提供 7位有效数字,
双精度型 double
占 8个字节内存,提供 16位有效数字。
整数没有误差,实数有精度,有误差,提供 6位小数,7位有效数字。
2.实型变量的说明格式和书写规则同整型变量说明相同,
如,float s,t;
double h,k;
例 2.4实型数据的舍入误差
main()
{float a,b;
a=123456.789e5;
b=a+20;
printf(“%f,%f”,a,b);
} 结果:
12345678848.000000,12345678848.000000
误差原因分析
b的理论值应是 12345678920,而一个实型变量只能保证的有效数字是 7位有效数字,后面的数字是无意义的,并不准确表示该数,从结果看出,把 20加在后几位上,是无意义的,应当避免将一个很大的数与一个很小的数直接相加减,否则就会“丢失”小的数。与此类似,用程序计算 1.0/3*3的结果并不等于 1。
2.3.3 字符变量字符变量用来存放字符常量,只能存放一个字符,占用 1个字节内存。
字符变量定义如下:
char c1,c2;
1,字符数据在内存中的存储将一个字符常量放到一个字符变量中,
不是把该字符本身放到内存单元中,而是将该字符的相应的 ASC Ⅱ 代码存放在存储单元中,如字符‘ a’ 的 ASC Ⅱ 代码为
97,‘ b’ 为 98,
97 98
c1 c2
0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 0
c1 c1
图 2.3
在内存中,字符数据以 ASCⅡ 码存储,
它的存储形式与整数存储形式类似,C语言允许对整型变量赋以字符值,也允许对字符变量赋以整型量。在输出时,允许把字符变量按整型量输出,也允许把整型变量按字符型量输出。
注意:当整形变量按字符型量处理时,
只有低八位参与处理。
例 2.5 向字符型变量赋以整型值
main()
{char c1,c2;
c1=97;
c2=98;
printf(“%c,%c\n”,c1,c2);
printf(“%d,%d\n”,c1,c2);
}
结果:
a,b
97,98
2,补充
Turbo C将字符变量中的最高位作为符号位,
也就是将字符处理成带符号的整数,即 signed
char型。它的取值范围是 -128~127。如果使用
ASCⅡ 码为 0~127间的字符,由于字节中最高位为 0,因此用 %d输出时,输出一个正整数。
如果使用 ASCⅡ 码为 128~255间的字符,由于在字节中最高位为 1,用 %d格式符输出时,就会得到一个负整数。例如:
main()
{char c=130;printf(“%d”,c);}
得到 -126。如果不想按有符号处理,可以将变量定义为 unsigned char类型,这时其取值范围是 0~255。 signed char和 unsigned char 相仿,
但它只有一个字节。
例 2.6
main()
{char c1=130;
unsigned char c2=130;
printf(“c1=%d,c2=%d\n”,c1,c2);
}
结果,c1=-126,c2=130
2.3.4 变量赋初值程序中常需要对一些变量预先设置初值。
C语言允许在定义变量的同时使变量初始化,

int a=3;
float f=3.56;
char c=?a?;
也可以使被定义的变量的一部分赋初值,如:
int a,b,c=5;
如果对几个变量赋予初值 3,应写成
int a=3,b=3,c=3;
不能写成,int a=b=c=3;
int a=3;
相当于:
int a;
a=3;
2.4 运算符和表达式
运算符是一些特定的符号,它用来对数据进行某些特定的操作;
运算对象(操作数)是用来进行运算的数据,
包括常量、变量等;
表达式是用运算符将运算对象连接起来的式子。
如 1+2,1和 2为运算对象,而 1+2就是表达式。
2.4.1 运算符种类、优先级和结合性
⑴ 算术运算符用于各类数值计算。运算符有,加 (+)、减 (-)、
乘 (*)、除 (/)、求余 (或称模运运算,%)、自增
(++)、自减 (--)。
⑵ 关系运算符用于比较运算。运算符主要有,大于 (>)、小于 (<)、等于 (==)、大于等于 (>=)、小于等于
(<=)和不等于 (!=)。
1,运算符的种类
⑶ 逻辑运算符用于逻辑运算。运算符有,与 (&&)、或 (||)、
非 (!)。
⑷ 位操作运算符参与运算的量,按二进制位进行运算。运算符有,按位与 (&)、按位或 (|)、取反 (~)、
按位异或 (^)、左移 (<<)、右移 (>>)。
⑸ 赋值运算符用于赋值运算。赋值运算符有,简单赋值
(=)、复合算术赋值 (+=,-=,*=,/=,%=)、复合位运算赋值 (&=,|=,^=,<<=,>>=)等三类。
⑹ 条件运算符是一个三目运算符,用于条件求值。运算符有,(?:)。
⑺逗号运算符用于把若干表达式组合成一个表达式。
运算符有,(,)。
⑻指针运算符用于取内容 (*)和取地址 (&)两种运算。
⑼求字节运算符用于数据类型所占的字节数 (sizeof)。
⑽ 强制类型转换运算符可以利用强制类型转换运算符将一个表达式转换成所需类型。其一般形式为:
(类型名)(表达式)
如 (double)a; (int)(x+y); (float)(5%3)
⑾ 其他运算符其他运算符有,括号 ()、数组下标 []、成员运算符,和用指针访问结构体成员的指向运算符 ->。
2.运算符的运算优先级
C语言中,运算符的运算优先级共分为 15级。 1级最高,15级最低。在表达式中,优先级较高的先于优先级低的进行运算。
如求表达式 x+y*z的值:
y的值左侧为加号,右侧为乘号,而乘号优先于加号,因此相当于 x+(y*z),即先进行乘法运算,然后再进行加法运算。
3,运算符的结合性
C语言的运算符不仅具有不同的优先级,还有结合性的问题。在表达式的运算过程中,各运算对象参与运算的先后顺序不仅要遵循运算符优先级别的规定,
还要受运算符结合性的制约,当一个运算对象两侧的运算符优先级别相同时,
需按运算符的结合性来处理,以便确定是自左向右进行运算还是自右向左进行运算。
C语言中运算符的结合性分为两种:即左结合性 (自左向右 )和右结合性 (自右向左 )。
例如,算术运算符就是左结合性的运算符表达式,x-y+z,运算对象 y的左侧运算符
,-”和右侧运算符,+”优先级相同,应按结合性来进行自左向右的运算,即先执行
x-y运算,再执行 +z的运算。
赋值运算符是右结合性的运算符表达式,x=y=z,由于赋值运算符,=”的右结合性,所以先执行 y=z运算,再执行
x=(y=z)运算。
优先级别运算符 运算形式 结合方向 含义
1
()
[]
.
->
(e)
a[e]
x.y
p->x
自左至右圆括号数组下标运算符结构体成员运算符指向结构体成员运算符
2
-
++ --
!
~
(t)
*
&
sizeof
-e
++x或 x++
!e
~t
(t)e
*p
&x
sizeof(t)
自右至左负号运算符自增运算符和自减运算符逻辑非运算符按位取反运算符强制类型转换运算符指针运算符,由地址求内容求变量地址的运算符求某类型变量的长度运算符
3 * / % e1*e2 自左至右 乘、除、求余运算符表 2.2 C语言各运算符的优先级别与结合方向
4 + - e1+e2 自左至右 加法、减法运算符
5 << >> e1<<e2 自左至右 左移、右移运算符
6 < <= > >= e1<e2 自左至右 关系运算符
7 = = != e1= =e2 自左至右 等于、不等于运算符
8 & e1&e2 自左至右 按位与运算符
9 ^ e1^e2 自左至右 按位异或运算符
10 | e1|e2 自左至右 按位或运算符
11 && e1&&e2 自左至右 逻辑与运算符
12 || e1||e2 自左至右 逻辑或运算符
13?,e1?e2:e3 自右至左 条件运算符
14
= += -=
*= /= %=
>>= <<=
&= ^= |=
x=e
x+=e
x&=e 自右至左 赋值运算符
15,e1,e2 自左至右 逗号运算符(顺序求值)
续表
⑴ 同一优先级的运算符优先级别相同,运算次序由结合方向决定;
⑵不同的运算符要求有不同的运算对象个数如
+(加 )和 -(减 )为双目运算符,要求在运算符运算符两侧各有一个运算对象 (如 3+5,8-3等 );
而 ++(自增 )和 -(负号 )运算符为单目运算符,
只能在运算符的一侧出现一个运算对象 (如 -a、
i++,--i,(float)i,sizeof(int),*p等 );条件运算符是 C语言中唯一的三目运算符,如
x? a,b。
⑶从上述表中可以大致归纳出各类运算符的优先级:
表 2.2说明:
特殊运算符 ( ) [ ],->
单目 运算符算术运算符关系 运算符逻辑运算符 (不包括 !)
条件运算符赋值运算符逗号运算符优先级别由上到下递减。
特殊运算符优先级最高,
逗号运算符优先级最低。
位运算符的优先级比较分散 (有的在算术运算符之前
(如 ~),有的在关系运算符之前 (如 <<,>>),有的在关系运算符之后 (如 &,^,|))。
2.4.2 算术运算符和算术表达式
1.基本的算术运算符基本的算术运算符有:加( +)、减( -)、乘
( *)、除( /)、求余(或称模运算,%)五种。
两个整数相除的结果为整数,如 5/3的结果为 1,舍去小数部分。但是,如果除数或被除数中有一个为负值,多数机器采取“向零取整”的方法,即 5/3=1,-5/3=-1,取整后向零靠拢。
求余运算符,%”要求参与运算的量均为整型,运算结果等于两数相除后的余数,余数的符号取决于被除数的符号,如 -100%3余数为 -1,100%-3余数为 1。
2.自增自减运算符
++i,--i 在使用 i之前,先使 i的值加 (减 )1
i++,i-- 在使用 i之后,再使 i的值加 (减 )1
粗略地看,++i和 i++的作用相当于 i=i+1,但
++i和 i++不同之处在于 ++i是先执行 i=i+1后,
再使用 i的值;而 i++是先使用 i的值后,再执行 i=i+1。
例 2.6
如果 i的原值等于 3,执行下面的赋值语句:
① j=++i;( i的值先变为 4,再赋给 j,j的值为 4)
② j=i++;(先将 i的值 3赋给 j,j的值变为
3,然后 i的值变为 4)
例 2.7
P35例 2.5
main()
{int c=5;
printf(“%d,%d,%d\n”,c+=c++,c+8,++c);
printf(“%d\n”,c+=c++,c+8,++c);
}
注意,Turbo C规定,printf()函数中出现多个表达式输出项时,先按从右到左的顺序计算各表达式的值,然后再从左到右输出结果。本例中先计算 ++c,得 c=6,然后计算 c+8得 14,最后计算 c+=c++,得 c=13。
1.有如下两个程序,试比较结果
① main()
{int i=3;
printf(“%d,%d\n”,(i++)+(i++)+(i++),i);}
② main()
{int i=3,k;
k=(i++)+(i++)+(i++);
printf(“%d,%d\n”,k,i);}
补充:
① 结果,12,3?② 结果:
9,6
2.当出现难以区分的若干个 +或 -组成运算符串时,C语言规定,自左向右取尽可以多的符号组成运算符。
例如:设整型变量 x,y均为 3,则:
x+++y 应理解为 (x++)+y,结果为 6,x值为 4,y值不变
x---y 应理解为 (x--)-y,结果为 0,x值为 2,y值不变
3.算术运算符的优先规则
① 单目算术运算符 (-,++,--)优先于 *,/,%
算术运算符优先于 +,-算术运算符;
② 同级单目算术运算符的结合性自右向左;
③ 同级双目算术运算符的结合性自左向右。
4.算术表达式用算术运算符和括号将运算对象连接起来的式子,称为算术表达式。例如下面的表达式为算术表达式:
a*b/c-1.5+?a?
如果一个算术运算符的两侧的数据类型不同,则按下面所述的内容先自动进行类型转换,使二者具有同一类型,然后再进行运算。
各类数值型数据间的混合运算整型 (包括 int,short,long,unsigned int,
unsigned short,unsigned long)和实型 (包括
float,double)数据可以混合运算。而字符型数据可以与整型通用,因此整型、实型和字符型数据间可以混合运算,在进行运算时,不同类型 的数据要先换成同一类型,然后进行运算,转换规则如下图所示:
double float
long
unsigned
int char,short
高低图中横向向左的箭头表示必须的转换,如字符数据必须先转换为整数,short型转换为 int,float型数据在运算时一律先转换为 double型,以提高精度 (即使是两个 float型数据相加,也先都化成 double型,然后再相加 )。
纵向的箭头表示当运算为不同类型时转换的方向。例如 int
型与 double型数据进行运算,先将 int型数据转换为 double型,
然后在两个同类型 (double型 )数据间进行运算,结果为 double
型。注意箭头方向只表示数据类型级别的高低,由低向高转换。不要理解为 int型先转换为 unsigned int型,再转成 long型,
再转成 double型。如果一个 int型数据与一个 double型数据运算,是直接将 int型转换成 double型。
例 2.8
假设已指定 i为 int型变量,f为 float型变量,d为 double型变量,e为 long型变量,
有以下式子:
10+?a?+i*f-d/e
在计算机执行时从左至右扫描,运算次序为,①进行
10+?a?的运算,先将‘ a?转换为整数 97,运算结果为 107;
②由于,*”比,+”优先,先进行 i*f的运算。先将 i与 f都转换成 double型,运算结果为 double型;③整数 107与
i*f的结果相加。先将整数 107转换成 double型,再相加,
结果为 double型;④将变量 e化为 double型,d/e结果为
double型;⑤将 10+?a?+i*f的结果与 d/e的商相减,结果为 double型 。
main()
{float x;
int i;
x=3.6;
i=(int)x;
printf(“x=%f,i=%d”,x,i);}
结果:
x=3.600000,i=3
上述类型转换由系统自动进行的,另一种类型转换为强制类型转换。
需要说明的是在强制类型转换时,得到一个所需类型的中间变量,原来变量的类型未发生变化。如:
(int)x;如果 x原来指定为 float型,进行强制类型运算后得一一个 int型的中间变量,它的值等于 x 的整数部分,
而 x的类型不变 (仍为 float型 )。见下例 2.9:
2.4.3 关系运算符和关系表达式所谓“关系运算”实际上是“比较运算”。将两个值进行比较,判断其比较的结果是否符合给定的条件。例如,a>3是一个关系表达式,大于号 (>)是一个关系运算符,如果 a的值为 5,则满足给定的
,a>3” 条件,因此关系表达式的值为逻辑值“真” (即“条件满足” ),用整数,1”
来表示;如果 a的值为 2,不满足,a>3”的条件,则称关系表达式的值为逻辑值
“假”,用整数,0”来表示。
1,关系运算符及其优先次序
C语言提供下面 6种关系运算符:
① < (小于 )
② <= (小于等于 )
③ > (大于 )
④ >= (大于等于 )
⑤ == (等于 )
⑥ != (不等于 )
优先级相同 (高)
优先级相同 (低)
关于优先顺序:
⑴前 4种关系运算符 (<,<=,>,>=)的优先级别相同,后
2种也相同。前 4种高于后 2种;
⑵关系运算符的优先级低于算术运算符;
⑶关系运算符的优先级高于赋值运算符。
例 2.10
例如,
c>a+b 等效于 c>(a+b)
a>b==c 等效于 (a>b)==c
a==b<c 等效于 a==(b<c)
a=b>c 等效于 a=(b>c)
用关系运算符将两个表达式 (可以是算术表达式、关系表达式、逻辑表达式、
赋值表达式、字符表达式 )连接起来的式子,称为关系表达式。
关系表达式的值是一个逻辑值,即
“真”或“假”。例如,关系表达式
,5==3”的值为“假”,,5>=0”的值为
“真”。 C语言没有逻辑型数据类型,以
1代表“真”,以 0代表“假”。
2,关系表达式例 2.11
a=3,b=2,c=1,则:
关系表达式,a>b”的值为“真”,表达式的值为
1;
关系表达式,(a>b)==c”的值为“真” (因为 a>b的值为 1,等于 c的值 ),表达式的值为 1;
关系表达式,b+c<a”的值为“假”,表达式的值为 0;
若有以下赋值表达式:
d=a>b d的值为 1
f=a>b>c f 的值为 0(因为,>”运算符是自左向右的结合方向,先执行,a>b”得值为例 2.12 P36例 2.6
main()
{int a=5,b=3;
float x=3.14,y=6.53;
printf(“%d,%d\n”,a+b!=a-b,x<=(y-=6.1));
}
结果,1,0
2.4.4 逻辑运算符
C语言提供的逻辑运算符有三种,&&(逻辑与 ),||(逻辑或 ),!(逻辑非 )。
,&&”和,||”为双目运算符,它要求有两个运算量,如 (a>b)&&(x>y),(a<b)||(x>y)。
,!”是单目运算符,只要求有一个运算量,
如 !(a>b)。
1.逻辑运算符及其优先次序逻辑运算举例如下:
a&&b 若 a,b为真,则 a&&b为真。
a||b 若 a,b之一为真,则 a||b为真。
!a 若 a为真,则 !a为假。
a b !a !b a&&b a||b
真 真 假 假 真 真真 假 假 真 假 真假 真 真 假 假 真假 假 真 真 假 假表 2.3逻辑运算的真值表在一个逻辑表达式中如果包含多个逻辑运算符,如 !a&&b||x>y&&c,按以下的优先顺序和结合性:
① !优先于双目算术运算符优先于关系运算符优先于 &&优先于 ||;
② 单目逻辑运算符 !和单目算术运算符同级别,结合性自右向左;
③ 双目逻辑运算符的结合性是自左向右。
2.逻辑表达式如前所述,逻辑表达式的值应该是一个逻辑量“真”或“假”。 C语言编译系统给出逻辑运算结果时,以数值 1代表“真”,以 0代表“假”,但在判断一个量是否为“真”时,以 0代表
“假”,以非 0代表“真”。即将一个非 0的数值认作“真”。例如:
① 若 a=4,则 !a的值为 0。因为 a的值为非 0,
被认作“真”,对它进行“非”运算,
得“假”,“假”以 0来代表。
② 若 a=4,b=5,则 a&&b的值为 1。因为 a和 b均为非
0,被认为是“真”,因此 a&&b的值也为
“真”,值为 1。
③ a,b值同前,a||b的值为
④ a,b值同前,!a||b的值为
⑤ 4&&0||2的值为结论:由系统给出的逻辑运算结果不是就是 1,不可能是其他数值。而在逻辑表达式中作为参加逻辑运算的运算对象可以是 0(“假” )
或任何非 0的数值 (按“真” )对待。如果在一个表达式中不同位置上出现数值,应区分哪些是作为数值运算或关系运逄的对象,哪些作为逻辑运算的对象。例如
1
1
1
5>3&&8<4-!0
表达式自左到右扫描求解。首先处理
,5>3”(因为关系运算符优先于 &&)。在关系运算符两侧的 5和 3作为数值参加关系运算,
,5>3”的值为 1。再进行,1&&8<4-!0”运算,
8的左侧为,&&”,右侧为,<”运算符,根据优先规则,应先进行,<”的运算,即先进行
,8<4-!0”的运算。现在 4的左侧为,<”,右侧为,-”运算符,而,-”优先于,<”,因此应先进行,4-!0”的运算,由于,!”级别高,因此先进行,!0”的运算,得到结果 1。然后进行,4-1”
的运算,得结果 3,再进行,8<3”的运算,得结果 0,最后进行,1&&0”的运算,得到结果 0。
注意在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。
① a&&b&&c 只有 a为真 (非 0)时,才需在判断
b的值,只有 a和 b都为真的情况下才需在判别
c的值。只要 a为假,就不必判别 b和 c(此时整个表达式已确定为假 )。如果 a为真,b为假,
不判别 c。
② a||b||c 只要 a为真 (非 0),就不必判断 b
和 c;只有 a为假,才需要判别 b; a和 b都为假才判别 c。
例 2.13
① main()
{int w=1,x=2,y=3,z=4,a=5,b=6,c;
c=(a=w>x)&&(b=y>z);
printf(“a=%d,b=%d,c=%d\n”,a,b,c);}
结果,a=0,b=6,c=0
② main()
{int m,n,l,a,b,c,d;
m=n=a=b=c=d=0;
l=(m=a= =b)||(n=c= =d);
printf(“m=%d,n=%d,l=%d\n”,m,n,l);}
结果,m=1,n=0,l=1
2.4.5赋值运算符和赋值表达式
1.简单赋值运算符赋值符号,=”就是赋值运算符,
它的作用是将一个数据赋给一个变量。如,a=3”的作用就是执行一次赋值运算,把常量 3赋给变量 a。也可以将一个表达式的值赋给一个变量。如,x=a+b*c。
2.复合赋值运算符在赋值符,=”之前加上某些二目运算符可构成复合赋值运算符。
复合算术赋值运算符有,+=,-=,*=、
/=,%=五种。
复合位运算赋值运算符有,<<=,>>=、
&=,^=,|=五种。
3.赋值表达式由赋值运算符将一个变量和一个表达式连接起来的的式子称为“赋值表达式”。其一般形式为:
<变量 ><赋值运算符 ><表达式 >
① 赋值表达式的求解过程:将赋值运算符右侧的“表达式”的值赋给左侧的变量,
赋值表达式的值就是被赋值的变量的值。
如,a=5”这个赋值表达式的值为 5(变量
a的值也为 5)。
② 上述赋值表达式的一般形式中的“表达式”,又可以是一个赋值表达式。如
a=(b=5),括号内的,b=5”是一个赋值表达式,它的值等于 5。,a=(b=5)”相当于,b=5”和,a=b”两个赋值表达式,
因此 a的值等于 5,整个赋值表达式的值也等于 5。
我们知道赋值运算符按照“自右向左”的结合顺序,因此,,b=5”外面的括号可以不要,即,a=(b=5)”和
,a=b=5”等价,都是先求,b=5”的值
(得 5),然后再赋给 a,下面举几个例子:
a=b=c=5 (赋值表达式值为 5,a,b,c
值均为 5)
a=5+(c=6) (表达式值为 11,a值为 11,c
值为 6)
a=(b=4)+(c=6) (表达式值为 10,a值为 10,
b值为 4,c 值为 6)
a=(b=10)/(c=2) (表达式值为 5,a值为 5,b
值为 10,值为 2)
③ 赋值表达式中可包含复合的赋值运算符。如,a+=a-=a*a,如果 a的初值为 12,此赋值表达式的求解步骤如下:
a)先进行,a-=a*a”运算,它相当于
a=a-a*a=12-144=-132;
b)再进行,a+=-132”运算,相当于
a=a+(-132)=-132-132=-264。
补充如果赋值运算符两侧的类型不一致,
但都是数值型或字符型时,在赋值时要进行类型转换。
I,将实型数据 (包括单、双精度 )赋给整型变量时,舍弃实数的小数部分。如 i为整型变量,
执行,i=3.56”的结果是使 i的值为 3,在内存中以整数形式存储。
II,将整型数据赋给单、双精度变量时,数值不变,但以浮点数形式存储到变量中,如将 23
赋给 float变量 f,即 f=23,先将 23转换成
23.00000,再存储在 f中。如将 23赋给 double
型变量 d,即 d=23,则将 23补足有效位数字为
23.00000000000000,然后以双精度浮点数形式存储到 d中。
III,将一个 double型数据赋给 float变量时,截取前面 7位有效数字,存放到 float变量的存储单元中,但应注意数值取值范围不以溢出。
IV,字符型数据赋给整型变量时,由于字符只占有 1个字节,而整型变量占 2个字节,因此将字符数据 (8位 )放到整型变量低 8位中,整型变量高 8位有两种情况:
① 若是将 unsigned char数据赋给整型变量,高
8位补 0。
② 若是将 char数据赋给整型变量,如果字符最高位为 0(0~127),则整型变量高 8位补 0;
如果字符最高位为 1(-128~-1),则整型变量高 8 位补 1。
V,将一个 int,short,long型数据赋给一个 char
型变量时,只将其 8位原封不动地送到 char
型变量 (即截断 )。
VI,将 int型数据赋给 long型变量时,要进行符号扩展,将整型数据的 16位送到 long型低 16位中,如果 int型数据为正值 (符号位为 0),则
long型变量的高 16位补 0;如果 int型变量为负值 (符号位为 1),则 long型变量的高 16位补
1,以保持数值不变。
VII,将 unsigned int型数据赋给 long型变量时,不存在符号扩展问题,只需将高位补 0。
VIII,将一个 unsigned 类型数据赋给一个占字节数相同的 signed 变量 (如,unsigned int=>int,
unsigned long=>long,unsigned short=>short,
unsigned char=>char),将 unsigned型数据的
IX,内存中各位原样送到 signed型变量中,
若 unsigned 类型数据未超过要赋值的变量的范围,则 signed型变量值与
unsigned型数据值相同;若超过,要根据补码知识进行转换。如:
main()
{unsigned int a=65535;
int b;b=a;
printf(“%d”,b);}
结果输出 -1
将 signed型数据赋给所占字节相同的 unsigned
型变量,同样将 signed型数据所占内存的各位原样送到 unsigned型变量内存中,若 signed型数据为非负值,则 unsigned型变量值与 signed型数据值相同;若为负值,要根据补码知识进行转换。如:
main()
{unsigned a;
int b=-1;a=b;
printf(“%u”,a);}
结果输出 65535。
2.4.6 条件运算符和条件表达式
1.条件运算符条件运算符要求有 3个操作对象,
它是 C语言中唯一的三目运算符。
条件运算符的优先级规则:
① 其他运算符优先于条件运算符,条件运算符优先于赋值运算符和逗号运算符;
② 条件运算符的结合性是自右向左。
2.条件表达式用条件运算符构成的表达式称为条件表达式,其一般形式为:
表达式 1?表达式 2:表达式 3
条件表达式的执行顺序是:先计算表达式 1的值,若值为非 0(真 ),则计算表达式 2的值,并将表达式 2的值作为整个条件表达式的结果;若表达式 1的值为 0(假 ),
则计算表达式 3的值,并将表达式 3的值作为整个条件表达式的结果。
例 2.14
main()
{int a=1,b=2,c=3,d=4,e;
e=a>b?a:c<d?c:d;
printf(“%d\n”,e);}
条件运算符的结合方向为,自右向左,。
所以条件表达式 a>b?a:c>d?c:d相当于
a>b?a:(c>d?c:d)。
2.4.7 逗号运算符和逗号表达式
C语言中提供了一种特殊的运算符 ——
逗号运算符。它用来将两个表达式连接起来组成一个表达式,如 3+5,6+8
称为逗号表达式。其一般形式为:
表达式 1,表达式 2
其求解过程是:先求解表达式 1,再求解表达式 2,并将表达式 2的值作为整个逗号表达式的值。如上面的逗号表达式
,3+5,6+8”的值为 14,又如
a=3*5,a*4
由表 2.2可知:赋值运算符的优先级别高于逗号运算符,因此应先求解 a=3*5这个赋值表达式,计算得这个赋值表达式值为
15,再求解 a*4这个表达式,得 60,整个逗号表达式的值为 60。
一个逗号表达式又可以与另一个表达式组成一个新的表达式,所以逗号表达式的一般形式可扩展为:
表达式 1,表达式 2,表达式 3 表达式 n
顺序求解这 n个表达式,整个表达式值为表达式 n的值。
请注意并不是任何地方出现的逗号都是作为逗号运算符,例如
① 变量说明,int a,b,c;
② 函数参数,printf(“%d,%d,%d”,a,b,c);其中的,a,b,c”并不是一个逗号表达式,
它是 printf函数的 3个参数。
2.4.8 位运算符和位运算
1.“按位与”运算符 (&)
参与运算的两个数,按二进位进行“与”
运算。如果两个相应的二进位都为 1,则该位的结果值为 1,否则为 0。即:
0&0=0; 0&1=0; 1&0=0; 1&1=1
2.“按位或”运算符 (|)
参与运算的两个数,按二进位进行
“或”运算。如果两个相应的二进位只要一个为 1,则该位的结果值为 1,即:
0&0=0; 0&1=1; 1&0=1; 1&1=1
3.“按位异或”运算符 (^)
异或运算符 ^也称 XOR运算符。它的规则是若参加运算的两个二进位相异时,
结果位为 1。 即
0^0=0; 0^1=1; 1^0=1; 1^1=0
2.4.8 位运算符和位运算
4.“按 位取反”运算符 (~)
~是一个单目运算符,用来对一个二进制数按位取反,即将 0变为 1,1变为 0。
例 2.15
教材 P37例 2.9
第三章 输入和输出所谓输入输出是以计算机主机为主体而言的,
从计算机向外部输出设备 (如显示屏、打印机、
磁盘等 )输出数据称为“输出”,从外部由输入设备 (如键盘、磁盘、光盘、扫描仪等 )输入数据称为“输入”。
一个完整的程序都应该有数据的输入输出功能,没有输出功能是无用的,因为程序运行的结果看不见;没有输入功能则程序缺乏灵活性,每次运行都只能对相同的数据执行操作,
所以输入输出是程序中不可缺少的部分。
C语言中输入和输出都是由函数来实现的,C提供的函数以库的形式存放在系统中 (如输入输出函数库、数学函数库、字符函数库、字符串函数库等 ),每个函数库含有若干个函数,C语言提供了一批标准输入输出函数,其中有 putchar(输出字符 )、
getchar(输入字符 ),printf(格式输出 ),
scanf(格式输入 ),puts(输出字符串 )、
gets(输入字符串 ),本章中介绍前四个最基本的输入输出函数。
在使用 C语言库函数时,要用文件包含命令
,#include”将有关的“头文件”包括到用户的源文件中,在头文件中包含了要用到的函数有关的一些信息,如变量的定义和宏定义。例如使用标准输入输出库函数时,要用到,stdio.h”
文件,stdio是 standard input&output的缩写,文件后缀,h”是 head的缩与,#include命令都是放在程序的开头,因些这类文件又被称为“头文件”,在调用标准输入输出库函数时,程序开头应用以下文件包含命令:
#include<stdio.h>
考虑到 printf和 scanf函数使用频繁,系统允许在使用这两个函数时可不加 #include命令。
3.1字符的输入输出函数
C语言提供了两个标准的 字符 输入输出函数 putchar和 getchar,在使用这两个函数时,在程序的头部一定要加上下面的文件包含命令:
#include<stdio.h>
3.1.1字符输出函数 (putchar)
putchar函数的作用是向终端 (显示屏 )输出 一个字符,其一般形式为
putchar(ch);
意思是在显示屏上输出括号内字符变量 ch所代表的字符,ch可以是字符数据
(常量或变量 )和整型数据 (常量或变量 )。
例 3.1
教材 P49例 3.7
#include<stdio.h>
main()
{char a=?Y?;b=?e?;putchar(a);putchar(b);
putchar(?s?);putchar(?\n?);putchar(?\141?);}
Yes
a
结果:
3.1.2字符输入函数 (getchar)
getchar函数的作用是从终端 (键盘 )设入一个字符 。其一般形式为:
getchar();
getchar()只能接收一个字符,该字符可以赋给一个字符变量或整型变量,也可以不赋给任何变量,作为表达式的一个运算对象参加表达式的运算处理。
例 3.2
教材 P50例 3.8
#include<stdio.h>
main()
{char c;c=getchar();putchar(c);}
例 3.3
教材 P50例 3.9
#include<stdio.h>
main()
{int c;c=getchar();
c>=?a?&&c<=?zputchar(c+?A?-?a?):putchar(c);}
3.2 格式输入输出函数
C语言提供了两个标准的格式输入输出函数,即格式输入函数 scanf和格式输出函数 printf。
字符输入输出函数只能输入输出单个字符,而格式输入输出函数可按指定的格式输入输出若干个任意类型的数据。
3.2.1格式输出函数 (printf)
printf函数作用是按用户指定的格式,
把若干个任意类型的数据输出到显示屏上。
其一般形式为
printf(“格式控制字符串”,输出表列 );
格式控制字符串用来指定输出的格式,
它由格式字符串和非格式字符串两大类组成。
格式字符串是以 %开头的字符串,用来指定输出数据的类型、形式、长度、小数位数等。
非格式字符串包括普通字符 (原样输出 )
和转义字符 (如 \n,\t,\r,\101等 )。
输出表列表示要输出的各个数据项,
要求格式字符串和各输出项在数量和类型上应该一一对应。
1.格式字符串格式字符串的一般形式为:
%[标志 ][输出最小宽度 ][.精度 ][长度 ]类型
① 类型:指定输出数据的类型格式符 意义
d 以十进制形式输出有符号整数 (正数不输出符号 )
o 以八进制形式输出无符号整数 (不输出前缀 0)
x 以十六进制形式输出无符号整数 (不输出前缀 0x)
u 以十进制形式输出无符号整数 (不输出符号 )
c 输出单个字符
s 输出字符串
f 以小数形式输出单、双精度实数
e 以指数形式输出单、双精度实数
g 以 %f和 %e中较短宽度输出单、双精度
② 标志,有 -,+,#,0四种标志 意义
- 输出结果左对齐,右边补空格
+ 输出符号 (正号或负号 )
# 对 c,s,d,u无影响;对 o在输出时加前缀 0;对 x在输出时加 ox;
0 输出结果右对齐时,左边空格用 0代替
③ 输出最小宽度:用十进制正整数来表示输出的最小位数,若实际位数多于定义的宽度,
则按实际位数输出,若实际位数少于定义的宽度则补以空格或 0。
④ 精度:以,.”开头,后跟十进制正整数,如果输出实数,则表示小数的位数;如果输出字符串,则表示输出字符的宽度,若实际小数位数大于所定义的精度数,要截去超过的部分。
⑤ 长度:格式符,l”表示按长整型输出。
例 3.4
main()
{unsigned int a=65535;
int b=-2;
printf(“a=%d,%o,%x,%u\n”,a,a,a,a);
printf(“b=%d,%o,%x,%u\n”,b,b,b,b);
}
结果,a=-1,177777,ffff,65535
b=-2,177776,fffe,65534
例 3.5字符串的输出
main()
{printf(“%3s,%7.2s,%.4s,%-5.3s\n”,
“china”,“china”,“china”,”china”);
}
结果,china,ch,chin,chi
例 3.6输出实数时指定小数位数
main()
{float f=123.456;
printf(“%f%10f%10.2f%.2f
%-10.2f\n”,f,f,f,f,f);
}
结果:
123.456001123.456001123.46123.46123.46
3.2.2格式输入函数 (scanf)
scanf函数作用是按用户指定的格式从键盘上把数据输入到指定的变量中。
其一般形式为:
scanf(“格式控制字符串”,地址表列 );
格式控制字符串是用来指定要输入的数据的格式,地址表列给出要赋值的各变量的地址,地址由地址运算符,&”后加变量名构成,如 &a表示变量 a的地址。
1.格式字符串格式字符串的一般形式为:
%[*][输入宽度 ][长度 ]类型
① 类型:指定输入数据的类型格式符 意义
d 输入十进制整数
o 输入八进制整数
x 输入十六进制整数
u 输入十进制无符号整数
c 输入单个字符
s 输入字符串
f 以小数形式输入实数
e 以指数形式输入实数
②,*” 格式符用来表示所对应的输入项读入后不赋予相应的变量。如
scanf(“%d %*d %d”,&a,&b);
当输入 1 2 3时,把 1赋给变量 a后,
跳过 2,再把 3赋给变量 b。
③ 输入宽度:是十进制的正整数,用来指定输入的宽度,系统自动按它截取所需数据。如:
scanf(%3d%3d”,&a,&b);
输入,123456,系纺自动将 123赋给变量 a,456赋给变量 b。
④ 长度,l表示输入长整型数据 (如 %ld)和双精度浮点数 (如 %lf);h表示输入短整型数据 (如 %hd)。
2.使用 scanf函数应注意的问题
scanf函数中的“格式控制字符串”后面应当是变量地址,而不是变量名。如:
若 a,b为整型变量,则:
scanf(“%d,%d”,a,b);是错误的,应将 a,b改为 &a,&b。
如果在“格式控制字符串”中有非格式字符则在输入数据时,也应输入与这些字符相同的字符。如:
scanf(“%d,%d,%d”,&a,&b,&c);
格式控制字符串中有非格式字符“,”以作间隔符,输入时一定要输为,1,2,3
同样:
scanf(“a=%d,b=%d,c=%d”,&a,&b,&c);
输入时要输为,a=1,b=2,c=5
在输入多个数值数据时,如果格式控制字符串中没有非格式字符作输入数据之间的间隔符时,则可用空格,tab或回车作间隔;在输入字符数据时,若格式控制字符串中没有非格式字符,则所有输入的字符都被认为是有效字符,如:
scanf(“%c%c%c”,&a,&b,&c);
若输入为 d ef,系统把’ d?赋给变量 a,把
‘ ’赋给变量 b,?e?赋给变量 c。
scanf函数中不能规定精度,如:
scanf(“%7.2f”,&a);是不合法的。
第四章 语句和流程控制流程主要用来规定程序的执行的顺序。
流程分为 3种基本结构:顺序、分支、
循环。各种复杂的程序都可由这三种基本结构来构成。 C语言提供了多种语句来实现这三种结构。
4.1 C语句应当指出,C语句都是用来完成一定操作任务的,声明部分的内容不应称为语句,如 int a;
C语句可分为以下 5类:
表达式语句由表达式加上分号,;”组成,如:
a=3 是一个赋值表达式而 a=3; 是一个赋值语句
函数调用语句由函数名、实际参数加上分号,;”组成,
执行函数调用语句就是把实际参数赋给被调用函数
控制语句
C有 9种控制语句:
① if语句 (条件语句 )
② switch语句 (多分支选择语句 )
③ while语句
④ do while语句
⑤ for语句条件判断语句循环执行语句
⑥ goto语句 (转向语句 )
⑦ break语句 (中止执行 switch或循环语句 )
⑧ continue语句 (结束本次循环语句)
⑨ return语句 (函数调用返回值语句 )
复合语句把多个语句用花括号 {}括起来组成一个语句,
如:
{z=x+y;t=z/100;printf(“%f”,t);}
空语句只用一个分号,;”组成的语句,空语句表示什行也不做,有时用来作循环语句中的空循环体。
4.2 分支结构分支结构又称为选择结构,根据对指定条件的判断决定执行某个分支程序段。
4.2.1 if语句
if语句是用来判定所给定的条件是否满足,根据判定的结果 (真或假 )决定执行给出的两种操作之一。
一,if语句的 3种形式:
1,if(表达式 ) 语句;
如果表达式的值为真,则执行其后的语句,否则不执行该语句。
表达式真语句假例 4.1 输入 a,b两个整数,并由小到大输出。
main()
{int a,b,t;
scanf(“%d,%d”,&a,&b);
if(a>b) {t=a;a=b;b=a;}
printf(“%d,%d\n”,a,b);
}
2,if(表达式 )
语句 1;
else
语句 2;
表达式真语句 1
假语句 2
例 4.2用 if-else语句重写例 4.1。
main()
{int a,b;
scanf(“%d,%d”,&a,&b);
if(a<b)
printf(“%d,%d\n”,a,b);
else
printf(“%d,%d\n”,b,a);
}
3,if(表达式 1)
语句 1;
else if(表达式 2)
语句 2;
else if(表达式 3)
语句 3;
...…
else if(表达式 m)
语句 m;
else
语句 n;
语句 n
表达式 1真语句 1
假表达式 2真假语句 2
表达式 3真真语句 3

假表达式 m
真 假语句 m

例 4.3P62例 4.3
#include<stdio.h>
main()
{char c;
printf(“input a character:”;c=getchar();
if(c<32)
printf(“This is a control character!\n”);
else if(c>=?0?&&c<=?9?)
printf(“This is a digit!\n”);
else if(c>=?A?&&c<=?Z?)
printf(“This is a capital letter!\n”);
else if(c>=?a?&&c<=?z?)
printf(“This is a small letter!\n”);
else
printf(“This is an other character!\n”);
}
二,if语句的嵌套当 if语句中的执行语句又是 if语句就构成了 if语句的嵌套。一般形式如下:
if(表达式 1 )
if(表达式 2) 语句 1;
else 语句 2;
else
if(表达式 3) 语句 3;
else 语句 4;
内嵌 if
内嵌 if
表达式 1
真语句 1
假语句 2
表达式 2
真 假 真 假表达式 3
语句 3 语句 4
注意:
对 if语句的嵌套,可能会出现多个 if和多个 else,这就特别要注意 if和 else的配对问题
else总是与它前面最近的且不带 else的
if配对。
例 4.4
if( )
if( ) 语句 1;
else
if( ) 语句 2;
else 语句 3;
编程者本意把 else写在与第一个 if(外层 if)
同一列上,希望 else与第一个 if对应,但实际上 else是与第二个 if配对,因为它们距离最近。
为实现程序设计者的意图,可以加花括号来确定配对关系:
if( )
{if( ) 语句 1;}
else
if( ) 语句 2;
else 语句 3;
4.2.2 switch语句
if语句只有两个分支可供选择,而实际问题中常常需要用到多分支的选择。例如,
学生成绩分等级 (90分以上为‘ A?等,
80~89分为‘ B?等,70~79分为‘ C?等 …… );
人口统计分类 ( 按年龄段分类老年、中年、
青年、少年、儿童 )等等。
虽然这些问题都可以用嵌套的 if语句来处理,但如果分支多,则嵌套的 if语句层数多,程序冗长而且可读性差。 C语言提供了 switch语句直接处理多分支的选择。
switch语句的一般形式为:
switch(表达式 )
{case 常量表达式 1:语句 1;
case 常量表达式 2:语句 2;..
.
case 常量表达式 n:语句 n;
[defaule:语句 n+1; ]
}
先计算表达式的值,并逐个与其后的常量表达式值相比较,当与某个常量表达式的值相等时,就执行其后的语句,然后不再进行判断,继续执行其后的语句。
如果表达式的值与所有 case后的常量表达式值都不相等,
则执行驶 default后的语句,若无 default语句,则什么也不做。
例 4.5 按照输入的考试等级打印了分数段。
main()
{char grade;
printf(“input grade:”);
scanf(“%c”,&grade);
switch(grade)
{case?A?:printf(“90-100\n”);
case?B?:printf(“80-89\n”);
case?C?:printf(“70-79\n”);
case?D?:printf(“60-69\n”);
case?E?:printf(“0-59\n”);
default:printf(“error\n”); }
}
若输入 grade的值为‘ A?,则输出:
90-100
80-89
70-79
60-69
0-59
error
因此,要想在执行一个 case分支后,
使流程跳出 switch,必须用一个 break语句来达到目的。
main()
{char grade;
printf(“input grade:”);
scanf(“%c”,&grade);
switch(grade)
{case?A?:printf(“90-100\n”);break;
case?B?:printf(“80-89\n”);break;
case?C?:printf(“70-79\n”);break;
case?D?:printf(“60-69\n”);break;
case?E?:printf(“0-59\n”);break;
default:printf(“error\n”); }
}
此时,若输入 grade的值为‘ A?,则输出:
90-100
补充:
多个 case可以共用一组执行语句,如:
main()
{char grade;
printf(“input grade:”);
scanf(“%c”,&grade);
switch(grade)
{case?A?:
case?B?:
case?C?:
case?D?:printf(“>=60\n”);break;
case?E?:printf(“<60\n”);break;
default:printf(“error\n”); }
}
若输入 grade的值为‘ A?、‘ B?、‘ C?、
‘ D?,输出都为:
>=60
4.3 循环结构
1*1+2*2+3*3=?
int s;
s=1*1+2*2+3*3;
引入循环结构就可以简化程序中大量的重复操作。
在 C语言中,循环结构是由 while语句,do while
语句和 for语句来实现的。为了更方便地控制程序流程,C语言还提供了两个循环辅助语句,break语句和 continue语句。
1*1+2*2+3*3+? +100*100=?
4.3.1 while语句
while(表达式 )
语句 ;
表达式循环体真假
while语句的工作过程是:
首先计算括号中的测试表达式,如果表达式的值为真,则执行循环体。循环体中的语句执行完后,
返回 while 处,重新计算测试表达式。如果测试表达式的值还为真,则继续执行循环体。依此循环,直至测试表达式的值为假,
跳出 while循环。
#include <stdio.h>
main( )
{
/*定义循环变量 i和 sum变量 */
int i,sum;
i=1;/*循环变量赋值 1*/
sum=0;/*sum赋值 0*/
while(i<=100)/*计算 100次 */
{
sum=sum+i;
/*循环变量参与运算后,自加 1*/
i++;
}
/*运算 100次后,打印最后结果
sum值 */
printf(“1+2+3+… +100=%d”,sum);
}
循环结构的术语
循环条件
循环体
循环控制变量循环条件是循环结构中的测试表达式。
如源程序中的
while(i<=100)。
循环体是在每个循环周期均要执行一次的语句序列。
如源程序中 while
语句下面用花括号括起来的复合语句。
循环控制变量是在循环条件中控制条件是真是假的变量。
如源程序中的变量 i。
要写出一个正确的循环结构,对控制变量要做三方面工作:一是控制变量赋初值;二是把控制变量写入正确的循环条件;三是控制变量的更新、调整。
例 求自然数 1到 5的平方和。
#include<stdio.h>
main()
{
int i,s ;
s=0;
i=1;
while(i<6)
{s=s+i*i;
i++;
}
printf(“1*1+2*2+…+5*5=%d”,s);
}
4.3.2 do while语句
do
循环体语句;
while(表达式 );
表达式循环体真假
do while语句的工作过程是:
首先执行一次 do下面的循环体语句,然后计算测试表达式,如果表达式的值为真,则返回 do语句处,
继续执行循环体,如此反复,直到表达式的值为假,
退出 do和 while构成的循环结构,执行 do while语句下面的语句。
从流程图可以看出:不管开始的时侯测试条件是真是假,do while语句的循环体都要执行一次,因为循环体是先于测试条件执行的。这是 do while循环与
while循环的主要区别。因此,do while循环常用在需要至少执行一次循环体的地方。
现在我们来看一个 do while循环的例子。
这是一个猜数游戏。程序借助 do while结构,可以让你探索出隐藏在程序中的一个“神秘数字”。
#include <stdio.h>
#define GOAL 39
main( )
{int date,count=0;
do
{printf(“Please input an integer:”);
scanf(“%d”,&data);
if(date>GOAL) printf(“%d too big,please try again!\n”,date);
else if(data<GOAL) printf (“%d too big,please try again!\n”,date);
elselse printf(“You get it!\n”);
count++;
}while(data!=GOAL);
printf(,You need %d times when you get it!\n”,count);
}
4.3.3 for语句我们前面已经说明,要正确表达循环结构应注意三方面的问题:控制变量的初始化、循环条件和控制变量的更新。
for语句在书写形式上正好体现了这种紧密的逻辑关系。
for(表达式 1;表达式 2;表达式 3)
循环体语句;
for语句的工作过程是:
首先计算表达式 1,然后计算表达式 2,如果表达式 2的值为真,则执行循环体;否则,退出 for循环,
执行 for循环下面的语句。如果执行了循环体,则循环体执行完后,
将计算表达式 3,然后重新计算表达式 2。如此反复,直至表达式 2
的值为假,退出循环。
表达式 2
循环体真假表达式 1
表达式 3
例:求自然数 1到 5的平方和。
#include <stdio.h>
main()
{
int i,s;
s=0;
for(i=1;i<6;i++)
s=s+i*i;
printf(“1*1+2*2+… +5*5=%d”,s);
}
4.3.4 while,do while,for语句的选择一、如果循环次数在执行循环体之前就已确定,
一般用 for语句;如果循环次数是根据循环体的执行情况确定的,一般用 while语句或者 do while语句。
/*循环次数已确定 */
for(i=0;i<10;i++)
printf(“*”);
char c;
/*循环次数不确定 */
/*只有当用户输入了字符’ h?
才结束循环 */
do
{/*等待用户输入一个字符 */
c=getchar();printf(“%c”,c);
}while(c!=?h’ )
同一个问题,可以用 while语句来解决,也可用 do while语句或者 for语句来解决。但在实际应用中,我们要根据具体情况来选用不同的循环语句。选用的一般原则如下:
二、当循环体至少执行一次时,用 do while 语句;
反之,如果循环体可能一次也不执行时,用
while语句。
char c;
/*循环体至少执行一次 */
/*用户输入的每个字符都被打印 */
do
{/*等待用户输入一个字符 */
c=getchar();
printf(“%c”,c);
}while(c!=?h?);
char c;
c=getchar();
/*循环体可能一次也不执行 */
/*只有不是 ‘ h’ 的字符才被打印 */
while(c!=?h?)
{printf(,%c”,c);
/*等待用户输入一个字符 */
c=getchar();
}
4.3.5 循环嵌套例:在屏幕上打印一个 8行 7列的星号矩形
#include<stdio.h>
main()
{
int i;
/*打印第 1行星号 */
for(i=0;i<7;i++);
printf(“*”);
printf(“\n”);/*换行 */
/*打印第 2行星号 */
for(i=0;i<7;i++);
printf(“*”);
printf(“\n”);/*换行 */..
.
/*打印第 8行星号 */
for(i=0;i<7;i++)
printf(“*”);
printf(“\n”);/*换行 */
}
*******
*******
*******
*******
*******
*******
*******
*******
一个循环的循环体中套有另一个循环叫循环嵌套。这种嵌套过程可以一直重复下去。
一个循环外面仅包围一层循环称二重循环一个循环外面包围两层循环称为三重循环一个循环外面包围多层循环称为多重循环前几节所学的三种循环结构,while,do
while,for可以互相嵌套自由组合。
什么是循环嵌套?
#include<stdio.h>
/*打印 8行 7列星号矩形 */
main()
{
int i,k;
/*外循环控制星号矩形的行 */
for(i=0;i<8;i++)
{/*内循环打印每一行的 7个星号 */
for(k=0;k<7;k++)
printf(“*”);
printf(“\n”);/*换行 */
}
}
把上页程序中的,k<7” 改成,k<=i”,
就可以打印星号三角形。
#include<stdio.h>
/*打印星号三角形 */
main()
{
int i,k;
/*外循环控制星号三角形的行 */
for(i=0;i<8;i++)
{/*内循环控制星号三角形的列
*/
for(k=0;k<=i;k++)
printf(“*”);
printf(“\n”);/*换行 */
}
}
*
**
***
****
*****
******
*******
********
循环的辅助语句有时,我们需要在循环体中提前跳出循环,或者在满足某种条件下,不执行循环体中的所有语句而提前开始下一轮循环。
这时候我们就要用到两个循环的辅助语句:
break语句和 continue语句。
/*使用 break语句的例子 */
#include <stdio.h>
#define PI 3.14159
/*打印半径为 1到 10的圆的面积,如果面积超过 100,则不予打印。 */
main()
{int r;float area;
for(i=1;r<=10;r++)
{area=PI*r*r;
if(area>100.0)
break;
printf(面积等于 %f\n”,area);
}
printf(,现在 r=%d\n”,r);
}
/*使用 continue语句的例子 */
#include <stdio.h>
/*计算用户输入的所有正数的和,用户输入 0时结束 */
main()
{float f,s;
s=0;
do
{scanf(“%f”,&f);
if(f<0)
continue;
s=s+f;
}while(f!=0.0);
}
break语句在学习 switch结构时,我们就接触过 break语句,那时它使程序跳出 switch结构。在循环结构中,break语句可以使程序提前跳出循环体,
结束循环。
如果在嵌套循环中使用了 break语句,它只影响包含它的最内层循环。
continue语句
continue语句只能用在循环结构中。一旦执行了 continue语句,程序就跳过循环体中位于该语句的所有语句,提前结束本次循环周期并开始下一个循环周期。
同 break语句一样,如果 continue语句用在嵌套循环中,那么它只影响包含它的最内层循环。