当前位置:首页 >> 高中教育 >>

c程序设计谭浩强第四版


课程目的
§熟记C语言的基本概念 §熟悉Turbo C、Visual C++的上机操作环境 §会读、会编、会调试C程序

学习要点
熟记C语言的语法 学会算法分析与算法设计

C语言程序设计

第一章 C语言概述

第1章 C语言概述
C语言发展历史 C语言的特点

/>
简单的C程序介绍
C程序的上机步骤

C语言程序设计

第一章 C语言概述

? C语言发展过程
?产生背景
? 1960 ALGOL 60→1963 CPL语言→1967 BCPL→1970 Ken Thompson B语言,写UNIX系统

?产生过程
? 时间:1972~1973 ? 地点:美国贝尔实验室 ? 目的:UNIX操作系统 ? 设计人: Ken.Thompson和Dennis.M.Ritchie

?C标准
? 标准C: 1978年 K&R合著《The C Programming Language》 ? ANSI C: 1983年 ? 87 ANSI C: 1987年 ? 1990年国际标准的ANSI C ,1994年再次修订。

?C版本 ? Microsoft C 或称 MS-C ? Turbo C 或称 TC

<

>

C语言程序设计

第一章 C语言概述

C语言简洁、紧凑,使用方便、灵活。 ANSI C一共只有32个关键字,见365页 附录B 32个关键字:(由系统定义,不能重作其它定义) auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef unsigned union void volatile while
Turbo C扩充了11个关键字: asm _cs _ds _es _ss cdecl far huge interrupt near pascal 注意:在C语言中,关键字都是小写的。
<

C语言程序设计

第一章 C语言概述

C语言有 9 种控制语 句,程序书写形式自 由,主要用小写字母 表示,压缩了一切不 必要的成分。

9种控制语句: if( )~else~ for( )~ while( )~ do~while( ) continue break switch goto return

<

C语言程序设计

第一章 C语言概述

C语言运算符丰富(附录C)
34种运算符: 算术运算符:+ - * / % ++ -关系运算符:< <= == > >= != 逻辑运算符:! && || 位运算符 :<< >> ~ | ^ & 赋值运算符:= 及其扩展 条件运算符:?: 逗号运算符:, 指针运算符:* & 求字节数 :sizeof 强制类型转换:(类型) 分量运算符:. -> 下标运算符:[] 其它 :( ) <
注意:各种运算符混合使用,其优先级与结 合方法是难点,可先预习。

C语言程序设计

第一章 C语言概述

C语言数据结构丰富
数值类型 基本类型 字符类型char

短整型short
整 型 整型int 长整型long 单精度型float 浮点型 双精度型double

数组
C 数 据 类 型 结构体struct 构造类型 共用体union

枚举类型enum
指针类型 空类型void

<

定义类型typedef

C语言程序设计

第一章 C语言概述

§1.3 简单的C程序介绍
例1.1 第一个程序Hello Word!. /* example1.1 The first C Program*/ #include <stdio.h> 编译预处理 void main() 主函数 { printf(“Hello Word!.\n”); } 输出: This is a c program. 注释

语句

printf语句中的“\n‖是换行


<

>

C语言程序设计

第一章 C语言概述

例1.2 求 俩 个 数 的 和

/* example1.1 calculate the sum of a and b*/ #include <stdio.h> 预处理命令 /* This is the main program */ void main() 注释 { int a,b,sum; /*定义变量*/ 函数 a=10; b=24; 语句 sum=add(a,b); printf(”sum= %d\n",sum); } printf语句中的“ %d ‖是表
示“十进制整数类型”

<

>

/* This function calculates the sum of x and y */ int add(int x,int y) { int z; z=x+y; 运行结果: return(z); sum=34 }

C语言程序设计

第一章 C语言概述

例1.3 从键盘输入两个整数,输出其中较大的数 #include <stdio.h> 声明部分,定义变量 void main() 输入:10,20 ? { int max(int x,int y) 输出:max = 20 int a,b,c; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(" max = %d",c); scanf语句中“&a‖的含 } 义是“取地址” int max(int x,int y) { int z; 调用 max 函数,返回值赋给 定义 max 子函数,函数值 c if(x>y) z=x; 、形参x、y为整型 else z=y; return(z); } 通过max函数将z值带回调用处 <

>

C语言程序设计

第一章 C语言概述

?C语言格式特点
?习惯用小写字母,大小写敏感 )) main( ?不使用行号,无程序行概念 main( { { ………………. ?可使用空行和空格 int i , j , sum; ……………… ?常用锯齿形书写格式 sum=0; ………….. for(i=1; i<10;i++) ………….. { 优秀程序员的素质之一: ……… for(j=1;j<10;j++) ? 使用TAB缩进 ………. { …………… ? {}对齐 sum+=i*j ; ? 有足够的注释 ……………. } ? 有合适的空行 ………………. } ……………….. } printf(―%d\n‖,sum); } < >

C语言程序设计

第一章 C语言概述

§1.4 C程序的上机步骤
?C程序开发步骤
开 始
编 辑 源程序 file.c 编 译

编辑 编译 链接 执行

程序代码的录入, 生成源程序*.c 语法分析查错,翻译 生成目标程序*.obj

有 有错? 无 可执 行 目标 程 序 连 接

目标程 序 file.obj

与其它目标程序或库 链接装配,生成可执行 程序*.exe

库函数和 执 行 其它目标 程序

file.exe

不正确 结果正确? 正确 结 束

<

>

源程序 目标程序 可执行程序 内容 程序设计语言 机器语言 机器语言 可执行 不可以 不可以 可以 文件名后缀 .c或.cpp .obj .exe

C程序设计

第一章 C语言概述

?Visual C++实现C程序 1)启动

<

>

C程序设计

第一章 C语言概述

2)文件编辑与保存

<

>

C程序设计

第一章 C语言概述

3)编译与链接

<

>

C程序设计

第一章 C语言概述

4)运行

<

>

C程序设计

第一章 C语言概述

本章小结
通过本章的学习,应对计算机语言及程序设计的概念,C 程序的组成特点,C程序的运行过程有一个初步了解。
学习C语言程序设计,掌握C语言语法规则和程序设计方 法,培养编程技能是很重要的。C语言相对其它高级语言来 说要相对难一些,但只要认真对待,学习程序设计好的方法 就是在掌握语法规则的基础上,多分析阅读别人写的程序, 多自己动手编写一些小程序,多上机调试运行程序,做到这3 个“多”字,学习好C程序设计就不难了。
< >

C语言程序设计

第二章 程序的灵魂——算法

§2.算法
?流程图表示
?用流程图符号构成,直观,易懂

? N-S流程图表示

<

>

C语言程序设计

第二章 程序的灵魂——算法

传统流程图流向混乱、可读性差,所以应该 采用结构化流程图。
?结构化程序设计
? 基本思想:任何程序都可以用三种基本结构表示, 限制使用无条件转移语句(goto) ? 结构化程序:由三种基本结构反复嵌套构成的程序 ? 优点:结构清晰,易读,提高程序设计质量和效率

?三种基本结构
? 顺序结构
A B A B N-S图

流程图

<

>

C语言程序设计

第二章 程序的灵魂——算法

?选择结构 ?二分支选择结构

真 A

P

假 真 B

P



A

B

k k=k1 k=k2 A2 ...

k=kn k=ki Ai ... An

?多分支选择结构

A1

<

>

C语言程序设计

第二章 程序的灵魂——算法

?循环结构

?当型循环结构

P 真 A



当P为真 A

?直到型循环结构
A 假 P 真 A 直到P为真

<

>

注:A,B,A1….An可以是一个简 单语句,也可以是一个基本结构

C语言程序设计

第二章 程序的灵魂——算法

三种基本结构的共同特点:
?只有一个入口; ?只有一个出口; ?结构内的每一部分都有机会被执行到; ?结构内不存在?死循环?。

<

>

C语言程序设计

第二章 程序的灵魂——算法

§2.5 结构化程序设计方法
?结构化程序:用三种基本结构组成的程序 ?基本设计思路:
?复杂问题分解成 几个最基本问题,再分别处理。

?采用的方法:
?自顶向下; ?逐步细化; ?模块化设计:复杂问题按功能分成多个子模块 ?结构化编码:正确采用三种基本结构实现

<

>

C程序设计

第二章 程序的灵魂:算法

本章小结
本章的内容是十分重要的,是学习后面各章的基础。学 习程序设计的目的不只是学习一门特定的语言,而是学习进 行程序设计的方法。掌握了算法就是掌握了程序设计的灵魂 ,再学习有关的计算机语言知识,就能够顺利编写任何一种 语言的程序。关键是算法。有了正确的算法,用任何语言进 行编码都不应该有什么困难。 在本章中只是初步介绍了有关算法的基本知识,并没有

深入介绍如何设计各种类型的算法。在以后的章节中将结合 实例陆续介绍有关的算法。
< >

C语言程序设计

第三章 顺序程序设计

第3章 最简单的C程序设计—— 顺序程序设计
C数据类型、表达式 C语句

数据输入输出的概念及在C语言中的实现
字符数据的输入输出 格式输入与输出 顺序结构程序设计举例

C语言程序设计

第三章顺序程序设计

§3.1 C数据类型、表达式
C的数据类型 常量与变量 整型数据 变量赋初值 各种数值型数据间的混合运算 算术运算符和算术表达式

实型数据 字符型数据

赋值运算符和赋值表达式 逗号运算符和逗号表达式

C语言程序设计

第三章顺序程序设计

§3.1.1 C的数据类型
整 型

短整型 short 整型 int 长整型 long 单精度型 float 双精度型 double

基本类型

实 型(浮点型)
字符型 char

C 数 据 类 型

枚举类型 enum 数组类型 构造类型

结构体类型
共用体类型

指针类型

<

>

空类型 void

数据类型决定: 1. 数据占内存字节数 2. 数据取值范围 3. 可以进行的操作

C语言程序设计

第三章顺序程序设计

§3.1.2 常量与变量
?常量和符号常量
?定义:程序运行过程中,其值不能被改变的量(常数) ?分类:直接常量、符号常量 类型 整型常量 示例

12 、 0 、 -3

实型常量
字符常量 符号常量

4.6 、 -1.23
?a‘ 、 ‘b‘ PRICE 、 PAI

<

>

C语言程序设计

第三章顺序程序设计

?符号常量:用标识符代表常量 ?一般用大写字母: PRICE 、 PI

?定义格式:

#define

符号常量

常量

?其值在作用域内不能改变和再赋值。 例3.1 符号常量举例 运行结果: #define PRICE 30 total=300 #include <stdio.h> void main() { 符号常量的优点是: int num,total; 见名知意、一改全 num=10; 改 total=num*PRICE; printf("total=%d\n",total); }

<

>

C语言程序设计

第三章顺序程序设计

?变量
? 定义:其值可以改变的量。 ? 定义格式:数据类型 变量名; ? 变量应该有名字,并在内存中占据一定的存储单元。 ? 变量名和变量值有不同的含义
? 变量名实为一个符号地址

<

>

例 变量的使用 main() { int a; a=3; printf(―a=%d",a); }

a

变量名

3

变量值
存储单元

C语言程序设计

第三章顺序程序设计

?标识符
?定义:标识变量名、符号常量名、函数名、数组名、 文件名的字符串序列——名字。 ?命名规则: ?只能由字母、数字、下划线组成,且第一个字 这些标识符合法吗? 符必须是字母或下划线 1A 、M.D.John、¥123、#33、 ? 大小写字母含义不同,一般用小写 Tatol、int、max ?不能使用关键字 ?TC允许最长32个字符,建议长度不超过8个字符 ?使用:先定义、后使用
标识符应该“见名知意”,如 total , max 标识符应该“不宜混淆”,如 l与1 , O与0

<

>

C语言程序设计

第三章顺序程序设计

§3.1.3 整型数据
?整型常量(整常数)的三种表示方法 ?十进制整数:由数字0~9和正负号表示.
如 123,-456,0

?八进制整数:由数字0开头,后跟数字0~7表示.
如 0123,011

?十六进制整数:由0x开头,后跟0~9,a~f,A~F表示.
如 0x123,0xff

<

>

C语言程序设计

第三章顺序程序设计

§ 补充知识:
?字节和位
7 6 5 4 3 2 1 0

?内存以字节为单元组成 ?每个字节有一个地址 ?一个字节一般由8个二进制位 组成 ?每个二进位的值是0或1
7 6 5 4 3 2 1

0 1 2 3 4 5 6 7 8 9 10 ……...

<

>

C语言程序设计

第三章顺序程序设计

?数值的表示方法——原码、反码和补码
?原码:最高位为符号位,其余各位为数值本身的绝对值 ?反码:
? 正数:反码与原码相同 ? 负数:符号位为1,其余位对原码取反

?补码:
? 正数:原码、反码、补码相同 ? 负数:最高位为1,其余位为原码取反,再对整个数加1 12 1 11 10 2 3 8 4 7 9-5=4 9+7=16=(14)12

9

<

>

6

5

C语言程序设计

第三章顺序程序设计

(用一字节表示数) 原码 反码 补码

+7
-7 +0

00000111
10000111 00000000

00000111
11111000 00000000

00000111
11111001 00000000

-0
数的范围

10000000 01111111~ 11111111 (-127~+127)

11111111
01111111~ 10000000 (-127~+127)

00000000
01111111~ 10000000 (-128~+127)

?负数补码转换成十进制数:最高位不动,其余位取反加1
例 补码:11111001 取反:10000110 加1: 10000111=-7

<

>

C语言程序设计

第三章顺序程序设计

?整型变量
?整型数据在内存中的存放形式
? 数据在内存中以二进制补码形式存放 ? 每一个整型变量在内存中占2个字节

10的原码 反码 补码 -10的原码 取绝对值 反码 补码

00 00 00 00 00 00 10 00 00 00 11 11 11 11

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 11 11 11 11 11

00 10 10 00 10 10 00 10 10 00 10 10 00 10 10 11 01 01 11 01 10

<

>

整数的最左二进 制位是符号位, 0正、1负

C语言程序设计

第三章顺序程序设计

?整型变量的分类
? 三类整型变量 有符号 无符号

基本型(简称整型) 短整型 长整型
? 整数类型和取值范围 TURBO C int short long unsigned int unsigned short unsigned long

int short或short int long或long int

unsigned int unsigned short unsigned long

<

>

所占位数 最小取值范围 -32768~+32767 16 16 --32768~+32767 2147483648~+21474836 32 47 0~65535 16 0~65535 16 0~4294967295 32

C语言程序设计

第三章顺序程序设计

?整型变量的定义
? 先定义后使用——强制类型定义 int a,b; ( 指定变量a、b为整型 ) 定义放在函数开 unsigned short c, d; (指定变量c、d为无符号短整型 ) 头的声明部分 指定abcd为整型变量 long e,f; ( 指定变量e、f为长整型)
00 00

int 型 00 00 例 00 00 整型变量的定义与使用 11 01 3.2

符号位

00 00
00 00 00 00 00 00

short 00 00 #include 00 00 11<stdio.h> 01



指定u为无符号整型变量
00 11 01

main() 00 00 void 00 00 00 00
00 00 00 00

作用域 00 00 00

结果:
a+u=22,b+u= -14 < >

{int a,b,c,d; 00 11 01 unsigned int 型 定义与赋值同时进行: unsigned u ; 00 00 00 11 01 unsigned int 型 a=12;b=-24;u=10; int a=12; 00 00 00 00 00 00 00 00 00 00 00 11 01 c=a+u;d=b+u; unsigned long 型 printf(―a+u=%d,b+u=%d\n",c,d); }
不同类型混合运算, 类型自动转换

00 00

00 00 00

long 型

C语言程序设计

第三章顺序程序设计

?整型数据的溢出 整型变量最大值32767 加1后是 –32768的补码形式
01 11 10 00 11 11 11 11 11 11 00 00 00 00 00 00

例3.3 整型数据的溢出 改为:long b; #include <stdio.h> void main( ) 结果是什么? { int a , b; 运行结果: a= 32767; 32767 , -32768 b= a+1; printf("%d , %d \n ",a,b); } < >

? 此情况称为?溢出?,运行时不报错,编程时要注 意

C语言程序设计

第三章顺序程序设计

?整型常量的类型
?整型常量的值在-32768~+32767范围内,编译器认 为是int类型 ?整型常量的值超过上述范围,而在-2147483648 ~ +2147483647范围内,编译器认为是long类型 ?当系统定义short int与int占内存长度相同,则 两种类型常量均可以赋给 int和short int型变量 ?在整型常量后面加大写L或小写l,则告诉编译器, 把该整型常量作为long类型处理。例:123L、0L ?在整型常量后面加u,则按无符号整型方式存放, 负数转换成补码再按无符号整型方式存放。

<

>

C语言程序设计

第三章顺序程序设计

§3.1.4 浮点型数据
?浮点型常量的表示方法
?浮点数(float)又称为实数(real) ?两种表示方法: ?十进制小数形式:必须有小数点 如 0.123 、.123 、123.0 、0.0 、123. ? 指数形式:e或E之前后必须有数字;指数必须为整数

如 123.456e0、12.3456e1 、1.23456e2 、
0.123456e3 、0.0123456e4 等

?规范化指数形式
< > ?是指数的输出形式

6.28e-2 表示

6.28× 10 -2

?只有一位非零整数的指数形式
-3.0824e4 表示 –3.0824× 10 4

C语言程序设计

第三顺序程序设计

?浮点型变量
?浮点型数据在内存中的存放形式
? 浮点型数据在内存中占4个字节(32位) ? 在内存中分成3部分,指数为2的幂次
+ .314159 1

数符

小数部分

指数

?浮点型变量的分类
类 型 位数 32位 64位 128位 有效数字 单精度 float 双精度 double 型 长双精度long double型

6~7
15~16 18~19

<

>

float x,y; double z; long double t;

(指定x、y为单精度浮点型变量) (指定z为双精度浮点型变量) (指定t为长双精度浮点型变量)

C语言程序设计

第三章顺序程序设计

?浮点型数据的舍入误差
? 数据超过有效位数,则产生误差 ? 要避免一个很大的数与一个很小的数加减

例3.4 浮点型数据的舍入误差 #include <stdio.h> void main( ) { float a , b; a= 123456.789e5; b= a+20; printf("%f \n",b); }

运行结果: 12345678848.000000

舍入误差使1.0/3*3 的 结果并不等于1 !

?浮点型常量的类型
< >
? 浮点型常量一般按双精度64位处理,数后加F或f按单精度 ? 浮点型常量不分float和double

C语言程序设计

第三章顺序程序设计

§3.1.5 字符型数据
?字符常量
?定义:用单引号括起来的单个字符或转义字符 如 ‘a? ?A? ?\n? ?\t ?

?字符常量的值:该字符的ASCII码值 如 ‘a‘——97 ,‘A‘——65 ?\n‘——10, ?\t‘——9 ?定义格式:char 变量名 = 值 char ch=65 与 char ch=‘A‘ 与char=?\101‘是等效的 ?转义字符:反斜线后面跟一个字符或一个代码值表示

<

>

C语言程序设计

第三章顺序程序设计

表1 转义字符及其含义
转义字符 \n 含义 换行 垂直制表 转义字符 \t \b \f \\ \― \xhh 含义 水平制表(右移8格) 退格 换页 反斜线 双引号 2位16进制数代表的字符 显示结果: f h gde jk

\v
\r \a \? \ddd

<

回车(不换行) 响铃 单引号 3位8进制数代表的字符

打印结果: fab h gde jik

<

>

例3.5 转义字符的使用 #include <stdio.h> void main( ) { printf(― ab c\t de\rf\tg\n‖); printf(―h\ti\b\bj k‖); }

C语言程序设计

第三章顺序程序设计

?字符变量
?存放字符常量,占用一个字节,存放一个字符 ?定义形式: 赋值: char c1,c2; c1=?a‘;c2=?b‘;

?字符数据在内存中的存储形式及其使用方法
?以二进制存放字符的ASCII码值(0~255整数) ?与整数的存储形式类似 例3.6 向字符变量赋整数 ?以字符或整数形式输出 #include <stdio.h> void main( ) 输出形式取决于printf函数中的格式符 { char c1,c2 ; c1=97 ; 格式符为“%c‖时输出的变量值为字 c2=98 ; 符 printf(―%c %c \n",c1,c2); 格式符为“%d"时输出的变量值为整 a b 运行结果: printf(―%d %d \n",c1,c2); 数 97 98 < > }

C语言程序设计

第三章顺序程序设计

?对字符数据进行算术运算
? 实质是对其ASCII值进行算术运算

例3.7 大小写字母的转换 #include <stdio.h> void main( ) {char c1,c2 ; c1=?a‘ ; c2=?b‘ ; c1=c1-32; c2=c2-32; printf(―%c %c ",c1,c2); } 运行结果: A < >

?字符型与整型间互相赋值
小写字母比大写字母的 例: 互相赋值 码大(32) ASCII 10 #include <stdio.h>

B

void main( ) {int c1; char c2 ; c1=?a‘ ; c2=98 ; c1=c1-32; c2=c2-32; printf(―%c %c ",c1,c2); }

C语言程序设计

第三章顺序程序设计

?字符串常量
?定义:用双引号(― ‖)括起来的字符序列
?How do you do‖ , ―CHINA‖ , ―a‖ , ―$123.45‖

?存储:每个字符串尾自动加一个 ‘\0’ 作为字 符串结束标志 例 字符串“hello‖在内存中 h e l l o \0
例 空串 “”

\0

?字符常量与字符串常量不同
例 ‘a‘ a

―a‖

a没有字符串变量, \0 只能用字符数组存放

例:
< >

char ch; ch=?A‘; ch=―A‖;

C语言程序设计

第三章顺序程序设计

§3.1.6 变量赋初值
?变量的使用:先定义,后使用 ?变量定义位臵:一般放在函数开头 ?变量初始化:可以在定义时赋初值

错!int a=b=c=3 int a=1, b=-3,c; 例: int a=1,b= -3,c; 地址 float data=3.67; 1 2字节 a char ch=?A‘; 地址 int x=1,y=1,z=1; b 2字节 -3 int x=y=1;(× )
…... 地址 编译程序根据变量定义为其 分配指定字节的内存单元

c

??
…...

2字节

<

>

内存

随机数

C语言程序设计

第三章顺序程序设计

§3.1.7 各类数值型数据间的混合运算
?整型、实型、字符型数据间可以混合运算

?自动转换
?什么情况下发生
? 运算转换------不同类型数据混合运算时 ? 赋值转换------把一个值赋给与其类型不同的变量时 ? 输出转换------输出时转换成指定的输出格式 ? 函数调用转换------实参与形参类型不一致时转换

?运算转换规则:不同类型数据运算时先自动转换 成同一类型

<

>

C语言程序设计

第三章顺序程序设计



double

float

说明: 必定的转换

long
unsigned int ch/i int int char,short

运算对象类型不同时转换

低 例 char ch; int i; float f; double d;

例 int i; float f; double d; long l;
10+?a‘ +i*f int int d/l

+ f*d - (f+i) double double double double

double double double double

double

double double

<

>

double

C语言程序设计

第三章顺序程序设计

?强制转换(见P56强制类型转换运算符部分)
?一般形式:(类型名)(表达式) 例3.8 例:(int)(x+y) 表达式仅一个 #include <stdio> (int)x+y 变量时,括号 main() 可以省略 强制类型转 (double)(3/2) { float x; 换运算符 (int)3.6 int i; ?说明:强制转换得到 x=3.6; 所需类型的中间变量, i=(int)x; printf(―x=%f,i=%d‖,x,i); 原变量类型不变 } 结果:x=3.600000,i=3 精度损失问题 < >
较高类型向较低类型转换时可能发生

C语言程序设计

第三章顺序程序设计

§3.1.8 算术运算符和算术表达式
算术运算符:(+ - * / % ++ --) 关系运算符:(< <= == > >= !=) 逻辑运算符:((! && ||) 位运算符 :(<< >> ~ | ^ &) 赋值运算符:(= 及其扩展) 条件运算符:(?:) ?学习运算符应注意: 逗号运算符:(,) ?运算符功能 指针运算符:(* &) 求字节数 :(sizeof) ?与运算量关系 ? 要求运算量个数 强制类型转换:(类型) ? 要求运算量类型 分量运算符:(. ->) 下标运算符:([]) ?运算符优先级别 其它 :(( ) -) ?结合方向 ?结果的类型

C 运 算 符

<

>

C语言程序设计

第三章顺序程序设计

?算术运算符和算术表达式
?基本算术运算符: + - * / %
? 结合方向:从左向右 ? 优先级: - ---->* / % -----> + (2) (3) (4)

说明:
? ?-?可为单目运算符时,右结合性 ? 两整数相除,结果为整数 ? %要求两侧均为整型数据 ? + - * / 运算的两个数中有一个数为实数, 结果是double型

例 例

5/2 5/2 = =2 -5/2.0 -5/2.0 ==-2.5

例 例

<

>

5%2 5%2 -5%2 -5%2 1%10 1%10 5%1 5%1 5.5%2 5.5%2

=1 = = -1 = = 1 = = 0 = ( ?)

C语言程序设计

第三章顺序程序设计

?自增、自减运算符++ --
? 作用:使变量值加1或减1 ? 种类: ?前臵 ++i, --i (先执行i+1或i-1,再使用i值) ?后臵 i++,i-(先使用i值,再执行i+1或i-1)



j=3; k=++j; j=3; k=j++; j=3; printf(―%d‖,++j); j=3; printf(―%d‖,j++); a=3;b=5;c=(++a)*b; a=3;b=5;c=(a++)*b;

//k=4,j=4 //k=3,j=4 //4,j=4 //3,j=4 //c=20,a=4 //c=15,a=4

<

>

C语言程序设计

第三章顺序程序设计

? 几点说明:

?++ -- 不能用于常量和表达式,如 5++,(a+b)++ ?++ -- 结合方向: 自右向左 ?优先级:- ++ -- ------>* / % ----->+ (2) (3) (4) ?该运算符常用于循环语句中,使循环变量加减1

例 -i++ i=3;

?

-(i++)

printf(―%d‖,-i++); //-3

?有关表达式使用中的问题说明
? 不同系统对运算符和表达式的处理次序不同,尽可能 写通用性强的语句 ? 不要写有歧义和不知系统如何执行的程序

<

>

C语言程序设计

第三章顺序程序设计

§3.1.9 赋值运算符和赋值表达式
?简单赋值运算符
? 符号: = ? 格式: 变量标识符=表达式 ? 作用:将一个数据(常量或表达式)赋给一个变量 ? 左侧必须是变量,不能是常量或表达式

例 a=3; 例 3=x-2*y; ?类型转换

d=func();

c=d+2;

a+b=3; (×)

? 赋值转换规则:使赋值号右边表达式值自动转换成其 左边变量的类型 例 float f ; int i=10; f=i; 则 f=10.0

<

>

例 int i; i=2.56;

//结果i=2;

?复合赋值运算符
? 种类:+= -= *= /= %= 《= 》= &= ^= |= ? 含义: exp1 op= exp2 ? exp1 = exp1 op exp2

a+=3

a=a+3

x*=y+8
x%=3

x=x*(y+8)
x=x%3

C语言程序设计

第三章顺序程序设计

?赋值表达式
? 形式:<变量> <赋值运算符> <表达式> ? 赋值表达式的值与变量值相等,且可嵌套

例:

a=b=c=5 //表达式值为5,a,b,c值为5 a=(b=5) // b=5;a=5 //表达式值11,c=6,a=11 a=5+(c=6) a=(b=4)+(c=6) //表达式值10,a=10,b=4,c=6 a=(b=10)/(c=2) //表达式值5,a=5,b=10,c=2

<

>

C语言程序设计

第三章顺序程序设计

§3.1.10 逗号运算符和逗号表达式
?形式:表达式1,表达式2,……表达式n ?结合性:从左向右 ?优先级: 15,级别最低 ?逗号表达式的值:等于表达式n的值 ?用途:常用于循环for语句中 //a=15,表达式值60 例 a=3*5,a*4 //a=15,表达式值20 a=3*5,a*4,a+5 例 x=(a=3,6*3) //赋值表达式,表达式值18,x=18 x=a=3,6*a //逗号表达式,表达式值18,x=3 例 a=1;b=2;c=3; //1,2,3 printf(―%d,%d,%d‖,a,b,c); printf(―%d,%d,%d‖,(a,b,c),b,c); //3,2,3 < >

C语言程序设计

第三章顺序程序设计

例: 逗号表达式使用 main() { int x,y=7; float z=4; x=(y=y+6,y/z); printf("x=%d\n",x); }

运行结果: X=3

本章的内容散乱而复杂,但却是 程序设计的基础,要认真看书,通过 编程序才可以深入理解。

<

>

C语言程序设计

第三章 顺序程序设计

§3.2 C语句
? C程序结构:
?一个C程序可以由多个源程序文件构成 ?一个源程序文件由若干函数、预编译命令及全局变量声明部 分构成 ?函数包括数据定义部分和执行部分,执行部分是C语言语句, 完成对数据的操作
C程序

源程序文件1

源程序文件2

源程序文件n

预处理命令

全局变量声明

函数1

函数n

函数首部

函数体

<

>

局部变量声明

执行语句

C语言程序设计

第三章 顺序程序设计

§3.2.1 语句的作用和分类
?C语句分为5类
?控制语句:共9种
? 完成一定的控制功能,这些语句能够根据一定的测试条件 决定某些语句是否被执行,如分支、循环、跳转等语句。

if( )~else~ for( )~ while( )~ do~while( ) continue switch break goto return < >

(条件语句) (循环语句) (结束本次循环语句) (多分支选择语句) (终止switch或循环语句) (转向语句) (从函数返回语句)

C语言程序设计

第三章 顺序程序设计

? 函数调用语句:由函数加? ; ‖组 成 printf(―This is a C program‖);

? 表达式语句:由表达式加? ; ‖组成
? 典型的是赋值语句,由赋值表达式加分号构成,如:y=x+1 是表达式,而y=x+1;则是赋值语句。实际上函数调用语句也 属于表达式语句。

a=3 ; i++ ;
? 空语句:只有一个? ; ‖,什么也不做 for(i=0;i<100;i++) { ; }

<

>

C语言程序设计

第三章 顺序程序设计

?复合语句:
? 用 {…}括起来的一组语句,也称作程序块。 ? 一般形式:

int i=0,sum=0; while(i<=100) { sum=sum+i; i=i+1; }
? 说明 ?复合语句? } ‖后不加分号 ?语法上和其它语句相同 ?复合语句可嵌套

<

>

C语言程序设计

第三章 顺序程序设计

§3.2.2 赋值语句
?基本格式:
赋值表达式 + ; ? 赋值表达式可以包含在其它表达式中,而赋值语句不 可以。

例:if ((a=b)>0) t=a; 不可写为:if ((a=b;)>0) t=a;

<

>

C语言程序设计

第三章 顺序程序设计

表达式中允许出现运算符号、变量、数值、函数
序号 1 2 3 语句 a=5 S=pi*r*r average=(a+b)/2 x=l*cos(q) i=0x30+255 ch=ch- ?A‘ m=a[1]+a[2] x=*px++ 求圆面积 求平均数 求横坐标 含义 常量 变量、乘号 变量、常数、括号 变量、函数 右侧表达式包括

4 5
6 7 8

十进制、十六进制
变量、字符常量 数组变量 指针变量、增1运算

<

>

C语言程序设计

第三章 顺序程序设计

?另一种形式的赋值语句 <变量><运算符> = <表达式>;
我们可以理解为:

<变量>=<变量><运算符><表达式>;
示例 a+ = 表达式 a - = 表达式

含义
a= a + (表达式) a= a - (表达式)

a * = 表达式
a / = 表达式 a % = 表达式

a= a * (表达式)
a= a / (表达式) a= a %(表达式)

<

>

只适合于 整型变量

C语言程序设计

第三章 顺序程序设计

?连续赋值语句
int a , b , c ; a=b=c=1 ;
int a=b=c=1 ;

步骤: 连续赋值语句应“从右向左”计算
a=b=c=1 ; 等价于: a=(b=(c=1) ); 1. 把常数 1 赋给变量c,表达式(c=1) 的值为1; 2. 把表达式(c=1)赋给变量b,表达式 (b=(c=1) )的值为1; 3. 将右侧表达式的值1赋给a , a =1 。

<

>

C语言程序设计

第三章 顺序程序设计

§3.3 数据输入输出的概念及在C语言中的实现
?所谓数据的输入输出是从计算机角度出发的。 ?C语言本身没有I/O语句,所有I/O都由函数来实现。 ?C语言的标准库函数
? 由编译系统提供的一系列函数,以库形式存放在系统中,不是 常用头文件: C语言文本的组成部分。 stdio.h 定义输入输出函数 ? 库函数已编译成目标文件( .obj),在连接阶段才与源程序 编译成的目标文件相连接,生成可执行文件。 string.h 定义字符串操作函数 ? 调用形式: math.h 定义sin、cos等数学函数 函数名(参数表) Turbo C 2.0可以 ? 注意在调用C语言库函数时,需要使用编译预处理命令 不加#include命令 #include <相关的头文件>,使相应的头文件包含到用户源程 序中。

?标准输入输出函数 #include <stdio.h> < >

putchar 输出字符, scanf 格式输入,puts 输出字符串 或 #include getchar 输入字符, printf‖stdio.h‖ 格式输出,gets 输入字符串

C语言程序设计

第三章 顺序程序设计

§3.3.1 字符数据的输入输出
?putchar 函数(单字符输出函数)
格式: putchar( ?字符’); 或 putchar( 字符变量);
强调:被输出的单个字符必须被‘ ’括起 来 ?输出一个字符: /* 例 4.1 putchar(? putchar( 字符 字符变量 ’)*/) */ #include <stdio.h> 运行结果:BOY #include void main() <stdio.h> void { char main() a,b,c; { a='B'; b=?O'; c=?Y'; 结果当然还是一样的! putchar('B'); putchar(a); putchar('O'); putchar(b); putchar('Y'); } putchar(c); < > }

C语言程序设计

第三章 顺序程序设计

?输出控制字符 /* 例 putchar(?控制字符’) */ #include <stdio.h> void main() { char a,b; a=?O'; b=?k'; putchar(a); putchar(?\n‘); putchar(b); } ?输出转义字符 运行结果:AB 运行结果:O k

<

>

/*例 putchar( ) 含有转义符* / #include <stdio.h> void main() { char a; a='B'; putchar('\101'); putchar(a); }

C语言程序设计

第三章 顺序程序设计

?getchar 函数(单字符输入函数) 。
格式: getchar( ) ; 强调:输入单个字符后,必须按一次回车, 计算机才接受输入的字符。

/*例4.2 */ #include <stdio.h> void main() { char c; c=getchar( ); putchar(c); } < >

运行结果: a? a

# include <stdio.h>不能少!

C语言程序设计

第三章 顺序程序设计

§3.3.2 格式输入与输出
?printf函数(格式输出函数)
?printf函数的一般格式 格式: printf( 格式控制,输出表列);
? 格式控制:用双引号括起来的字符串,包含两种信息 ?格式说明:%[修饰符]格式字符,指定输出格式 ?普通字符:原样输出 ? 输出表列:要输出的数据,可以是变量或表达式,可以 转义字符 格式说明 输出表列 普通字符 没有,多个时以?,?分隔)

例: printf( ―%d %d‖,a,b); printf( ―a=%d b= %d\n‖,a,b); < >

C语言程序设计

第三章 顺序程序设计

/*从最简单的学起 */ #include <stdio.h> void main() { printf(―Hello World !‖ ); }

运行结果: Hello World!

调用 printf( ) 时可以省略# include 命令!

<

>

C语言程序设计

第三章 顺序程序设计

?格式字符
?d格式符:输出十进制整数,有3种用法
? %d格式:按数据实际长度输出,数据范围 -32768~32767。

/* %d 格式的 printf( ) 函数使用 */ #include <stdio.h> void main() { int a=3 , b=4; printf(―%d %d\n ‖,a,b); printf(―a=%d , b=%d\n‖,a,b); } 格式说明决定最终输出的格式

运行结果: 3 4 a=3, b=4

格式说明应与输出列表项个数相同,顺序一致

<

>

格式说明通常用小写字母表示

C语言程序设计

第三章 顺序程序设计

? %md格式:m指定输出字段的宽度 ?数据位数小于m,左端补空格,反之按实际输出。

int a=123 , b=12345 ; printf(―%4d %4d ‖, a , b);
? %ld格式:输出长整型数据 ?可以用%mld格式指定输出列宽

123 12345

long c=135790 printf(―%ld \n‖, c); printf(―%8ld ‖, c);

135790 135790

135790 > 32767 ( int 型数据的最大值)

<

>

C语言程序设计

第三章 顺序程序设计

?o格式符:八进制输出整数
? 是将内存中的二进制位整个按八进制输出,所以输出 值没有符号。 ? 可以指定输出宽度%mo,长整型可以用%lo格式输出。

?x格式符:十六进制输出整数
? 同o格式符,无符号,即无负十六进制数。 ? 可以指定输出宽度%mx ,长整型可以用%lx格式输出。

int a= -1; printf(―%d , %o , %8o , %x ‖, a , a , a , a); 输出: -1,177777,_ _177777,ffff
11 11 11 11 11 11 11 11

<

>

-1在内存的存放形式(补码)

C语言程序设计

第三章 顺序程序设计

?u格式符:十进制输出unsigned型数据
? int型可以用%u格式输出,unsigned型也可以用%d、 %o和%x格式输出。

例4.3 无符号数据的输出 #include <stdio.h> void 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 < >

C语言程序设计

第三章 顺序程序设计

?c格式符:输出一个字符
? 值在0~255的整数,可以用%c形式输出为字符

例4.4 字符数据的输出 #include <stdio.h> void main() { char c=?a‘; int i=97; printf(―%c , %d\n ‖,c,c); printf(―%c , %d\n‖ ,i ,i); }

运行结果: a , 97 a , 97

<

>

C语言程序设计

第三章 顺序程序设计

?s格式符:输出一个字符串
? 有%s,%ms,% -ms,%m.ns,% -m.ns五种用法

例4.5 字符串的输出 #include <stdio.h> void main() { printf(―%3s , %7.2s , %.4s , %-5.3d\n ‖, ―CHINA‖, ―CHINA‖, ―CHINA‖, ―CHINA‖); }
m自动=n

运行结果: CHINA , _ _ _ _ _CH , CHIN , CHI _ _ < >

C语言程序设计

第三章 顺序程序设计

?f格式符:输出实数
? %f格式:整数部分全部输出,小数6位。可以有非有 效数字输出,因为单精度有效位7位,双精度16位。 ? %m.nf格式:占m列,其中n位小数,左补空格。 ? % -m.nf格式:右补空格

例 4.6 %f格式输出实数时的有效位数 4.7 %f格式输出双精度实数时的有效位数 例4.8例%f 格式输出实数时指定小数位数 #include <stdio.h> #include <stdio.h> #include <stdio.h> main() void void main() void main() { flot x,y; double x,y; { flot{f=123.456; x=111111.111;y=222222.222; a=1111111111111.111111111; printf(―%f %10f %10.2f %.2f %-10.2f\n‖,f,f,f,f,f); printf(―%f\n‖,x+y); b=2222222222222.222222222; } } printf(―%f \n‖,x+y); 运行结果: } 123.456001_ _123.456001_ _ _ _ _ _123.46_ _123.46_ _123.46_ _ _ _ 运行结果: 333333.328125 3333333333333.333010 < >

C语言程序设计

第三章 顺序程序设计

?e格式符:指数形式输出实数
? %e格式:不指定m和n,小数6位,指数部分共5位, 其中e和指数符号各1位,指数值3位。 ? %m.ne和% -m.ne格式:m、n、-的含义同前面。 没有n时,自动=6

?g格式符:输出实数
? 可以自动根据数值大小选择 f 或 e 格式(选列少的) ? 不输出无意义的零

<

>

C语言程序设计

第三章 顺序程序设计

? 格式字符表

d x,X o u c s e,E f g,G %%

十进制整数
十六进制无符号整数 八进制无符号整数 不带符号十进制整数 单一字符 字符串 指数形式浮点小数 小数形式浮点小数 e和f中较短一种 百分号本身

int a=100;printf ( ―%d‖,a);
int a=255;printf(―%x‖,a); int a=8;printf(―%o‖,a); int a=100;printf(―%u‖,a); char a=65;printf(―%c‖,a);

100
ff 10 100 A ABC 5.677890e+002 567.789000 567.789

printf(―%s‖,―ABC‖);
float a=567.789;printf(―%e‖,a); float a=567.789;printf(―%f‖,a); float a=567.789;printf(―%g‖,a);

printf(―%%‖);

%

<

>

C语言程序设计

第三章 顺序程序设计

?scanf 函数(格式输入函数)
?一般形式 格式: scanf(格式控制,地址表列 ) ;
? 功能:按指定格式从键盘读入数据,存入地址表指定的存储

单元中,并按回车键结束

? 格式控制:含义同printf函数 ? 地址表列:变量地址或字符串地址,地址间?,?分 隔。 ? 强调:地址列表中每一项必须以取地址运算符&开头。

输入:3_4_5? 输出:3,4,5

<

>

例4.9 用scanf函数输入数据 #include <stdio.h> voidmain() { int a , b , c ; scanf(―%d%d%d‖,&a,&b,&c) ; printf(―%d, %d, %d\n‖,a,b,c) ; }

C语言程序设计

第三章 顺序程序设计

例 scanf(―%4d%2d%2d‖,&yy,&mm,&dd); 输入 19991015 ? 则 1999?yy, 10 ?mm, 15 ?dd
例 scanf(―%3d%*4d%f‖,&k,&f); 输入 12345678765.43? 则 123?k, 8765.43?f 例 scanf(―%2d? %*3d? %2d‖,&a,&b); 输入 12? 345? 67? 则 12?a, 67?b

<

>

例 scanf(―%3c%2c‖,&c1,&c2); 输入 abcde ? 则 ‘a‘?c1, ?d‘ ?c2

C语言程序设计

第三章 顺序程序设计

?输入分隔符的指定
? 一般以空格、TAB或回车键作为分隔符 ? 输入数据时,遇非法输入则认为数据结束 ? 其它字符做分隔符:格式串中两个格式符间有其它字 符,则输入时对应位臵也要有相同的字符。

例 scanf(―%d:%d:%d‖,&h,&m,&s); 输入 12:30:45? 则12 ?h, 30 ?m, 45 ?s 例 scanf(―%d%c%f‖,&a,&b,&c); 输入1234a123o.26 ? 则 1234 ?a, ?a‘ ?b, 123 ?c
< > 非法字符

C语言程序设计

第三章 顺序程序设计

§3.4 顺序结构程序举例
例4.10 输入三角形边长,求面积 #include <math.h> 文件包含预处理命令 #include <stdio.h> void main() { float a,b,c,s,area; 变量定义 scanf("%f,%f,%f",&a,&b,&c); 输入数据 s=1.0/2*(a+b+c); area=sqrt(s*(s-a)*(s-b)*(s-c)); printf("a=%7.2f, b=%7.2f, c=%7.2f, s=%7.2f\n",a,b,c,s); printf("area=%7.2f\n",area); 输出数据 } < > 输入:3,4,6 ? 输出:a= 3.00, b= area= 5.33

4.00, c=

6.00 s=

6.50

C语言程序设计

第三章 顺序程序设计

例4.11 从键盘输入大写字母,用小写字母输出
#include "stdio.h" void main() { char c1,c2; c1=getchar(); printf("%c,%d\n",c1,c1); c2=c1+32; printf("%c,%d\n",c2,c2); }

输入:A ? 输出:A,65 a,97

<

>

C语言程序设计

第三章 顺序程序设计

#include <stdio.h> #include <math.h> void main() { float a,b,c,disc,x1,x2,p,q; scanf("a=%f,b=%f,c=%f",&a,&b,&c); disc=b*b-4*a*c; p=-b/(2*a); q=sqrt(disc)/(2*a); x1=p+q; x2=p-q; printf("\n\nx1=%5.2f\nx2=%5.2f\n",x1,x2); } 输入:a=1,b=3,c=2 ? 输出:x1=-1.00 x2=-2.00

<

>

本章小结
通过本章的学习,基本掌握C语言中的基本数据类型 ,了解常量的表示方法、变量的定义及初始化、运算符与 表达式的概念和基本应用。 C语句分为控制语句、函数调用语句、表达式语句、 空语句、复合语句等五种。C语言允许一行写几个语句, 也允许一个语句拆开写在几行上,书写格式无固定要求。 本章介绍的几种顺序执行的语句,在执行过程中不会发生 流程的控制转移。 本章介绍的四种输入输出库函数,是C语言中进行输 入输出的最基本函数,掌握不好会浪费大量的调试程序的 时间。这部分内容要在自学和在计算机上练习,应当通过 编写和调试程序来逐步深入而自然地掌握输入输出的应用 。

C语言程序设计

第四章 选择结构程序设计

第4章 选择结构程序设计
关系运算符和关系表达式

逻辑运算符和逻辑表达式
if语句 switch语句 程序举例

C语言程序设计

第四章 选择结构程序设计

选择结构是三种基本结构之一,其作用是,根据 指定的条件所满足的情况转而执行相应的操作。 C语言用关系表达式和逻辑表达式通过if语句实现 双分支选择,用switch语句实现多分支选择。

§4.1 关系运算符和关系表达式
??关系运算?即?比较运算,是对两个值进行 比较,比较的结果是得到真假两种值。 关系运算符

A>3
关系表达式 < >

C语言程序设计

第四章 选择结构程序设计

?关系运算符及其优先次序
?C语言提供6种关系运算符
? 种类:< <= == >= > != ? 结合方向:自左向右 ? 优先级别:

算术运算符



关系运算符
赋值运算符 低

< <= > >=

(小于) (小于等于) 优先级6(高) (大于) (大于等于)
优先级7(低)

= = (等于) ! = (不等于)

c>a+b a>b!=c a==b<c a=b>c

// // // //

c>(a+b) (a>b)!=c a==(b<c) a=(b>c)

<

>

C语言程序设计

第四章 选择结构程序设计

?关系表达式
?用关系运算符将两个表达式连接起来的式子

a>b , (a+b)>(b+c) , 5==3
?关系表达式的值:是逻辑值?真?或?假?,用1和0 表示

int a=3,b=2,c=1,d,f; a>b //表达式值1 (a>b)==c //表达式值1 b+c<a //表达式值0 d=a>b //d=1 f=a>b>c //f=0

<

>

C语言程序设计

第四章 选择结构程序设计

?关系运算几点注意:

例 5>2>7>8在C中是允许的, 值为 0
例 int i=1, j=7,a; a=i+(j%4!=0); 则a= 2
1 结果为 结果为0

>结合方向 自左至右

例 ‘a‘>0 ‘A‘>100

<

>

用ASCII值 比较

C语言程序设计

第四章 选择结构程序设计

?关系运算中应该注意 应避免对实数作相等或不等于0的判断 如 1.0/3.0*3.0==1.0 可改写为: fabs(1.0/3.0*3.0-1.0)<1e-6 注意区分“ = ‖与“ = = ‖ int a = 0,b =1; if(a = b) printf(―a equal to b‖); else printf(―a not equal to b‖);

<

>

C语言程序设计

第四章 选择结构程序设计

§4.2 逻辑运算符和逻辑表达式
用逻辑运算符将关系表达式或逻辑量连接起来 的式子就是逻辑表达式。 ?逻辑运算符: C语言提供3种逻辑运算符
运算符 && || ! 名称 逻辑与 示例 a && b a || b !a

含义
若a 、 b同时为真,则a && b为真 若a 、 b之一为真,则a || b为真 若a为真,则!a为假;a为假,则!a为真

逻辑或
逻辑非

―&&‖和“ ||‖是双目运算符 “!”是单目运算符

<

>

C语言程序设计

第四章 选择结构程序设计

?逻辑运算真值表
a 真 b 真 !a 假 !b 假 a&&b 真 a||b 真

真 假 假

假 真 假

假 真 真

真 假 真

假 假 假

真 真 假

?逻辑运算符的优先次序 !(非) , &&(与),
优先次序:高(2) 结合方向:从右向左 (11) 从左向右

||(或)
(12)低 从左向右

<

>

例:优先次序 (a>b)&&(x>y) //写成 a>b&&x>y (a==b)||(x==y) //写成 a==b||x==y (!a)||(a>b) //写成 !a||a>b

C语言程序设计

第四章 选择结构程序设计

?逻辑表达式
C语言中, 运算量: ?假?, 0表示?假?,运算结果: 0表示 非0表示?真?, 1表示

?真?, 例 a=4;b=5; !a a&&b a||b !a||b 4&&0||2 5>3&&2||8<4-!0 ?c‘&&?d‘

值为0 值为1 值为1 值为1 值为1 //(5>3)&&2||(8<(4-(!0))) 值为1 值为1

<

>

C语言程序设计

第四章 选择结构程序设计

?逻辑运算中的注意点:
短路特性:逻辑表达式求解时,并非所有的逻辑运算符 都被执行,只是在必须执行下一个逻辑运算符才能求 出表达式的解时,才执行该运算符。

a&&b&&c a||b||c

//只在a为真时,才判别b的值; 只在a、b都为真时,才判别 c的值 //只在a为假时,才判别b的值; 只在a、b都为假时,才判别 c的值

若 a=1;b=2;c=3;d=4;m=1;n=1; 则 (m=a>b)&&(n=c>d) //结果m=0,n=1 < >

C语言程序设计

第四章 选择结构程序设计

?复杂逻辑条件的表述

判断某一年year是否为闰年
判别闰年的条件(int year): 能被4整除: year%4==0 能被4整除但不能被100整除: (year%4==0)&&(year%100!=0) 能被400整除: year%400==0 综合起来: ((year%4==0)&&(year%100!=0))||year%400==0 优化语句: 此表达式为真时是闰年 (year%4==0&&year%100!=0)||year%400==0 < >

C语言程序设计

第四章 选择结构程序设计

§4.3 if 语句(条件选择语句)
?If语句的三种形式
?形式一:
? 格式:if (表达式) 语句 ? 执行过程:

表达式

=0

非0
语句

main() { int x , y ; x=20 ; 没有 y=10 ; “;” if (x>y) printf(―%d‖,x); }

<

>

C语言程序设计

第四章 选择结构程序设计

?形式二:
? 格式:if (表达式) 语句1 else 语句2 ? 执行过程:

非0

表达式

=0

语句1

语句2

main() { int x , y ; x=20 ; y=10 ; if (x>y) printf(―%d‖,x); else printf(―%d‖,y); }

<

>

C语言程序设计

第四章 选择结构程序设计

?形式三:
表达式1

=0
表达式2

非0

=0
表达式3

非0 语句1 语句2

=0

非0 语句3 语句n

? 格式:if (表达式1) 语句1 else if (表达式2) 语句2 else if (表达式3) 语句3 …… else if (表达式m) 语句m else 语句n ? 执行过程:

<

>

例:if (number>500) else if (number>300) else if (number>100) else if (number>50) else

cost=0.15 ; cost=0.1 ; cost=0.075 ; cost=0.05 ; cost=0 ;

必须有 ? ; ?

C语言程序设计

第四章 选择结构程序设计

?几点说明:
? if后面的表达式类型任意

if(a = =b&&x= =y) printf(―a=b,x=y‖); if(3) printf(―OK‖); if(?a‘) printf(―%d‖,a);
? if 后面的语句可以是复合语句,必须要加{ }

<

>

考虑下面程序的输出结果: { }后没有 main() { int x,y; ? ;? scanf(―%d,%d‖,&x,&y); if(x>y) x=y; y=x; else Compile Error! x++; y++; printf(―%d,%d\n‖,x,y); }

C语言程序设计

第四章 选择结构程序设计

例:输入两个数并判断两数是否相等

#include <stdio.h> void main() { int a,b; printf("Enter integer a:"); scanf("%d",&a); printf("Enter integer b:"); scanf("%d",&b); 运行:Enter if(a= =b) Enter printf("a==b\n"); a==b else printf("a!=b\n"); 运行:Enter } Enter < > a!=b

integer a:12? integer b:12?

integer a:12? integer b:9?

C语言程序设计

第四章 选择结构程序设计

例:判断输入字符种类
#include<stdio.h> void main() { char c; printf("Enter a character:"); c=getchar(); if(c<32) printf("The character is a control character\n"); else if(c>='0'&&c<='9') printf("The character is a digit\n"); else if(c>='A'&&c<='Z') printf("The character is a capital letter\n"); else if(c>='a'&&c<='z') printf("The character is a lower letter\n"); else printf("The character is other character\n"); }

<

>

运行: Enter aa character : ? 运行: 运行: 运行: 运行: Enter Enter Enter Enter a character acharacter acharacter character : : 8 : : ? D h F1 ? ?? The character is a control character The The The The character character character character is is is a is a a digit other capital lowercharacter letter letter

C语言程序设计

第四章 选择结构程序设计

例4.1:输入两个实数,按由小到大的次序输出两数

#include <stdio.h> void main() { float a,b,t ; scanf("%f,%f",&a,&b); if(a>b) {t=a;a=b;b=t;} printf("%5.2f,%5.2f",a,b); } 输入:3.6, -3.2 ? 输出:-3.20, 3.60
< >

C语言程序设计

第四章 选择结构程序设计

例4.2:输入三个数,按由小到大的次序输出

<

>

#include <stdio.h> void main() { float a,b,c,t ; scanf("%f,%f,%f",&a,&b,&c); if(a>b) {t=a;a=b;b=t;} 输入:3,7,1 ? if(a>c) 输出:1.00,3.00,7.00 {t=a;a=c;c=t;} if(b>c) {t=b;b=c;c=t;} printf(―%5.2f,%5.2f,%5.2f‖,a,b,c); }

C语言程序设计

第四章 选择结构程序设计

?If 语句的嵌套
? If语句中又包含一个或多个if语句称为if语句的嵌套。 ? 实际上只要将前述if语句的形式1和2中的内嵌语句用 一个if语句代替,即成为if语句的嵌套。 ? 嵌套的if语句还可以嵌套另一个if语句,形成多重嵌套。

?一般形式: if (条件1) if (条件2) else else if(条件3) else 语句1 语句2

内嵌if

语句3 语句4

内嵌if

<

>

C语言程序设计

第四章 选择结构程序设计

?if 嵌套的几种变形

是这样吗?

if (条件1) if (条件1) 语句1 if (条件2) 语句1 else else 必要时用{ }限定 if (条件2) 语句2 内嵌if范围 if (条件3) 语句2 内嵌if else 语句3 else 语句3 if (条件1) if (条件2) 语句1 else 语句2 else 语句3 < >

内嵌if

内嵌if 内嵌if

内嵌if

if (条件1) {if (条件2) 语句1} 内嵌if else if (条件3) 语句2 内嵌if else 语句3

注意:else 总是与前面最近的if 配对。

C语言程序设计

第四章 选择结构程序设计

例:输入两个数并判断其大小关系

#include <stdio.h> void main() { int x,y; printf("Enter integer x,y:"); scanf("%d,%d",&x,&y); if(x!=y) if(x>y) printf("X>Y\n"); else printf("X<Y\n"); else printf("X==Y\n"); }
< >

Enter integer x,y:12,23? X<Y Enter integer x,y:12,6? X>Y Enter integer x,y:12,12? X==Y

C语言程序设计

第四章 选择结构程序设计

?if ~ else 配对原则:缺省{ }时,else总是和它
上面离它最近的未配对的if 配对。

if(……) if(……) if(……) else…... else…... else…...

例 考虑下面程序的输出结果

结果:-1 < >

main() { int x=100,a=10,b=20; int v1=5,v2=0; if(a<b) if(b!=15) if(!v1) x=1; else if(v2) x=10; x= -1; printf(―%d‖,x); }

C语言程序设计

第四章 选择结构程序设计

例5.3 有一函数 -1 (x<0) y= 0 (x=0) 1 (x>0) 请考虑: 编一程序,输入一个x值,输出y值。 y=1或y=0时,if语句应 程序3 : 2 1改: 该如何写?

<

>

main( ) { }什么情况下可以不要? { int x,y; scanf(―%d‖,&x); if(x>=0); y= -1; y= -1; if(x<0) if(x>0) y=1; if(x!=0) else if(x= =0) y=0;输入 :-2 if(x>0) y=1; else y=0; { if(x>0) y=1;} 得到:x=-2,y=0 else y=1; else y=0; else y= -1 y=0; printf(―x=%d,y=%d \n‖,x,y); } printf(―x=%d,y=%d\n‖,x,y); }

C语言程序设计

第四章 选择结构程序设计

?条件运算符
if语句中,当表达式为?真?和?假?时,都只执行一个 赋值语句给同一个变量赋值时,可以用条件运算符处理。

if (a>b) max=a; else max=b;

max=(a>b)? a:b;

表达式1 ? 表达式2 : 表达式3
非0 =0

表达式1

条件运算符是 C 语言中唯一的 三目运算符 < >

表达式2值

表达式3值

C语言程序设计

第四章 选择结构程序设计

?条件运算符练习 例求 a+|b| (a==b)?‘Y‘:‘N‘ printf(―a+|b|=%d (x%2==1)?1:0 \n‖,b>0?a+b:a-b); (x>=0)?x:-x (c>=?a‘ && c<=?z‘)?c-‘a‘+‘A‘:c ?条件运算符几点说明:
? 条件运算符可嵌套 嵌套:x>0?1:(x<0?-1:0) ? 优先级: 13 ? 结合方向:自右向左 ? 表达式1?表达式2:表达式3 类型可以不同,表达式 值取表达式2和表达式3中较高的类型

x??a‘:?b‘ //x=0,表达式值为‘b‘; x≠0,表达式值为‘a‘ max=(a>b)? a:b; //max=a>b? a:b; a>b?a:c>d?c:d ? a>b?a:(c> d?c:d) x>y?1:1.5 //x>y ,值为1.0; x<y ,值为1.5 < >

C语言程序设计

第四章 选择结构程序设计

例4.4 输入一个字母,大写转小写,然后输出字母

#include <stdio.h> void main() { char ch; scanf("%c",&ch); ch=(ch>=?A‘ && ch<=?Z‘)? (ch+32) : ch; printf(―%c―,ch); }
输入:A 输出:a

<

>

C语言程序设计

第四章 选择结构程序设计

§4.4 switch语句(多分支选择语句)
?一般形式:

switch(表达式e) { case C1: ?执行过程 语句1; break; case C2: switch 语句2; break; ……. 表达式 case Cn: case 语句n; break; C1 C2 Cn default [default:语句n+1; break;] 语句组1 语句组2 …... 语句组n 语句组 }
< >

需要跳出switch 语句时使用

C语言程序设计

第四章 选择结构程序设计

?switch几点说明
? C1,C2,…Cn是常量表达式,且值必须互不相同 ? 常量表达式起语句标号作用,必须用break跳出 ? case后可包含多个可执行语句,且不必加{ } ? switch可嵌套 ? 多个case可共用一组执行语句

<

>

#include <stdio.h> A?A? 如: …… main() 85~100 85~1 { char grade; case ?A‘: 70~84 00 grade =getchar(); 60~69 switch(grade) case ?B‘: <60 { case ?A‘ : printf(―85~100 \n‖); break; Error case ?C‘: case ?B‘ : printf(―70~84 \n‖); break; case ?C‘ : printf(―60~69 \n‖); break; printf(―score>60 n‖); case ?D‘ : printf(―<60 \n‖);\break; default : break; printf(―Error \n‖); } 缺少 break; } ……..

C语言程序设计

第四章 选择结构程序设计

例 switch嵌套 #include <stdio.h> void main( ) { int x=1,y=0,a=0,b=0; switch(x) { case 1: switch(y) { case 0: a++; break; case 1: b++; break; } case 2: a++;b++; break; case 3: a++;b++; } printf(―\na=%d,b=%d‖,a,b); } < > a=2 , b=1

C语言程序设计

第四章 选择结构程序设计

§4.5 程序举例
例4.5 判断某一年是否闰年

#include <stdio.h> ② ① ③使用逻辑表达式 main() #include void <stdio.h> { int year,leap; void main() scanf(―Enter year:%d‖,&year); { int year,leap; if(year%4!=0) if(year%4==0) scanf(―Enter year:%d‖,&year); { leap=0; if(year%100==0) if((year%4==0&&year%100!=0)||(year%400==0)) else { if(year%100!=0) if(year%400==0) leap=1; leap=1; leap=1; else leap=0;} else leap=0; { }能省略吗? else if(year%400!=0) else leap=1;} if(leap) printf(―%d is‖,year); leap=0; else leap=0; else printf(―%d is not‖,year); else leap=1;is‖,year); printf(―%d printf(―aif(leap) leap year. \n‖); if(leap) printf(―%d is‖,year); else printf(―%d is not‖,year); } else printf(―%d is not‖,year); printf(―a leap year. \n‖); } printf(―a leap year.\n‖); < > }

C语言程序设计

第四章 选择结构程序设计

例 根据输入的字母输出相应的字符串

#include <stdio.h> void main() { int c; printf("Enter m or n or h or other:"); c=getchar(); switch(c) { case 'm': printf(" Good morning!\n");break; case 'n': printf(" Good night!\n"); break; case 'h': printf(" Hello!\n"); break; default : printf(" ????????\n"); } } m? Good morning!

<

>

C语言程序设计

第四章 选择结构程序设计

例4.6 求ax2+bx+c=0方程的解
#include <stdio.h> #include<math.h> void main() { float a,b,c,d,disc,x1,x2,realpart,imagpart; scanf(―%f,%f,%f‖,&a,&b,&c); printf(―The equation‖); if(fabs(a)<=1e-6) printf(―is not a quadratie‖); else {disc=b*b-4*a*c; if(fabs(disc)<=1e-6) printf(―has two equal roots:%8.4f\n‖,-b/(2*a)); else if(disc>1e-6) {x1=(-b+sqrt(disc))/(2*a); x2=(-b-sqrt(disc))/(2*a); printf(―has has distinct real roots:%8.4f and %8.4f\n‖,x1,x2);} else { realpart=-b/(2*a); imagpart=sqrt(-disc)/(2*a); printf(―has complex roots:\n‖); printf(―%8.4f + %8.4fi\n‖,realpart,imagpart); printf(―%8.4f + %8.4fi\n‖,realpart,imagpart); }}}

<

>

C语言程序设计

第四章 选择结构程序设计

例4.7 计算运费 #include <stdio.h> void main() { int c,s; float p,w,d,f; scanf(―%f,%f,%d‖,&p,&w,&s); if(s>=3000) c=12; else c=s/250; switch(c) { case 0: d=0;break; case 1: d=2;break; case 2: case 3: d=5;break; case 4: case 5: case 6: < >

case 7: d=8;break; case 8: case 9: case 10: case 11: d=10;break; case 12: d=15;break; } f=p*w*s*(1-d/100.0); printf(―freight=%15.4f‖,f); }

C语言程序设计

第四章 选择结构程序设计

§ 补充习题
? 编程实现:输入整数a和b,若a2+b2大于100,则 输出a2+b2百位以上的数字,否则输出a+b之和。 ? 编程实现:输入一个整数,判断它能否被3、5、 7整除,并输出以下信息之一: 1. 能同时被3、5、7整除; 2. 能被其中两数(要指出哪两个)整除; 3. 能被其中一个数(要指出哪一个)个整除; 4. 不能被3、5、7任一个整除。

<

>

本章小结
选择结构是三种基本结构之一。在大多数程序中都会包 含选择结构。它的作用是,根据指定的条件是否满足,决 定从给定的两组操作选择其一。本章主要介绍了如何用C语 言实现选择结构。 在C语言中选择结构是用if语句来实现的。其常用形式 是: if(关系表达式) 语句1 else 语句2

C语言程序设计

第五章 循环控制

第5章 循环控制
概述 goto语句以及用goto语句构成循环 while语句

do-while语句 for语句

循环的嵌套 几种循环的比较

break语句和continue语句 程序举例

C语言程序设计

第五章 循环控制

§5.1 概述
程序中凡涉及求阶乘、累加、排序等问题都要 用循环解决,因为程序中的某一程序段要重复执行 若干次。 C语言实现循环的语句: ?goto 和if组合 ?while语句 ?do while语句 重点 ?for语句

<

>

C语言程序设计

第五章 循环控制

§5.2 goto语句以及用goto语句构成循环
?作用:无条件地转移到语句标号指向的语句去执行。 ?一般格式: goto 语句标号; ….….. 标号:语句; ?说明:
? 语句标号由字母、数字和下划线组成,定名规则同变 量名,不能用数字开头。

goto loop; ( √ )

goto 100;(×)

<

>

? 与循环语句配合使用时,可从循环体内跳到循环体外, 而不能从循环体外跳到循环体内。 ? goto语句转移的方向可前可后。 ? 与if语句配合使用时可构成循环。 ? goto 语句违背结构化程序设计的原则,因此应限制 使用。

C语言程序设计

第五章 循环控制

例5.1 用if 和goto语句构成循环,求

循环初值

循环变量增值

<

>

#include <stdio.h> void main( ) { int i,sum=0; i=1; loop: if(i<=100) { sum+=i; i++; goto loop; } printf("%d",sum); }

循环终值

循环条件

循环体 sum=0+1 sum=1+2=3 sum=3+3=6 sum=6+4 …… sum=4950+100=5050

C语言程序设计

第五章 循环控制

例 从键盘输入一组数据,以0结束输入,求数据和。

#include <stdio.h> void main() { int number,sum=0; read_loop: scanf("%d",&number); if(!number) goto print_sum; sum+=number; goto read_loop; print_sum: printf("The total sum is %d\n",sum); }
< >

C语言程序设计

第五章 循环控制

§5.3 while语句
while语句实现?当型?循环结构。 没有 “;” ?一般形式: while(表达式) 循环体语句;

?功能:先判断表达式,若为真则执行循环体, 再判断表达式,重复上述过程,直到表达式为 假时退出循环。 i=1;sum=0 ?求 i=1;sum=0
i≤100
真 假

当i≤100 sum=sum+i i=i+1

sum=sum+i i=i+1

<

>

C语言程序设计

第五章 循环控制

例5.2 用while语句构成循环,求

循环初值

循环变量增值

<

>

#include <stdio.h> void main( ) { int i,sum=0; i=1; while(i<=100) { sum=sum+i; i++; } printf("%d",sum); }

循环终值

循环条件 循环体

C语言程序设计

第五章 循环控制

?关于while循环语句:
? while循环先判断表达式,后执行循环体。循环体有可 能一次也不执行。 ? 循环体若包含一个以上语句,应该用{}括起来。 ? 循环体应包含有使循环趋向结束的语句; ? 下列情况,退出while循环 ?条件表达式不成立(为零) ?循环体内遇 break , goto ? 无限循环

while(1)
循环体 ;

<

>

C语言程序设计

第五章 循环控制

例 用while语句显示1~10的平方

#include <stdio.h> void main() { int i=1; while(i<=10) { printf("%d*%d=%d\n",i,i,i*i); i++; } }
< >

1*1=1 2*2=4 3*3=9 4*4=16 5*5=25 6*6=36 7*7=49 8*8=64 9*9=81 10*10=100

C语言程序设计

第五章 循环控制

§5.4 do-while语句
?do-while语句实现?当型?循环结构。 ?一般形式: 有“;” do 循环体语句; while(表达式) ; ?功能:先执行循环体,然后判断表达式。若为 真,则再次执行循环体,否则退出循环。 ?求 i=1,sum=0 i=1,sum=0
sum=sum+i i=i+1
真 i≤100

sum=sum+i i=i+1 直到i>100

<

>



C语言程序设计

第五章 循环控制

例5.3 用do-while语句构成循环,求 输入:1 101 #include <stdio.h> 输出:

#include <stdio.h> void main( ) 5050 5050 101 0 void main() { int i,sum=0; 比较 {int i,sum=0; scanf("%d",&i); scanf("%d",&i); do while(i<=100) { sum+=i; 循环体 { sum+=i; i++; i++; } } while(i<=100); 循环条件 printf("%d",sum); printf("%d",sum); } }
< >
? do-while 循环,循环体至少执行一次; ? while和do-while可以解决同一问题,两者可以互换。 ? while后的表达式一开始就为假时,两种循环结果不同。

C语言程序设计

第五章 循环控制

§5.5 for语句
for 语句是 C 语言中最为灵活,使用最广泛的 循环语句,可完全替代while,do-while语句。 ?一般形式 for(表达式1;表达式2;表达式3) 循环体语句; ?常用形式 for(循环变量赋初值;循环条件;循环变量增值) 循环体语句;

<

>

C语言程序设计

第五章 循环控制

例 用for语句构成循环,求
i=1 i≤ 100 Y sum=sum+i i ++ N

#include <stdio.h> void main( ) { int i,sum=0; for(i=1;i<=100;i++) sum+=i; printf("%d",sum); }

循环步长

for循环下 面的语句

<

>

C语言程序设计

第五章 循环控制

?几点说明:
?for语句中表达式1、2、3类型任意,都可省略, 但分号?;?不能省。 ?无限循环:for(;;)不断执行循环体,循环不终止。 ?For语句可以转换成while结构

表达式1; while(表达式2) { 循环体语句; 表达式3; }
< >

C语言程序设计

第五章 循环控制

?几种形式:
? 省略表达式1:应在for之前为变量赋初值。 ? 省略表达式2:循环条件始终为?真?,循环不终止。 ? 省略表达式3:应另外设法使程序能够结束。 ? 省略表达式1、3:完全等同于while语句。 ? 三个表达式都省略:无初值,不判断条件,循环变量 不增值,死循环。

<

>

/*省略表达式1、3*/ /*省略表达式 1*/ 3*/ main( ) main( ) { int i,sum=0; { int i=1i,sum=0; ; for(i=1;i<=100;) i=1; for(;i<=100;) for(;i<=100;i++) {sum=sum+i sum=sum+i i++;} printf("%d",sum); }

/*正常形式*/ main( ) { int i ,sum=0; for(i=1;i<=100;i++) sum=sum+i; printf("%d",sum); }

C语言程序设计

第五章 循环控制

? 表达式1、3可以是与循环无关的表达式,也可以是逗 号表达式。

for ( s=0 , i=1 ; i<=100 ; i++ ) s=s+i;
? 表达式2可以是关系、逻辑、算术、字符表达式,非0 时,执行循环体,为0时退出循环。

/*表达式是逗号表达式 */ #include<stdio.h> #include <stdio.h> main() main() main() { int{ i,j,k; { int char i,c; c; for(i=0,j=100;i<=j;i++,j--) for(;(c=getchar())!='\n';) for(i=0;(c=getchar())!='\n';i+=c) { k=i+j; printf("%c ",c); printf("%d ",i+c); printf("%d+%d=%d\n",i,j,k); } } } } < >

C语言程序设计

第五章 循环控制

§5.6 循环的嵌套
?定义:一个循环体内又包含了另一个完整的循 环结构,称为循环的嵌套。 ?三种循环可以互相嵌套,层数不限。 ?嵌套循环的执行流程。
(1) while() { …… while() { …… } …... } (2) do { …… do { …… } while(); …... } while( ); (3) for(;;) { …… for(;;) { …… } }

(4) while() { …… do { …… } while(); ……. }

<

>

C语言程序设计

第五章 循环控制

(7) for( ; ;) { …… do { …… } while(); …… while() { …… ?循环可以互相嵌套,但不能相互交叉。 } …... for for }

(5) for( ; ;) { …… while() { …… } …... }

(6) do { …… for(; ;) { …… } …... } while();

for …… …... …...

for …… …... …...

<

>

C语言程序设计

第五章 循环控制

例 计算3组1~4累加的和

#include <stdio.h> void main() { int i,j,s=0; for(i=1;i<=3;i++) for(j=1;j<=4;j++) s=s+j; printf(―s=%d\n",s); }
结果:s=30 < >

i 1 1 1 1 2 2 2 2 3 3 3 3

j 1 2 3 4 1 2 3 4 1 2 3 4

s=0 1 3 6 10 11 13 16 20 21 23 26 30

C语言程序设计

第五章 循环控制

例 循环嵌套,输出九九乘法表 j void main() 2 3 4 5 6 7 8 9 { 1 int i,j; 1 2 3 4 5 6 7 8 9 for(i=1;i<10;i++) 2 printf("%4d",i); 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 printf("\n------------------------------------\n"); …………….. for(i=1;i<10;i++) for(j=1;j<10;j++) 9 18 27 36 45 54 63 72 81 printf((j==9)?"%4d\n":"%4d",i*j); }
条件运算符:

i

<

>

j=9,输出i*j,再回车换行。 j≠9,只输出i*j。

C语言程序设计

第五章 循环控制

? 九九乘法表逻辑框图

i=1 i<10 N Y j=1 j<10

外循环

N Y

内循环

printf

for(i=1;i<10;i++) for(j=1;j<10;j++) printf((j==9)?"%4d\n":"%4d",i*j);

j++

i++

<

>

C语言程序设计

第五章 循环控制

§5.7 几种循环的比较
语句 适用范围

说 明
该循环不能用break 和continue 语句控制

if~goto 无条件循环

只知道结束条件 ① 循环变量初始化在循环体之前 while 而无法确定执行 次数的情况下。 ② 循环体中应包含使循环结束的语句 ③ 可以用 break 和continue 语句控制 do-while 至少执行一次时

for

已知执行次数或 者已知初值,终 值,步长时。

使用比较灵活

<

>

C语言程序设计

第五章 循环控制

§5.8 break语句和continue语句
?Break语句
?功能:在循环语句和switch语句中,终止并跳出 循环体或开关体。 ?说明:
? break只能终止并跳出最近一层的结构。 ? break不能用于循环语句和switch语句之外的任何其它 语句之中。

?一般形式:break;

<

>

C语言程序设计

第五章 循环控制

?流程形式:
while 假(0) do …… break; …... 真(非0) while
表达式

for
表达式1 表达式2

假(0)

表达式

真(非0) …… break; ……

真(非0)
…… break;

…...
表达式3

假(0)

<

>

C语言程序设计

第五章 循环控制

switch 表达式 case const 1 const 2 const n default

语句组1
break;

语句组2
break;

…...

语句组n
break;

语句组
break;

<

>

C语言程序设计

第五章 循环控制

例 break举例:输出圆面积,面积大于100时停止 #include <stdio.h> #define PI 3.14159 void main( )

{ int r ; float area; for(r=1;r<=10;r++) { area=PI*r*r ; if(area>100) break; printf("r=%d,area=%f",r,area); } }
< > 使用break跳出 整个循环

输出: r=1, area=3.14 N r ≤ 10 r=2, area=12.57 Y r=3, area=28.27 area=3.14*r* r=4, area=50.27 r r=5, area=78.85 Y /*当 r=6 时, area>100 area=113.10 N 故此值没有被 i ++ 输出 */
for循环下 面的语句

r =1

C语言程序设计

第五章 循环控制

例 break举例:小写字母转换成大写字母,直至输入非字母字符

#include <stdio.h> void main() {char c; while(1) { c=getchar(); if(c>='a' && c<='z') putchar(c-32); else if(c>=?A' && c<=?Z') putchar(c); else break; } } break 使无限
< > 循环结束

C语言程序设计

第五章 循环控制

?Continue语句
?功能:结束本次循环,跳过循环体中尚未执行 的语句,进行下一次是否执行循环体的判断。 ?continue 语句仅用于循环语句中。

break 和 continue 语句的区别
?continue 语句只结束本次循环,break语句则是 结束整个循环。 ?continue 语句只用于while,do-while,for循环语句 中,break语句还可以用于switch语句中。

<

>

C语言程序设计

第五章 循环控制

?流程形式:
while 假(0)
do …… continue ;

for 表达式1
表达式2

假(0)

表达式

真(非0) ……
continue ; ……

真(非0) …… continue ; …...

真(非0)

…...
表达式

while

假(0) 表达式3

<

>

C语言程序设计

第五章 循环控制

例5.5 把100~200之间不能被3整除的数输出

#include <stdio.h> void main() { int i; for(i=100;i<=200;i++) { if(i%3= =0) continue; printf(―%d‖,n); } }

运行结果: 100,101, 103,104, 106,107, 109,110, 112,113, 115,116, 118,119,

i =100 i ≤ 200 Y i%3= =0 N printf i ++ Y N

使用continue 结束本次循环
< >

for循环下 面的语句

C语言程序设计

第五章 循环控制

例 求输入的十个整数中正数的个数及其平均值 #include <stdio.h> void main() { int i,num=0,a; float sum=0; for(i=0;i<10;i++) { scanf("%d",&a); if(a<=0) continue; num++; sum+=a; } printf("%d plus integer's sum :%6.0f\n",num,sum); printf("Mean value:%6.2f\n",sum/num); } < >

C语言程序设计

第五章 循环控制

§5.9 程序举例
分子:1,-1,1,-1… 分母:1,3,5,7,... t=1,pi=0,n=1.0,s=1 当|t|?1e-6 pi=pi+t

n=n+2 s=-s t=s/n
pi=pi*4 输出pi

<

>

#include <stdio.h> #include <math.h> void main() { int s; float n,t,pi; t=1; pi=0; n=1.0; s=1; while((fabs(t))>=1e-6) { pi=pi+t; n=n+2; s= -s; 运行结果: t=s/n; pi=3.141594 } pi=pi*4; printf("pi=%10.6f\n",pi); }

C语言程序设计

第五章 循环控制

例5.7 求Fibonacci数列:1、1、2、3、5、8……前40个数。
Fibonacci数列可以用一个有趣的古典数学问 题来描述:有一对兔子,出生三个月后每个月都 生一对兔子。小兔子长到三个月后每个月又生一 对兔子。假设所有的兔子都不死,问每个月的兔 子总数是多少对?

月数 1 2 3 4 5 …
< >

小兔 1 0 1 1 2 …

中兔 0 1 0 1 1 …

老兔 0 0 1 1 2 …

总数 1 1 2 3 5 …

C语言程序设计

第五章 循环控制

f1=1,f2=1

for i=1 to 20
输出f1,f2 f1=f1+f2 f2=f2+f1

#include <stdio.h> #include <conio.h> void main() { long int f1,f2; int i; f1=1; f2=1; for(i=1;i<=20;i++) { printf("%12ld %12ld ",f1,f2); if(i%2==0) printf("\n"); f1=f1+f2; f2=f2+f1; }
} 1 5 34 233 1597 10946 75025 514229 3524578 24157817 1 8 55 377 2584 17711 121393 832040 5702887 39088169 2 13 89 610 4181 28657 196418 1346269 9227465 63245986 3 21 144 987 6765 46368 317811 2178309 14930352 102334155

<

>

C语言程序设计

第五章 循环控制

例5.8 判断m是否素数。 19 ? 19 is a prime number

读入m
k= m i=2 当i?k 真 m被i整除

假 #include <stdio.h> 用break #include <math.h> 结束循环 void main() i=i+1 { int m,i,k; scanf("%d",&m); i?k+1 假 真 k=sqrt(m); for(i=2;i<=k;i++) 输出?是素数? 输出?不是素数? if(m%i==0) break; if(i>k) printf("%d is a prime number\n",m); else printf("%d is not a prime number\n",m); } < >

C语言程序设计

第五章 循环控制

例5.9 求100~200间的全部素数。
由于不是求一个数是否素数,因此需要使用双循环嵌套。外层第一个 循环,用于在100~200间提取一个数,然后内层第二个循环进行判断。

#include <stdio.h> #include <math.h> void main() { int m, k, i, n=0; for(m=101;m<=200;m=m+2) { k=sqrt(m); for(i=2;i<=k;i++) if(m%i==0) break; if(i>=k+1) {printf("%d",m);n=n+1;} if(n%10==0) printf("\n"); } 运行结果: printf("\n"); 101 103 107 109 113 } 151 157 163 167 173 < > 199

127 131 137 139 149 179 181 191 193 197

C语言程序设计

第五章 循环控制

例5.10 译密码。
按一定规律将电文变成密码: 将字母A变为E、将字母a变为e,即变成其后的第四个字母,W将 变成A。字母按上述规律转换,非字母字符不变。输入一行字符,输出 相应密码。

分析: 由于字符和整数之间可以通用,所以‘A‘->‘E‘对应‘A‘>‘A‘+4 可以定义一个字符型变量c,c接受输入,并c->c+4。 特殊之处是‘W‘-‘Z‘和‘w‘-‘z‘之间时,它们需要对应为‘A‘‘D‘和‘a‘-‘d‘,怎么办? 一种是用书上的办法,再减回去,即用c->c-26来解决。 < >

C语言程序设计

第五章 循环控制

#include <stdio.h> void main() { char c; while((c=getchar())!='\n') { if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) { c=c+4; if(c> 'Z'&&c<= 'Z'+4||c>'z') c=c-26; } printf("%c",c); } printf(―\n"); }
Hello,world! ? Lipps,asvph!

<

>

C语言程序设计

第五章 循环控制

?本章小结:
?问题求解的过程和步骤叫算法,如求π值的算法、验证 素数的算法。算法分析是程序设计的第一步,也是最 重要的步骤。用某种编程程序语言来表达算法是程序 设计的目的。 ?用编程语言实现结构化算法就是结构化程序设计。 ?结构化算法中只包含顺序、分支和循环三种控制结构。 ?在C语言中实现上述三种结构的控制语句分别是顺序语 句,分支语句和循环语句。 ?if/if else语句在使用时应注意else和最近一个没有被else 匹配的if匹配。 ??运算符相当于根据不同情况对同一变量赋值的if/else 语句的简写形式。 < >

C语言程序设计

第五章 循环控制

?switch语句实现多路选择,应用时应注意其条件表达式 值为整型或字符型,且每个分支应用break语句结束。 ?while和do while语句在应用时要注意后者至少执行一次 循环体。 ?for循环应用时要注意其控制结构中各个表达式的作用及 执行次序。for(表达式1;表达式2;表达式3)→表达式1是初 始执行,仅执行一次;表达式2接下来执行,以判断是否 退出循环,如果执行了循环,接下来执行表达式3,对循 环条件进行某中改变,然后再到表达式2进行判断…… ?注意break和continue的区别,break是结束本层循环, continue是结束本次循环。

<

>

C语言程序设计

第五章 循环控制

§本章要求
?初步熟悉用计算机解决问题的思路和方法。 ?掌握while, do while, for语句的特点和使用方法。 ?掌握break, continue语句的用法。 ?熟悉一些常见问题的算法及其C语言实现。

<

>

C语言程序设计

第六章 数组

第6章 数组-同类型批量数据
一维数组的定义和引用 二维数组的定义和引用 字符数组

C语言程序设计

第六章 数组

用基本数据类型可以解决所有问题吗? 例如:对学生的成绩按由高到低的次序进行排序。 3 名?stud01,stud02,stud03 300 名?stud001,stud02,……stud300 ?

? 数组属于构造类型。 ? 数组:是具有一定顺序关系的若干相同类型变量的集合, 用数组名标识。 ? 元素:组成数组的变量,用数组名和下标确定

<

>

C语言程序设计

第六章 数组

§6.1 一维数组的定义和引用
?一维数组的定义
?定义方式: 数据类型 例 int a[6];
a 0 1 2 3 4 5

表示元素个数 下标从0开始

数组名[常量表达式]; [ ] : 数组运算符 单目运算符 优先级(1),左结合 不能用( )

合法标识符
a[0] a[1] a[2] a[3] a[4] a[5]

数组名表示内存首地 址,是地址常量

<

>

编译时分配连续内存 例 int //C语言对数组不作越界检查, intdata[5]; i=15; 内存字节数=数组大小× data[5]=10; 使用时要 注意 int data[i]; (?不能用变量定义数组维数 ) 每元素的字节

C语言程序设计

第六章 数组

?一维数组元素的引用
?数组必须先定义,后使用 ?只能逐个引用数组元素,不能一次引用整个数组。 ?数组元素表示形式: 数组名[下标] 其中:下标可以是常量或整型表达式 例 int a[10]; printf(―%d‖,a); (?) 必须 for(j=0;j<10;j++) printf(―%d\t‖,a[j]); (?) 运行结果: 9876543210 < >

例6.1 #include <stdio.h> void main() { int i,a[10]; for(i=0;i<=9;i++) a[i]=i; for(i=9;i>=0;i- -) printf(―%d‖,a[i]); }

C语言程序设计

第六章 数组

?一维数组的初始化
实现的方法: ?在定义数组时对数组元素赋初值。 在定义数组时,为数组元素赋初值 int a[5]={1,2,3,4,5}; (在编译阶段使之得到初值) 等价于:a[0]=1; a[1]=2; a[2]=3; a[3]=4; a[4]=5; ?只给一部分元素赋值。 如 int a[5]={6,2,3}; 等价于: a[0]=6; a[1]=2;a[2]=3; a[3]=0; a[4]=0; 如 int a[3]={6,2,3,5,1}; (?) ?数组元素值全部为0。 int a[5]={0,0,0,0,0}; 或int a[5]={0}; ?对整个数组元素赋初值时,可以不指定长度。 < > int a[]={1,2,3,4,5,6}; 编译系统根据初值个数确定数组大小

C语言程序设计

第六章 数组

#include <stdio.h> ?一维数组程序举例 #define SIZE 10 例 读10个整数存入数组,找出其中最大值和最小值 void main() { int x[SIZE],i,max,min; printf("Enter 10 integers:\n"); 步骤: for(i=0;i<SIZE;i++) 1. 输入:for循环输入{ 10printf("%d:",i+1); 个整数 2. 处理: scanf("%d",&x[i]); (a) 先令max=min=x[0] } (b) 依次用x[i]和max,min 比较(循环) max=min=x[0]; 若max<x[i],令max=x[i] for(i=1;i<SIZE;i++) 若min>x[i],令min=x[i] { if(max<x[i]) max=x[i]; 3. 输出:max和min if(min>x[i]) min=x[i]; } printf("Maximum value is %d\n",max); printf("Minimum value is %d\n",min); < > }

C语言程序设计

第六章 数组

例6.2 用数组来处理求Fibonacci数列问题
0 1
2 3 4 1 1 2 3 5 ……... f[0] f[1] f[2] f[3] f[4] f[5]

5

#include <stdio.h> void main() { int i; int f[20]={1,1}; for(i=2;i<20;i++) f[i]=f[i-2]+f[i-1]; for(i=0;i<20;i++) { if(i%5==0) printf("\n"); printf("%12d",f[i]);} }
运行结果: 1 1 8 13 89 144 987 1597 2 21 233 2584 3 34 377 4181 5 55 610 6765

19

f[19]

f[19]

<

>

C语言程序设计

第六章 数组

例6.3 用起泡法对10个数排序(由小到大)
排序过程: (1)比较第一个数与第二个数,若a[0]>a[1],则交换;然后比较第二 个数与第三个数;依次类推,直至第n-1个数和第n个数比较为止 ——第一趟起泡排序,结果最大的数被安臵在最后一个元素位臵上 (2)对前n-1个数进行第二趟冒泡排序,结果使次大的数被安臵在第n-1 个元素位臵 (3)重复上述过程,共经过n-1趟冒泡排序后,排序结束 9 8 8 8 8 8 8 9 5 5 5 5 5 5 9 4 4 4 4 4 4 9 2 2 此处:n=6 8 5 5 5 5 5 8 4 4 4 4 4 8 2 2 5 4 2 0 4 5 2 0 4 2 5 0 4 2 0 5 4 2 2 2 2 4 0 0 0 0 4 2 0 0 2

2 2 2 8 0
0 0 0 0 8 第二轮

2 2 2 2 9 0
0 0 0 0 0 9 第一轮大数沉底

<

>

第三轮

第四轮

第五轮

外层循环j(1~n-1)次

内层循环i (1~n-j)次

C语言程序设计

第六章 数组

输入n 个数给a[1] 到 a[n]
for j=1 to n-1

for i=1 to n-j
真 a[i]>a[i+1]

a[i]?a[i+1]
输出a[1] 到 a[n]

<

>

#include <stdio.h> void main() { int a[10],i,j,t; printf("Input 10 numbers:\n"); for(i=0;i<10;i++) scanf("%d",&a[i]); printf("\n"); 假 for(j=0;j<9;j++) for(i=0;i<9-j;i++) if(a[i]>a[i+1]) {t=a[i]; a[i]=a[i+1]; a[i+1]=t;} printf("The sorted numbers:\n"); for(i=0;i<10;i++) printf("%d ",a[i]); }

C语言程序设计

第六章 数组

例 用简单选择法对10个数排序
排序过程: (1)首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数 交换—第一趟选择排序,结果最小的数被安臵在第一个元素位臵上 (2)再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录, 将它与第二个数交换—第二趟选择排序 (3)重复上述过程,共经过n-1趟排序后,排序结束

i=1 初始: [ 49
i=2 一趟: 13 二趟: 13 三趟: 13

38
[38 27 27

65
65 [65 38

97
97 97 [97

76
76 76 76

13
49 49 49

27 ]
27 ] 38 ] 65 ]

四趟: 13
五趟: 13

27
27 27

38
38 38

49
49 49

[76
65 65

97
[97 76

65 ]
76 ] [97 ]

<

>

六趟: 13

C语言程序设计

第六章 数组

输入n 个数给a[1] 到 a[n] for i=1 to n-1 k=i

for j=i+1 to n
真 k=j a[j]<a[k]

i != k 真 a[i]?a[k]
输出a[1] 到 a[n]

<

>

#include <stdio.h> void main() { int a[11],i,j,k,x; printf("Input 10 numbers:\n"); for(i=1;i<11;i++) scanf("%d",&a[i]); printf("\n"); for(i=1;i<10;i++) 假 { k=i; for(j=i+1;j<=10;j++) 假 if(a[j]<a[k]) k=j; if(i!=k) { x=a[i]; a[i]=a[k]; a[k]=x;} } printf("The sorted numbers:\n"); for(i=1;i<11;i++) printf("%d ",a[i]); }

C语言程序设计

§6.2 二维数组的定义和引用(多维数组)

第六章 数组 0 c[0][0][0] 1 c[0][0][1] 2 c[0][0][2] 3 c[0][0][3] int c[2][3][4] ?二维数组的定义 4 =行数 c[0][1][0] 行数 元素个数 *列数 列数 5 c[0][1][1] ?定义的一般形式 c[0][1][2] 6 c[0][1][3] 7 类型说明符 数组名[常量表达式][常量表达式 ]; c[0][2][0] ?数组元素的存放顺序 c[0][2][1] 例 int a[3][4]; c[0][2][2] ? 原因:内存是一维的float b[2][5]; c[0][2][3] ? 二维数组:按行序优先 c[1][0][0] int c[2][3][4]; c[1][0][1] ? 多维数组:最右下标变化最快 int a[3,4]; (? ) c[1][0][2] c[1][0][3] a[0][0] 0 int a[3][2] c[1][1][0] a[0][1] 1 c[1][1][1] a[0][0] a[0][1] 2 c[1][1][2] a[1][0] a[1][0] a[1][1] c[1][1][3] 3 a[1][1] 20 a[2][0] a[2][1] c[1][2][0] 21 4 a[2][0] c[1][2][1] 22 < > c[1][2][2] 5 a[2][1] 23 c[1][2][3] ………...

C语言程序设计

第六章 数组

?二维数组理解
二维数组a是由3个元素组成 例 int a[3][4]; a[0][1] a[0][2] a[0][3] a[0] a[0][0] 1 3 5 7 a[1][1] a[1][2] a[1][3] a[1] a[1][0] 9 11 13 15
2016 2018 2020 2022 行名 a[2] a[2][0] a[2][1] a[2][2] a[2][3] 17 19 21 23 2008 2010 2012 2014 2000 2002 2004 20006

0 1

2 3 4 5 6 7
8

每个元素a[i]由包含4个元素 的一维数组组成

9 10 11

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

a[0]

a[1]

a[2]

<

>

C语言程序设计

第六章 数组

?二维数组的引用
?形式: 数组名[下标][下标] ?下标是整型或字符型的常量,变量或表达式。 (定义时不能使用变量) 如: a[1][2] a[i][j] ?数组元素可出现在表达式中,如: a[1][2]=a[2][2]/2 ?使用数组元素时,应注意不要超出其定义的 范围; 如: int a[2][3]; a[2][3]=5;

<

>

C语言程序设计

第六章 数组

?二维数组的初始化
?分行初始化

第一维长度省略初始化 部分初始化 全部初始化 ?按元素排列顺序初始化
a[2][3]={1,2,4}; a[][3]={1,2,3,4,5}; 例 int inta[2][3]={1,2,3,4,5,6}; a[2][3]={{1,2,3},{4,5,6}}; a[2][3]={{1,2},{4}}; a[][3]={{1},{4,5}}; 1 2 3 4 5 6 4 0 0 0 0 0 1 2 3 4 5 6 a[0][1] a[0][2] a[0][2] a[1][0] a[1][0] a[1][1] a[1][1] a[1][2] a[1][2] a[0][0] a[0][1] a[0][0]

<

>

C语言程序设计

第六章 数组

?二维数组程序举例
例6.4 将二维数组行列元素互 换,存到另一个数组中

a=

1 2 3 4 5 6

b=

1 4 2 5 3 6

<

>

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

C语言程序设计

第六章 数组

例6.5 求二维数组中最大元素值及其行列号
max=a[0][0] for i=0 to 2

for j=0 to 3
真 a[i][j]>max 假

max=a[i][j] row=i colum=j 输出:max和row,colum

<

>

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

C语言程序设计

第六章 数组

例 读入下表中值到数组,分别求各行、各列及表中所有数之和
12 4 6 22

8
15

23
7

3
9

34
31

2
37

5
39

17
35

24
111

for(i=0;i<5;i++) { for(j=0;j<4;j++) printf("%5d\t",x[i][j]); printf("\n"); } } < >

#include <stdio.h> void main() { int x[5][4],i,j; for(i=0;i<4;i++) for(j=0;j<3;j++) scanf("%d",&x[i][j]); for(i=0;i<3;i++) x[4][i]=0; for(j=0;j<5;j++) x[j][3]=0; for(i=0;i<4;i++) for(j=0;j<3;j++) { x[i][3]+=x[i][j]; x[4][j]+=x[i][j]; x[4][3]+=x[i][j]; }

C语言程序设计

第六章 数组

§6.3 字符数组
字符数组:存放字符数据的数组。 一维字符数组:存放一个字符串(每个数组元素存放一个字符) 二维字符数组:存放多个字符串(行数是字符串的个数)

?字符数组的定义
?形式:
? char 数组名[常量表达式] ? char 数组名[常量表达式][常量表达式] ? 常量表达式:整数、字符、符号常量

例 char c[10], ch[3][4];
?可以用整型数组存放字符型数据,但浪费存储空间。 < >

C语言程序设计

第六章 数组

?字符数组的初始化
?逐个字符赋值 ?用字符串常量

二维字符数组初始化 逐个字符赋值

例 char diamond[][5]={{' ', ' ','*'},{' ','*',' ','*'}, 例 char ch[ ch[4]={ ch[5]={ ]={?H‘,‘e‘,‘l‘,‘l‘,‘o‘}; ?H‘,‘e‘,‘l‘,‘l‘,‘o‘ ?B‘,‘o‘,‘y‘ }; }; {'*', ' ', ' ', ' ' ,'*'},{' ','*', ' ','*'},{' ', ' ','*'}}; B H o e diamond[0] y l \0 l
*

\0 o

\0

有问题! \0 \0 * \0 \0

diamond[1] ch[0] ch[1] ch[2] *ch[3] ch[4] * * diamond[2]

diamond[3]
diamond[4] < >

* *

* \0

C语言程序设计

第六章 数组

?字符数组的引用
例6.6 输出一个字符串
0 I a m

#include <stdio.h> void main() { char c[10]={'I',' ','a','m',' ','a',' ','b','o','y'}; int i; for(i=0;i<10;i++) printf("%c",c[i]); printf("\n"); }
< >

1 2

3 4 5
6 7 8 9

a
b

o
y

C语言程序设计

第六章 数组

例6.7 输出一个钻石图形

#include <stdio.h> void main() { char diamond[ ][5]={{' ',' ','*'},{' ','*',' ','*'},{'*',' ',' ',' ','*'}, {' ','*',' ','*'},{' ',' ','*'}}; int i,j; 运行结果: for(i=0;i<5;i++) * {for(j=0;j<5;j++) * * printf("%c",diamond[i][j]); * * printf("\n"); * * } * }
< >

C语言程序设计

第六章 数组

?字符串和字符串结束标志
?字符串:用双引号括起的若干字符,如:

?china‖
可将其存放在一维或两维字符型数组中。 无字符串变量,用字符数组处理字符串

?字符串结束标志:‘\0’,(既无动作,又不显示)
? 字符串的长度:第一个‘\ 0‘以前字符的个数 ? 在字符型数组或字符串中遇‘\ 0‘,即认为该字符串结束。 ? 系统对字符串常量自动加一个‘\0‘作为结束符。

printf(―china‖); c h i n a \0

<

>

C语言程序设计

第六章 数组

?用字符串常量初始化字符数组 二维字符数组初始化 用字符串常量 例 char fruit[][7]={‖Apple‖,‖Orange‖, ‖Grape‖,‖Pear‖,‖Peach‖}; 例 char ch[6]={―Hello‖ }; char ch[6]=―Hello‖; A p p fruit[0] char ch[]=―Hello‖; a fruit[1]e O l r H l l e \0 \0

n o g \0 e \0 G r a p e \0 \0 fruit[2] ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] e a r \0 \0 \0 fruit[3] P fruit[4] < > P e a c h \0 \0

C语言程序设计

第六章 数组

?字符数组的输入输出
?逐个字符I/O: %c ?整个字符串I/O: %s 用字符数组名,不要加& 例 用%c void main() { char str[5]; 输入:China ? int i; 例 用%s for(i=0;i<5;i++) 输出:China void main() scanf(―%c‖, &str[i]); 输入:Program ? { char str[5]; for(i=0;i<5;i++) scanf(―%s‖, str); str[i]); 输出: Progr printf(―%c‖, }printf(―%s‖, str); 用字符数组名, }
遇‘\0‘结束 输入串长度<数组维数 遇空格或回车结束 自动加‘\0‘

<

>

C语言程序设计

第六章 数组

其它注意事项:

#include <stdio.h> void main() { char a[ ]={'h','e','l','\0','l','o','\0'}; printf("%s",a); }

输出:hel

h e

l \0 l o \0

数组中有多个‘\0‘时, 遇第一个结束 < >

C语言程序设计

第六章 数组

#include <stdio.h> void main() { char a[15],b[5],c[5]; scanf("%s%s%s",a,b,c); printf("a=%s\nb=%s\nc=%s\n",a,b,c); scanf("%s",a); printf("a=%s\n",a); } 运行情况: 输入:How are you?

运行情况: 输入:How are you? 输出:a=How b=are c=you? 输入:How are you? 输出:a=How

scanf中%s输入时,遇 空格或回车结束

H o w a r

\0

e \0

<

>

y o u ? \0

C语言程序设计

第六章 数组

例 若准备将字符串?This is a string.‖记录下来, 错误的输入语句为: (A)char s[20]; scanf(―%20s‖,s); (B)for(k=0;k<17;k++) s[k]=getchar(); (C)while((c=getchar())!=?\n‘) s[k++]=c; (D)char a[5],b[5],c[5],d[10]; scanf(―%s%s%s%s‖,a,b,c,d);

<

>

C语言程序设计

第六章 数组

?字符串处理函数
包含在头文件 string.h 中 ?字符串输出函数 puts
? 格式: puts(字符数组) ? 功能:向显示器输出一个字符串(输出完,换行) ? 说明:字符数组必须以‘\0‘结束。可以包含转义字符。 输出时‘\0‘转换成‘\n‘,即输出字符后换行。

这里是将 ‘\ 0‘ ? ?\ n‘ 因此光标移 到下行

运行结果: china beijing china WUHAN

<

>

例: #include <stdio.h> void main( ) { char a1[ ]=―china\ nbeijing‖ ; char a2[ ]=―china\ 0beijing‖ ; puts(a1); puts(a2); puts(―WUHAN‖ ); }

C语言程序设计

第六章 数组

?字符串输入函数gets
? 格式:gets (字符数组) ? 功能:从键盘输入一个以回车结束的字符串放入字符 数组中,并自动加‘\0’。 ? 说明:输入串长度应小于字符数组维数

例:gets和scanf输入比较 #include <stdio.h> void main( ) { char a1[15], a2[15] ; gets(a1); scanf(―%s‖,a2); printf (―a1=%s\ n‖,a1); printf (―a2=%s\ n‖,a2); }
< >

注意: puts 和gets函数只能输入输 在scanf 中遇空格字符串便结 出一个字符串。 束了, 而gets 中,却将空格 作为字符存入字符型 数组中。 错 puts(str1,str2) gets(str1,str2) 输入:china beijing ? china beijing ? 输出:a1=china beijing a2=china

C语言程序设计

第六章 数组

?字符串连接函数strcat
? 格式:strcat (字符数组1,字符数组2) ? 功能:把字符数组2连到字符数组1后面 ? 返值:返回字符数组1的首地址 ? 说明:?字符数组1必须足够大 ?连接前,两串均以‘\0’结束;连接后,串1的 ‘\0’取 消,新串最后加‘\0’。

例: #include <stdio.h> void main( ) { char str1[30]={―People‘s Republic of ―}; char str2[]={China‖}; printf (―%s\n‖,strcat(str1,str2)); } str1: People‘s Republic of \0 < > str2: china\0 str1: People‘s Republic of china\0

C语言程序设计

第六章 数组

?字符串拷贝函数strcpy
? 格式:strcpy(字符数组1,字符串2) ? 功能:将字符串2,拷贝到字符数组1中去 ? 返值:返回字符数组1的首地址 ? 说明:?字符数组1必须足够大,>字符串2 ?字符数组1必须是数组名形式(str1), 字符串 2可以是字符数组名或字符串常量。 ?拷贝时‘\0’一同拷贝 ④不能使用赋值语句为一个字符数组赋值

例 char str1[20],str2[20]; str1={―Hello!‖}; str2=str1;

( ?) (?)

<

>

⑤可以只复制字符串2中的前几个字符,来取 代字符数组1的前几个字符。 strcpy(str1,str2,2) —— 复制前2个。

C语言程序设计

第六章 数组

例 strcpy与strcat应用举例

#include <stdio.h> void main() { char destination[25]; char blank[] = " ", c[]= "C++", turbo[] = "Turbo"; strcpy(destination, turbo); strcat(destination, blank); strcat(destination, c); printf("%s\n", destination); }
< >

0 1 2

T u r b o \0 \0 C +

3 4 5
6 7 8 9

+ \0

24

C语言程序设计

第六章 数组

?字符串比较函数strcmp
? 格式:strcmp(字符串1,字符串2) ? 功能:比较两个字符串 ? 比较规则:对两串从左向右逐个字符比较(ASCII码), 直到遇到不同字符或‘\0’为止。 ? 返回值:返回int型整数。其值是ASCII码的差值 a. 若字符串1< 字符串2, 返回负整数 b. 若字符串1> 字符串2, 返回正整数 c. 若字符串1== 字符串2, 返回零 ? 说明:字符串比较不能用?==?,必须用strcmp, 虽然编译无错,但结果不对

错 if(str1==str2) printf(―yes‖);
< > if(strcmp(str1,str2)==0) printf(―yes‖);



C语言程序设计

第六章 数组

例:字符比较 #include <stdio.h> void main( ) { int i,j,k; char a1[ ]=―wuhan‖, a2[ ]=―beijing‖ ; i=strcmp(a1,a2); j=strcmp(―china‖, ―korea‖); k=strcmp(a2, ―beijing‖ ); printf(―i=%d\ nj=%d\ nk=%d\ n‖,i,j,k); } 运行结果: i=21 i=w-b=119-98=21 j=-8 j=c-k=99-107=-8 k=0 k=b-b=98-98=0

<

>

C语言程序设计

第六章 数组

?字符串长度函数strlen
? 格式:strlen(字符数组) ? 功能:计算字符串长度 ? 返值:返回字符串实际长度,不包括‘\0’在内

例 对于以下字符串,strlen(s)的值为: (1)char s[10]={?A‘,?\0‘,?B‘,?C‘,?\0‘,?D‘}; (2)char s[ ]=―\t\v\\\0will\n‖; (3)char s[ ]=―\x69\082\n‖; 答案:1 3 1 例:测试字符串长度 运行结果:5 #include <stdio.h> 7 void main( ) { char a1[10]=― china‖ ; printf (―%d\ n‖,strlen(a1)); printf (―%d\ n‖, strlen(―beijing\ 0wuhan‖)); }

<

>

C语言程序设计

第六章 数组

?大写字母转换成小写字母函数strlwr
? 格式:strlwr(字符串)

?小写字母转换成大写字母函数strupr
? 格式:strupr(字符串)

例:字符转换 #include <stdio.h> void main( ) { char a1[6]=―CHinA‖, a2[ ]=―wuHAn‖ ; printf (―%s\ n‖,strlwr(a1)); printf (―%s\ n‖,strupr(a2)); }

运行结果:china WUHAN
< >

C语言程序设计

第六章 数组

例6.8 输入一行字符,统计其中的单词个数,单词间空格分开。 分析:根据题目要求,可以用一个字符数组来存储输入的这行字 符。要统计其中单词数,就是判断该字符数组中的各个字 符,如果出现非空格字符,且其前一个字符为空格,则新 单词开始,计数num加1。 但这在第一个单词出现时有点特殊,因为第一个单词前面 可能没有空格,因此在程序里我们可以人为加上一个标志 word,并初始化为0。该标志指示前一个字符是否是空格, 如果该标志值为0则表示前一个字符为空格。

<

>

C语言程序设计

第六章 数组



未出现新单词,使word=0,num不累加 前一字符为空格(word==0),新单词出现, word=1,num加1 前一字符为非空格(word==1),未出现新单词,num不变

当前字符=空格


例 输入:I ?am ?a ?boy. 当前字符 是否空格 word原值
I

?

a

m

?

a

?

b

o

y

.

否 是 否 否 是 否 是 否 否 否 否 0 1 0 1 1 0 1 0 1 1 1

新单词开始否 是 未 是 未 未 是 未 是 未 未 未 word新值 1 1 0 1 1 2 1 2 0 2 1 3 0 3 1 4 1 4 1 4 1

num值

4

<

>

C语言程序设计

第六章 数组

输入一字符串给 string i=0 num=0 word=0 当((c=string[i])!=?\0‘) 真 c=空格 假 word==0





word=0 word=1 num=num+1 i=i+1

输出:num

<

>

#include <stdio.h> void main() {char string[81]; int i,num=0,word=0; char c; gets(string); for(i=0;(c=string[i])!='\0';i++) if(c==' ') word=0; else if(word==0) {word=1; num++;} printf("There are %d words in the line\n",num); }

C语言程序设计

第六章 数组

例6.9 有3个字符串,要求找出其中最大者。 #include <stdio.h> #include <string.h> void main() { char string[20],str[3][20]; int i; for(i=0;i<3;i++) gets(str[i]); if(strcmp(str[0],str[1])>0) strcpy(string,str[0]); else strcpy(string,str[1]); if(strcmp(str[2],string)>0) strcpy(string,str[2]); printf("\nThe largest string is:\n%s\n",string); }

str[0] str[1] str[2]

H o w
H e l H i g

\0
l o \0 h \0

<

>

C语言程序设计

第六章 数组

例 char name[0]; float weight[10.3]; int array[-100];
例 int a[10]; float i=3; a[i]=10;

例 char str[]=―Hello‖; char str[]={?H‘,?e‘,?l‘,?l‘,?o‘};
0 h


1 e 1 e

2 l 2 l

3 l 3 l

4 5 o \0 4 o

例 int a[5]; a={2,4,6,8,10};

0 h

例 int a[][10]; float f[2][]={1.2 ,2.2};
例 比较 int a[2][3]={{5,6},{7,8}}; 与 int a[2][3]={5,6,7,8};

5 7 5 8

6 8 6 0

0 0 7 0

<

>

C语言程序设计

第六章 数组

?本章要求
数组是程序设计的常用数据结构,字符串(字符数组) 在程序中应用普遍,应掌握它们的意义和用法。 ?数组(一维和二维)名、数组元素的概念。 ?数组的初始化方法。 ?数组元素在内存中的存储顺序。 ?数据排序算法。 ?字符串的特点(作为数组处理,最后一字节加 ‘\0‘) ?字符串处理函数的应用。 skip < >

C语言程序设计

第六章 数组

? 补充习题:
1. 2. 已知10个学生的成绩求平均分。 有3个学生四门课成绩,求每个学生的平均分,每门课 的平均分。 数学 英语 化学 物理 张三 92 85 68 75 李四 54 88 98 45 王五 61 79 81 40

<

>

C语言程序设计

第六章 数组

§补充例题
例 1 接受键盘输入的两个字符串,并将其首尾相接后输出。每 个字符串内部不含空格,两个字符串之间以空白符分隔。 分析: 数据结构: 字符串的存储需要用字符数组 算法要点: 字符串输入,可以用具有词处理功能的scanf()函数。 字符串拼接方法:先找到第一个字符串的末尾,然后 将第二个串的字符逐个添加到末尾。 注意,要去掉第一个串的结束符‘\0‘,但第二个串的 结束符‘\0‘要添加进去。 < >

C语言程序设计

第六章 数组

程序1: #include <stdio.h> void main() { char str1[50],str2[20]; int i,j; printf("Enter string No.1:\n"); scanf("%s",str1); printf("Enter string No.2:\n"); scanf("%s",str2); i=j=0; while(str1[i]!='\0') i++; /*寻找字符串str1的尾*/ while((str1[i++]=str2[j++])!=?\0‘) ; /*str2加入到str1*/ printf("string No.1->%s\n",str1); }
< >

C语言程序设计

第六章 数组

例 2 从键盘输入若干行文本,每行以回车结束,以 ctrl+z 作 为输入结束符,统计其行数。

分析: 数据结构: 由于只统计行数,所以不必使用数组存储文本内容, 只须定义一个字符变量暂存读入的字符。 算法要点: 读入字符可以用 getchar() 函数。 每读入一个字符,要判断是否输入结束 要判断读入的是否回车符,定义一个整型变量对回车符 进行计数,以实现统计行数的功能。

<

>

C语言程序设计

第六章 数组

程序2: #include<stdio.h> void main() { int c,nl; nl=0; while((c=getchar())!=EOF) if(c=='\n') /*如果是换行,则nl加1*/ ++nl; printf("%d\n",nl); } < >

C语言程序设计

第六章 数组

例 3 把输入的字符串逆序排列,并显示。

分析: 数据结构: 输入的字符串用字符数组存放。 算法要点: 逆序排列用交换算法,求出字符串最后一个字符的下标, 然后将第一个和最后一个交换,第二个和倒数第二个交 换, ...。

<

>

C语言程序设计

第六章 数组

程序3: #include <stdio.h> void main() { char str[80]; int temp,i,j; printf("Enter a string:\n"); scanf("%s",str); for(i=0,j=strlen(str)-1;i<j;i++,j--) { temp=str[i]; str[i]=str[j]; /*交换i,j两个元素*/ str[j]=temp; } printf("\nReversed string:\n%s\n",str); } < >

C语言程序设计

第六章 数组

例 4 从键盘输入字符,以 ctrl+z 结束,统计输入的数字 0~9、空白符和其它字符的个数。 分析: 数据结构: 定义一个具有 10 个元素的整型数组来存放数字 0~9 的 个数 定义两个整型变量来存放空白符和其它字符的个数。 算法要点: 计数用的数组和变量要初始化为0。 用循环结构处理字符读入,内嵌分支结构处理计数。

<

>

C语言程序设计

第六章 数组

程序4: #include<stdio.h> void main() { int c,i,nwhite,nother,ndigit[10]; /*存放相应的计数值*/ nwhite=nother=0; for(i=0;i<10;i++) /*初始化这些计数值*/ ndigit[i]=0; while((c=getchar())!=EOF) if(c>='0'&&c<='9') ++ndigit[c-'0']; /*相应的ndigit[i]加1*/ else if(c==' '||c=='\n'||c=='\t') ++nwhite; else ++nother; for(i=0;i<10;i++) printf("digit '%d':%d\n",i,ndigit[i]); printf("white space:%d\n",nwhite); printf("other character:%d\n",nother); } < >

C语言程序设计

第六章 数组

例 5 从键盘输入一个字符串(长度不超过20,其中不含 空格),将其复制一份,复制时将小写字母都转换 成为大写字母)。 分析: 数据结构 定义两个数组,存放字符串。 算法要点 将小写字母 转换为大写字母:小写字母-'a'+'A'。

<

>

C语言程序设计

第六章 数组

程序5: #include <stdio.h> void main() { char a[20],b[20]; int i; printf("Enter a string:\n"); scanf("%s",a); i=0; do { b[i]=(a[i]>='a'&&a[i]<='z')? /*将a数组中小写字母转为*/ a[i]-'a'+'A':a[i]; /*大写并对b数组赋值*/ } while(a[i++]!='\0'); printf("Copyed string:\n%s\n",b); }
< >

C语言程序设计

第六章 数组

例6 从一个三行四列的整型二维数组中查找第一个出现 的负数。 分析 算法要点: 用两层嵌套的 for 循环来遍历数组元素,判断是否为负数。 当找到第一个负数时就应该退出循环,为此,应定义一个 标记变量,用于标记找到与否的状态,并将此标记加入循 环控制条件中,以控制循环在适当时候退出。

<

>

C语言程序设计

第六章 数组

<

>

程序6: #include <stdio.h> void main() { int i,j,found,num[3][4]; printf("Enter 12 integers:\n"); for(i=0;i<3;i++) for(j=0;j<4;j++) scanf("%d",&num[i][j]); found=0; for(i=0;i<3 && !found;i++) for(j=0;j<4 && !found;j++) found=num[i][j]<0; if(!found) printf("not found\n"); else printf("minus number num[%d][%d]:%d\n", i-1,j-1,num[i-1][j-1]); }

C语言程序设计

第六章 数组

例7 用筛选法求100以内的素数 分析 数据结构 定义一个具有 100 个元素的数组,用来标记整数 1~100是否素数。0表示素数,1表示非素数。 算法要点 本例使用筛选法:1不是素数,从2开始,每找到一 个素数,便将其倍数全部标记为非素数,最后剩下 的便是素数。

<

>

C语言程序设计

第六章 数组

N-S图
定义及初始化变量 将 1 标记为非素数 n=1; n<=100; n++ n是素数?

Y
输出 n

N

将 n 的所有倍数都标记为 非素数
< >

C语言程序设计

第六章 数组

for(n=1;n<=SIZE;n++) 程序7: if(sieve[n-1]==0) #include<stdio.h> {printf("%5d",n); #define SIZE 100 /*分行打印n值*/ #define PWIDTH 10 if(++printcol>=PWIDTH) void main() { putchar('\n'); { char sieve[SIZE]; printcol=0; int i,n,printcol; } for(i=0;i<SIZE;i++) /*将能被n整除的数都标记为非素数*/ for (i=2*n;i<=SIZE;i=i+n) sieve[i]=0; /*暂时都标记为素数 */ sieve[i-1]=1; sieve[0]=1; /*因为1是非素数,所以sieve[0]标记为非素数*/ } printcol=0; }
< >

C语言程序设计

第七章 函数

第7章 函数-模块化程序设计
概述
函数定义的一般形式

函数参数和函数的值
函数的调用 函数的嵌套调用 函数的递归调用 数组作为函数参数 局部变量和全局变量 变量的存储类别 内部函数和外部函数 运行一个多文件的程序

C语言程序设计

第七章 函数

本章学习目标:
?认识到函数是一种简化程序结构的重要手段; ?理解函数调用和函数调用过程中的参数传递; ?理解函数原型(声明)和怎样写函数原型; ?能够用前几章的知识实现简单的函数; ?能够用return语句实现函数的返回值; ?能够理解函数调用过程中形式参数和实际参 数的关系,理解数组名作为函数参数时代表的 意义; ?能够理解函数的嵌套调用和递归调用机制 。
< >

C语言程序设计

第七章 函数

§7.1 概述
?函数的概念
一个大的程序一般应分为若干个程序模块,每个模块 实现一个特定的功能,这些模块称为子程序,在C语言 中子程序用函数实现。
不能被调用 分为: 库函数和 自定义函数 main 所有函数都是 平行的,不能 嵌套定义 c

a

b

a1

ab

b1

b2

<

>

C语言程序设计

第七章 函数

一、常规方法:各函数包含在一个文件中 例T7-1.c #include <stdio.h> void main( ) {void printstar( ); 运行结果: void print_message( ); **************************** printstar( ); How do you do! print_message( ); *********************** ***** printstar( ); } void printstar( ) {printf (―***********************\ n‖ ); } void print_message( )
{printf (―_ _ _ _ _How_do_you_do!\n‖) ;} < >

C语言程序设计

第七章 函数

二、工程的方法 例:某程序由四个文件组成,其中,一个文件包含主函数,两 个文件包含两个被调用函数。一个为工程文件,包含这个程序 的三个文件名。 T7-1-1.c 操作:Alt+p Project name :T7-1-4.prj main( ) { p1( ) ; p2( ) ; p1( ) ; } Alt +R 结果同上 T7-1-4.prj T7-1-1 T7-1-2 T7-1-3 < > T7-1-2.c p1( ) {printf (―*********************\ n‖); } T7-1-3.c p2( ) {printf (―

How do you do!\ n‖); }

C语言程序设计

第七章 函数

三、文件包含的方法 在主函数中使用文件包含预编译命令,将不在本文件 而在其它文件中的函数进行预编译处理把各文件中的函数 包含到本文件中来,然后一起进行编译、连接、运行。 T7-1-5.c #include ―T7-1-2.c‖ #include ―T7-1-3.c‖ main( ) {p1( ); p2( ) ; p1( ) ; }

运行结果同上

<

>

C语言程序设计

第七章 函数

?几点说明: (1)一个源文件由一个或者多个函数组成。 (2)一个C程序由一个或者多个源文件组成。 (3)C程序的执行从main 函数开始。 (4)所有的子函数都是平行的。 (5)从用户的角度看,函数分库函数和自定义 函数。 (6)函数形式: ①无参函数:主调函数无数据传送给被调函 数,可带或不带返回值。 ②有参函数:主调函数与被调函数间有参数 < >传递,主调函数可将实参传送给被调函数的

§根据(1)(2)(3)可知,逻辑上一个C语言程 序是由函数构成的,C语言程序从主函数 开始执行,在主函数中调用其他函数, 这些函数可能又调用别的函数,主函数 执行完毕代表整个程序结束。主函数只 能调用不能被调用。物理上一个程序由 一个或者若干个文件(源文件)构成,函数 分别放臵在这些文件中。

C语言程序设计

第七章 函数

§7.2 函数定义的一般形式
?无参函数的定义形式
?类型标识符: ?用于指定函数带回的值的类型,不写时为int 型。 合法标识符 ?不带回值时可以不写。 例 无参函数 printstar( ) { printf(―**********\n‖); } 或 printstar(void ) { printf(―**********\n‖); } < > 类型标识符 函数名() { 说明部分 语句 } 函数体

C语言程序设计

第七章 函数

?有参函数定义的一般形式
现代风格: 函数体

函数返回值类 型 隐含为int型

类型标识符 { 说明部分 语句 }

函数名(形式参数表列)

例 有参函数(现代风格) int max(int x,int y) { int z; z=x>y?x:y; return(z); } < >

例 有参函数(现代风格) int max(int x, y) { int z; z=x>y?x:y; return(z); }

C语言程序设计

第七章 函数

?空函数
?为扩充功能预留,在主调函数中先占一个位臵。 类型标识符 { } 函数名() 例 空函数 dummy( ) { }

?对形参的声明的传统方式
类型标识符 函数名(形参表) 形参类型说明 { 说明部分 语句 }
< >

函数体为空 ?即把对形参的声明放在函数定义的下一行 例 有参函数(传统风格) int max(x,y) int x,y; { int z; z=x>y?x:y; return(z); }

C语言程序设计

第七章 函数

§7.3 函数参数和函数的值
?形式参数和实际参数
?形式参数:定义函数时函数名后面括号中的变量名 ?实际参数:调用函数时函数名后面括号中的表达式 例7.2比较两个数并输出大者 #include <stdio.h> c=max(a,b); (main 函数) void main() { int max(int x,int y); max(int x, int y) (max 函数) int a,b,c; { int z; scanf("%d,%d",&a,&b); z=x>y?x:y; c=max(a,b); 实参 return(z); printf("Max is %d",c);} } max(int x, int y) 形参 { int z; 运行:7,8? z=x>y?x:y; < > Max is 8 return(z);}

C语言程序设计

第七章 函数

?几点说明: ?实参可以是常量、变量或表达式。必须有确定 的值。当函数调用时,将实参的值传递给形参, 若是数组名,则传送的是数组首地址。

?形参必须指定类型,只能是简单变量或数组, 不能是常量或表达式
?形参与实参类型一致,个数相同顺序相同。

?若形参与实参类型不一致,自动按形参类型转 换———函数调用转换
?形参在函数被调用前不占内存;函数调用时为形 参分配内存;调用结束,内存释放 ?实参对形参的数据传送是值传送,也是单向传 送,当被调函数的形参发生变化时,并不改变 主调函数实参的值。形、实参占据的是不同的 存储单元

<

>

C语言程序设计

第七章 函数

例:形、实参占据的是不同的存储单元 #include <stdio.h> void main( ) {int a=2,b=3; printf (―a=%d, b=%d\ n‖,a, b); printf(―&a=%x,&b=%x\n‖ ,&a,&b); add(a,b); printf(―a=%d,b=%d\n‖, a,b); printf(―&a=%x,&b=%x\n‖, &a,&b); } add(int x,int y) {x=x+8; y=y+12; printf(―x=%d,y=%d\ n‖,x,y); printf(―&x=%x,&y=%x\n‖,&x,&y); }
< >

ffd2 ffd4 ffd6 ffd8

2+8=10 3+12=15 2 3

x y a b

运行结果: a=2,b=3 &a=ffd6,&b=ffd8 x=10,y=15 &x=ffd2,&y=ffd4 a=2, b=3 &a=ffd6,&b=ffd8

C语言程序设计

第七章 函数

?函数的返回值 ?返回语句形式: return(表达式);或 return 表达式; ?功能:使程序控制从被调用函数返回到 调用函数中,同时把返值带给调用函数

<

>

?说明: ?函数的返回值,必须用 return 语句带回。 ?return 语句只能把一个返值传递给调用函数。 ?函数中可有多个return语句,执行哪一个由 程序执行情况来定。 if(a>b) return(a); else return(b); ?return 后的值可以是一个表达式,如: return(x > y ? x : y); ?返回值的类型为定义的函数类型,不指定的 按整型处理。 如: int max(int x, int y) float min(float a,float b) double abc(float d1,float d2)

C语言程序设计

第七章 函数

?若 return 语句中表达式类型与函数类型不一 致,则转换为函数类型。 ?若无return语句,遇}时,自动返回调用函数。 可能返回一个不确定或无用的值 。 ?无返回值的函数,定义为 void 类型。 例:无return语句,函数带回不确定值 printstar() { printf("**********"); } main() { int a; a=printstar(); printf("%d",a); } < >
输出:10

void printstar() { printf("**********"); } main() { int a; a=printstar(); printf("%d",a); }
编译错误!

C语言程序设计

第七章 函数

#include <stdio.h> 例:无返回值函数 void main() void swap(int x,int y ) { int max(float x,float y); { int temp; float a,b; temp=x; int c; x=y; scanf("%f,%f",&a,&b); y=temp; c=max(a,b); } printf("Max is %d\n",c); } 例7.3: 函数返回值类型转换 max(float x, float y) { float z; 输入:1.5,2.5 z=x>y?x:y; return(z); 输出:Max is 2 < > }

C语言程序设计

第七章 函数

§7.4 函数的调用
主调函数:主动去调用其它函数 被调函数:被其它函数所调用

?函数调用的一般形式
函数名(实参表列) ?说明: ?实参表列:有确定值的数据或表达式 ?实参与形参个数相等,类型一致,按顺序一 一对应,当有多个实参时,实参间用? ,? 分隔 ?实参表求值顺序,因系统而定(Turbo C 自 右向左) ?调用无参函数时,实参表列为空,但( )不 > 能省

<

C语言程序设计

第七章 函数

例7.4 参数求值顺序 按自右向左求值 函数调用等于f(3,3) 运行结果:0 #include <stdio.h> void main() { int f(int a,int b); int i=2,p; p=f(i,++i); printf("%d",p); } int f(int a, int b) { int c; if(a>b) c=1; else if(a==b) c=0; else c=-1; return(c); } 按自左向右求值 函数调用等于f(2,3) 运行结果:- 1

需自右向左求值时, 改为:j=++i; p=f ( j , j ) ;

需自左向右求值时,

改为:j = i ;
k = ++ i ; p=f(j,k);

<

>

Printf(―%d,%d‖,i,i++); 为使程序有通用性: /*同样存在此情况*/

C语言程序设计

第七章 函数

?函数调用的方式
按函数在程序中出现的位臵,有三种调用方式: ?函数语句:以独立的语句去调用函数。不要求有 返回值,仅完成一定的操作。 例 printstar(); printf(―Hello,World!\n‖); ?函数表达式: 函数返回一个确定值,以参加表达式的运算。不 可用于void 例 m=max(a,b)*2; ?函数参数:函数调用作为另一个函数的参数。 例 printf(―%d‖,max(a,b)); /*输出大数*/ m=max(a,max(b,c)); /*三数比大小*/

<

>

C语言程序设计

第七章 函数

?对被调用函数的声明和函数原型 ?对被调用函数要求: ?必须是已存在的函数 ?库函数: #include <*.h> ?用户自定义函数:如果被调函数定义 在主调函数之后,那么在主调函数中 对被调函数作声明。

<

>

?函数声明 ?一般形式:函数类型 函数名(形参类 型 [形参名],….. ); 或 函数类型 函数名(); ?作用:告诉编译系统函数类型、参数 个数及类型,以便检验 ?C语言中函数声明称为函数原型。 ?函数定义与函数声明不同,声明只与 函数定义的第一行相同。声明可以不 写形参名,只写形参类型。 ?函数说明位臵:程序的数据说明部分 (函数内或外)

C语言程序设计

第七章 函数

例7.5 对被调用的函数作声明

<

#include <stdio.h> void main() { float add(float x,float y ); /*对被调用函数的声明*/ float a,b,c; scanf("%f,%f",&a,&b); float add(float,float); c=add(a,b); printf("sum is %f",c); } float add(float x, float y) /*函数首部*/ { float z; /*函数体 z=x+y; return(z); 输入:3.6 ,6.5 } 输出:sum is 10.100000 >

C语言程序设计

第七章 函数

?说明: ?旧版本C中函数声明不采用函数原型,只声明 函数名和函数类型。如: float add( ) ?函数调用之前,如果未对函数作声明,则编 void main() #include <stdio.h> char letter(char,char); 译系统把第一次遇到的函数形式作为函数声 { float a,b; float add(float x, float y) float f(float,float); 明,并默认为int型。即:函数类型是 int型可 int c; z; { float int I(float,float); int 型函数可不作函数说明 以不作函数声明,最好作声明。 在函数外面做函数说明 scanf("%f,%f",&a,&b); z=x+y; main() ?被调用函数的定义(程序)在主调函数之前, c=max(a,b); return(z); {……} 被调函数出现在主调函 可以不加函数声明。 } printf("Max is %d\n",c); char letter(char c1,char c2) 数 } main() ?在所有函数定义前,已在函数外部做了函数 {……} 之前,不必函数说明 max(float x, float y) 声明,则在各主调函数中可以不加函数声明。 { float a,b,c; float f(float x,float y) { float z; scanf("%f,%f",&a,&b); {……} z=x>y?x:y; c=add(a,b); Int I(float j,float k) return(z); printf("sum is %f",c); {……} } < >

C语言程序设计

第七章 函数

函数调用的执行过程
main() ① ②

保存: 返回地址 当前现场



fun()


调fun()
⑦ 结束



恢复: 主调程序现场 返回地址



返回

<

>

C语言程序设计

第七章 函数

§7.5 函数的嵌套调用
不允许嵌套定义,函数间的关系是平行的、独立的。

C中的函数:
允许嵌套调用,即在调用某函数过程中又调用另一函数。 main( ) ? 调用函数a ?

a函数
? 调用函数b ? ? ? ?

b函数

?

?
结束

<

>

C语言程序设计

第七章 函数



输入两个整数,求平方和

#include <stdio.h> int fun1(int x,int y); void main(void) { int a,b; scanf(―%d%d‖,&a,&b); printf(―The result is:%d\n‖,fun1(a,b) ); } int fun1(int x,int y) { int fun2(int m); return ( fun2(x)+fun2(y) ); }
int fun2(int m) { return (m*m); } 输入: 3 4 输出: The result is: 25

<

>

C语言程序设计

第七章 函数

例 求三个数中最大数和最小数的差值 #include <stdio.h> int dif(int x,int y,int z) int dif(int x,int y,int z); { return max(x,y,z)-min(x,y,z); } int max(int x,int y,int z); int max(int x,int y,int z) int min(int x,int y,int z); { int r; void main() r=x>y?x:y; { int a,b,c,d; return(r>z?r:z); scanf("%d%d%d",&a,&b,&c); } d=dif(a,b,c); int min(int x,int y,int z) printf("Max-Min=%d\n",d); { int r; } r=x<y?x:y; main( ) dif函数 max函数 return(r<z?r:z); }
调用函数dif 输出 结束 调用函数max 调用函数min min函数

skip

<

>

C语言程序设计

第七章 函数

例7.6 用弦截法求方程 x 3 ? 5x 2 ? 16x ? 80 ? 0 的根
1. 取x1,x2两点,求得f(x1), f(x2) 。 异号:x1,x2之间必有一根。 同号:改变x1, x2,直到f(x1), f(x2)异号为止。 2. 连f(x1),f(x2)两点(弦)交x轴于x。 X点的坐标求法: x ? f ( x ) ? x ? f ( x ) 2 2 1 ①求X点的x坐标 x ? 1 f ( x2 ) ? f ( x1 ) ②从x值得f(x) 3. 若f(x)与f(x1)同号, 则根必在(x,x2)区间,此时将x1=x; 若f(x)与f(x2)同号, 则根必在(x1,x)区间,此时将x2=x;
y

f(x2)

x1

0

x
f(x)

x2 x

f(x1)

4. 重复步骤2和3 ,直到| f(x) | < ε为止, 设ε < 10-6 , 则 f(x)≈0

<

>

C语言程序设计

第七章 函数

用三个函数实现各部分的功能: ① 函数f(x): 求x的函数:x3 - 5x2 +16x-80 ② 函数xpoint(x1,x2): 求弦与x轴交点X的x坐标 ③ 函数root(x1, x2) : root函数 求(x1, x2)区间的实根

输入x1,x2,求f(x1),f(x2)

直到f(x1)与f(x2)异号
求弦与x轴的交点x y=f(x),y1=f(x1) 真 x1=x y1=y y与y1同号 x2=x 假

直到 |y|<?
root=x 输出 root

main( ) 调用函数root

root函数

xpoint函数
调用函数f

f函数

调用函数xpoint

<

>

输出根 x 结束

C语言程序设计

第七章 函数

#include <stdio.h> #include <math.h> float f(float x) { float y; y=((x-5.0)*x+16.0)*x-80.0; return(y); } float xpoint(float x1, float x2) { float y; y=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1)); return(y);}

float root(float x1,float x2) { float x, y, y1; y1=f(x1); do { x=xpoint(x1, x2);y=f(x); if(y*y1 > 0) { y1=y;x1=x;} else x2=x; }while(fabs(y) >=0.0001); return(x); } 运行情况:
Input x1,x2:

void main( ) 2,6? { float x1, x2, f1, f2, x; A root of equation is 5.0000 do { printf(―input x1, x2:\ n‖); scanf(―%f%f‖,&x1,&x2); f1=f(x1); f2=f(x2); }while(f1*f2 >=0); x=root(x1, x2); printf(―A root of equation is %8.4f\ n‖,x); < } >

C语言程序设计

第七章 函数

§7.6 函数的递归调用
递归:在函数调用过程中,直接或间接的调用自身。

?递归调用方式
?直接递归调用:在函数体内又调用自身

int f(int x) { int y,z; …… z=f(y); ……. return(2*z); }

f( )

调f

<

>

C语言程序设计

第七章 函数

?间接递归调用:当函数1去调用另一函数2时,而 另一函数2反过来又调用函数1自身。

int f1(int x) { int y,z; …… z=f2(y); ……. return(2*z); }

int f2(int t) f1( ) { int a,c; …… c=f1(a); ……. return(3+c); 调f2 }

f2( )

调 f1

?解决无终止递归调用的方法是:确定好结束递 归的条件。 条件成立,进行递归 用if语句控制 < > 条件不成立,结束递归

C语言程序设计

第七章 函数

例7.7 有5个人,第5个人比第4个人大2岁,第4个人比第3 个人大2岁,……第2个人比第1个人大2岁,第1个人 10岁,问第5个人多大? 回推 age(5) =2+age(4) =18 age(4) =2+age(3) =16 10 数学模型:age(n)= age(n-1)+2 n>1 运行结果:18 < > age(3) =2+age(2) =14 n=1 age(2) =2+age(1) =12 age(int n) {int c; if(n==1) c=10; else c=2+age(n-1); return(c); } #include <stdio.h> void main( ) {printf(―%d\ n‖, age(5));} =10 递推 age(1)

C语言程序设计

第七章 函数

有些问题,可以用递推,也可以用递归的方法解决。 ?递推:从一个已知的事实出发,按一定规律推出下 一个事实,再从已知的新的事实,推出下一个新的 事实. 例 用递推法求n! ,即从1开始, 乘2, 乘3....一直到n #include <stdio.h> void main( ) { int i, s=1; for(i=1;i<=5;i++) s=s* i; printf(―s=%d\ n‖,s); } < >

运行结果:s=120

C语言程序设计

第七章 函数

?递归:在函数调用自身时,要给出结束递归的条件。 ? 先回推再递推 例7.8 用递归方法求n! ? 如:n!, #include <stdio.h> 5!=5 × 4! void main() 4!=4 × 3! { float fac(int n); 3!=3 × 2! int n; float y; 2!=2 × 1! printf("Input a integer number:"); 1!=1 scanf("%d",&n); 0!=1 y=fac(n); 1 (n=0,1) printf("%d! =%15d",n,y); n!= } n*(n-1)! (n>1) float fac(int n) 运行: { float f; input a integer number:10 if(n<0) printf("n<0,data error!"); 10! = 3628800 else if(n==0||n==1) f=1; else f=fac(n-1)*n; < > return(f);}

C语言程序设计

第七章 函数

例7.9 Hanoi(汉诺)塔问题

十九世纪未,欧洲珍奇商店出现一种汉诺塔游戏,推销材料介 绍说:古代印度布拉玛庙里的僧侣们正在玩这种游戏,如果游戏 结束,世界未日即来临。是一个只能用递归方法解决的问题。 规则及分析: n个盘子从一根针移到另一根针,每次只能移动一个盘子,不允 许大盘在小盘上面。 共有三根针,n个盘子由A移到C,需移动的次数是2n -1, 若64个 盘子移动的次数为: 264 - 1=18, 446, 744, 073, 709, 551, 600 一年的秒数是:365 x 24 x 60 x 60=31536000 18446744073709511600÷31536000 =58494217355年 A B C
即:5849亿年, 从能源角度推算, 太阳系寿命只有150亿年 < >

C语言程序设计

第七章 函数

?方法与步骤
? 将A上n-1个盘子借助C移到B 。 ? 把A上剩下一个盘子送到C ? 将n-1个盘子从B借助A移到C

A

B

C

?简化实例:将A上3个盘子移到C
步骤:1. A上两个盘子借助C移到B 2. A上最后一个盘子移到C (可直接完成) 3. B上两个盘子借助A移到C 第一步进一步分解: 1.1 A上一个盘子从A?C 1.2 A上一个盘子从A?B 1.3 C上一个盘子从C?B 第三步进一步分解: 共移动7步:23-1次 3.1 B上一个盘子从B?A n-1次 所以, n 个盘要移动 2 3.2 B上一个盘子从B?C 3.3 A上一个盘子从A?C

<

>

C语言程序设计

第七章 函数

?结论:上面三个步骤包含两类操作
? 步骤1和3都是将n-1个盘子从一个针移到另一个针上 (n>1时),这是一个递归的过程;方法一样,只是针的 名称不同而已,为使问题一般化,将步骤1和3表示为: 将one 针上的n-1个盘子移到two针,借助 three针,只是 对应关系不同。 第一步对应关系:one ? A two ? B three ? C 第三步对应关系:one ? B two ? C three ? A ? 将1个盘子从一个针上移到另一针上。

?因此,可以用两个函数分别实现上面两类操作, 用hanoi函数实现第一类操作,用move函数实现第 2类操作。
? hanoi(n,one,two,three) 将n个盘从 one → three借助two ? move(x,y) 将1个盘从x → y座,x、y根据情况取代ABC 座中的1个。

<

>

C语言程序设计

第七章 函数

例7.9 用递归方法解决Hanoi(汉诺)塔问题的程序 #include <stdio.h> void main() { void hanoi(int n,char one,char two,char three); int m; 运行: printf("Input the number of diskes:"); input number of diskes: 3? scanf("%d",&m); the step to moving 3 diskes: printf("The step to moving %3d diskes:\n",m); A ?C hanoi(m,'A','B','C');} A ?B void hanoi(int n,char one,char two,char three) C ?B {void move(char x, char y); A ?C B ?A if(n==1) move(one,three); B ?C else { hanoi(n-1,one,three,two); A ?C move(one,three); hanoi(n-1,two,one,three); }} void move(char x, char y) < > { printf("%c--->%c\n",x, y); }

C语言程序设计

第七章 函数

§7.7 数组作为函数参数
?数组元素作函数实参——值传递
例8.10 两个数组比较大小
a b a和b为有10个元素的整型数组 0 12 i 43 0 比较两数组对应元素 1 23 a[i]>b[i], i a[i]==b[i], 变量n,m,k分别记录 的次数。 1 23 a[i]<b[i] 2 认为数组 最后,若n>k, a>b i 56 2 21 若n<k, a<b i 3 认为数组 10 98 3 若n==k, a==b i 76 4 认为数组 66 4 5 n=0 m=0 k=0 88 n=0 m=0 k=1 i n=0 m=1 k=1 54 n=1 m=1 k=1 5 n=1 m=1 k=2 n=2 m=1 k=2 n=3 m=1 k=2

<

>

C语言程序设计

第七章 函数

#include <stdio.h> void main() 运行: { int large(int x,int y) enter array a: int a[10],b[10],i,n=0,m=0,k=0; 1 3 5 7 9 8 6 4 2 0? printf("Enter array a:\n"); enter array b: for(i=0;i<10;i++) scanf("%d",&a[i]); 5 3 8 9 -1 -3 5 6 0 4 ? printf("\n"); a[i] > b[i] 3 time printf("Enter array b:\n"); a[i] = b[i] 1 time for(i=0;i<10;i++) scanf("%d",&b[i]); a[i] < b[i] 1 time printf("\n"); array a is large then array b for(i=0;i<10;i++) large(int x,int y) { if(large(a[i],b[i])==1) n=n+1; { int flag; else if(large(a[i],b[i])==0) m=m+1; if(x>y) flag=1; else k=k+1; } else if(x<y) flag=-1; printf(―a[i]>b[i]%d times\n‖,n); else flag=0; printf(―a[i]=b[i]%d times\n‖,m); return(flag); printf(―a[i]<b[i]%d times\n‖,k); } if(n>k) printf(―array a is larger than array b\n‖); else if(n<k) printf(―array a is smaller than array b\n‖); else printf(―array a is equal to array b\n‖); < > }

C语言程序设计

第七章 函数

?数组名可作函数参数
实参和形参都应用数组名 例7.11 求学生的平均成绩

形参用数组定义?float array[ ]

#include <stdio.h> void main() { float average(float array[10]); float score[10], aver; int i; printf("Input 10 scores: \n"); for( i=0; i<10; i++ ) scanf("%f", &score[i]); printf(―\n‖); aver=average(score); printf("Average is: %5.2f", aver); } < > 实参用数组名

float average(float array[10]) { int i; float aver,sum=array[0]; for( i=1; i<10; i++ ) sum=sum+array[i]; aver=sum/10; return (aver); }
score
0 1 2 . . 9 12 23 56 …. …. 88

array

C语言程序设计

第七章 函数

几点说明: ?地址传递 ?调用函数时,对形参数组元素的操作, 实际上也是对实参数组元素的操作。 ?在主调函数与被调函数分别定义数组,且类 型应一致

?如:array是形参数组名,score是实参数 组名。

<

>

?形参数组大小(多维数组第一维)可不指定

?在定义数组时在数组名后面跟一个空 的方括弧
?C编译对形参数组大小不检查,即使 定义了也不起作用。 ?形参数组名是地址变量 ?调用时,只是将实参数组的首地址传 给形参数组, ? 因此score[n]和array[n]指的是同一单 元

C语言程序设计

第七章 函数

例7.12 求两组学生的平均成绩,形参数组长度缺省
#include <stdio.h> void main() { float average(float array[ ],int n); float score_1[5]={98.5,97,91.5,60,55}; float score_2[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5}; printf(―The average of clase A is %6.2f\n‖,average(score_1,5)); printf(―The average of clase B is %6.2f\n‖,average(score_2,10)); } float average(float array[ ],int n) { int i; 另设一个参数,传递需 float aver,sum=array[0]; 要处理的数组元素个数 for( i=1; i<n; i++ ) sum=sum+array[i]; aver=sum/n; 运行: return (aver); The average of class A is 80.40 } < > The average of class B is 78.20

C语言程序设计

第七章 函数

?数组名作函数参数时,实参和形参 两个数组共占同一段内存单元,形 参数组的元素值改变会使实参数组 元素的值同时变化。

例7.13 用选择法对数组中的10个整数按由小到大排序

<

>

#include <stdio.h> void main() { void sort(int array[ ],int n); int a[10],i; printf(―enter the array\n‖); for(i=0;i<10;i++) scanf("%d",&a[i]); sort(a,10); printf(―the sorted array: \n‖); for(i=0;i<10;i++) printf("%d ",a[i]); printf("\n");}

C语言程序设计

第七章 函数

选择法排序思路

void sort(int array[ ],int n) a { int i,j,k,t; array for(i=0;i<n-1;i++) i=0 { k=i; for(j=i+1;j<n;j++) if(array[j]<array[k]) k=j; t=array[i]; array[i]=array[k]; array[k]=t; } }
< >

49 9 68 57 32 9 49 99 27 13 76 88

0 1 2 3 4 5 6 7 8 9

k j j j j j j j j j

k k

C语言程序设计

第七章 函数

选择法排序思路

void sort(int array[ ],int n) { int i,j,k,t; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(array[j]<array[k]) k=j; t=array[i]; array[i]=array[k]; array[k]=t; } }

a array i=1

49 9 68 13 57 32 9 49 99 27 13 68 76 88

0 1 2 3 4 5 6 7 8 9

k j j j j j j j j

k k k k

<

>

C语言程序设计

第七章 函数

选择法排序思路

void sort(int array[ ],int n) { int i,j,k,t; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(array[j]<array[k]) k=j; t=array[i]; array[i]=array[k]; array[k]=t; } }

a array i=8

9 13 27 32 49 57 68 76 88 99

0 1 2 3 4 5 6 7 8 9

<

>

C语言程序设计

第七章 函数

? 用多维数组名作函数参数 ?可以用多维数组名作实参和形参 ?形参数组定义时,只能省略第一维的大小说明。 ?C编译不检查第一维的大小,而且数组名作 函数参数是地址传送,所以形参数组第一维 大小任意,可以和实参数组的维数不同。 实参数组定义:int score[5][10] 形参数组定义:int array[3][10] 或 int array[8][10] ?合法的定义:int array[3][10]; 或 int array[ ][10] ?错误的定义:int array[ ][ ]; int array[3][ ]; < >

C语言程序设计

第七章 函数

例7.14 求3×4矩阵中各元素的最大值 #include <stdio.h> void main() {int max_value(int array[ ][4]); int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}}; printf("max value is %d\n",max_value(a)); } int max_value(int array[3][4]) { int i,j,k,max; 多维形参数组第一维维数 max=array[0][0]; 可省略,第二维必须相同 for(i=0;i<3;i++) ? int array[][4] for(j=0;j<4;j++) if(array[i][j]>max) max=array[i][j]; return(max); } >

<

C语言程序设计

第七章 函数

例 求二维数组中各行元素之和

get_sum_row(int x[][3], int result[] ,int row, int col) { int i,j; for(i=0;i<row;i++) { result[i]=0; for(j=0;j<col;j++) result[i]+=x[i][j];} result } a sum_row main() 18 3 6 9 x { int a[2][3]={3,6,9,1,4,7}; 12 1 4 7 int sum_row[2],row=2,col=3,i; get_sum_row(a,sum_row,row,col); for(i=0;i<row;i++) printf("The sum of row[%d]=%d\n",i+1,sum_row[i]); }
< >

C语言程序设计

第七章 函数

§7.8 局部变量和全局变量
变量按其作用域,可分为局部变量和全局变量。 ? 局部变量——内部变量 ?定义:在函数内定义,只在本函数内有效 ?说明: ?main中定义的变量只在main中有效 ?不同函数中同名变量,占不同内存单元 ?形参属于局部变量 ?可定义在复合语句中有效的变量 ?局部变量可用存储类型:auto register static (默认为auto) < >

C语言程序设计

第七章 函数

例 不同函数中同名变量
float f1(int a) { int b,c; ……. } a,b,c有效

char f2(int x,int y) { int i,j; x,y,i,j有效 …… } main() { int m,n; ……. }

m,n有效

<

>

void main() { int a,b; a=3; b=4; printf("main:a=%d,b=%d\n",a,b); sub(); printf("main:a=%d,b=%d\n",a,b); } 运行结果: sub() main:a=3,b=4 { int a,b; sub:a=6,b=7 main:a=3,b=4 a=6; b=7; printf("sub:a=%d,b=%d\n",a,b); }

C语言程序设计

第七章 函数

例 复合语句中变量
main() { int a, b; ┇ { int c; c=a+b; c 范围 a,b 范围 ┇ } ┇ }

#define N 5 void main() { int i; int a[N]={1,2,3,4,5}; for(i=0;i<N/2;i++) { int temp; temp=a[i]; a[i]=a[N-i-1]; a[N-i-1]=temp; } for(i=0;i<N;i++) printf("%d ",a[i]); }
运行结果:5 4 3 2 1

<

>

C语言程序设计

第七章 函数

?全局变量——外部变量 ?定义:在函数外定义,可为本文件所有 函数共用,也叫外部变量。 ?有效范围:从定义变量的位臵开始到本 源文件结束,及有extern说明的其它源文 件 ?几点说明: ?全局变量的使用,增加了函数间数据联 系的渠道,同一文件中的所有函数都能 引用全局变量的值,当某函数改变了全 局变量的值时,便会影响其它的函数。
< >

?习惯上,全局变量名的第一个字母用 大写。 ?使用全局变量可以减少函数的实参和 形参个数。 ?不必要时不要使用全局变量 ?全局变量在程序执行的全过程都占 用存储单元。 ?不利于程序的移植。程序的可读性 变差。 ?全局与局部变量重名时,在函数内部 将屏蔽全局变量。

C语言程序设计

第七章 函数

<

>

int p=1,q=5; float f1(a) int a; { int b,c; ……. } int f3() {….. } char c1,c2; char f2(int x,int y) { int i,j; …… } main() { int m,n; ……. }

p,q的作用范围

c1,c2的作用范围

C语言程序设计

第七章 函数

例 全局变量的作用域及其使用情况 int a=1; f1( ) {int b; b=a+3; printf(―f1:a=%d, b=%d\ n‖,a, b); } f2( ) {int a, b; a=5; b=a+3; printf(―f2: a=%d, b=%d\ n‖,a, b); } 局部变量和全局变量 f3( ) {int b; a=6; b=a+3; printf(―f3:a=%d, b=%d\ n‖,a, b); } 同名,局部变量作用 void main( ) 域中外部变量被屏蔽 外部变量 局部变量 { int b=3; printf(―1.main : a=%d, b=%d\ n‖,a, b); f1( ); printf(―2.main : a=%d, b=%d\ n‖,a, b); f2( ); 运行: printf(―3.main : a=%d, b=%d\ n‖,a, b); f3( ); 1.main:a=1, b=3 f1:a=1, b=4 printf(―4.main : a=%d, b=%d\ n‖,a, b); 2.main:a=1, b=3 } 全局变量增加了函数 f2:a=5, b=8 间传送数据的联系 3.main:a=5, b=3 f3:a=6, b=9 4.main:a=6, b=3 < >

C语言程序设计

第七章 函数

#include <stdio.h> 例7.15 float Max=0,Min=0; 一维数组内存放了10个学 void main() 生成绩,求平均分、最高 { float average(float array[ ],int n); int i; float ave,score[10]; 分和最低分。 for(i=0;i<10;i++) scanf("%f",&score[i]); ave=average(score,10); 全局变量 printf("max=%6.2f\nmin=%6.2f\n 运行: input 10 numbers: Max Min average=%6.2f\n",Max,Min,ave); main 99 45 函数 78 97 100 67.5 89 92 66 43? } max=100.00 float average(float array[], int n) ave score 10 Max Min min=43.00 { int i; average=77.65 float aver, sum=array[0]; Max=Min=array[0]; aver array n Max Min for(i=1;i<n;i++) average { if(array[i]>Max) Max=array[i]; 函数 else if(array[i]<Min) Min=array[i]; sum=sum+array[i]; } aver=sum/n; < > return(aver);}

C语言程序设计

第七章 函数

例7.16 外部变量与局部变量同名 #include <stdio.h> int a=3,b=5; void main() { int max(int a, int b); int a=8; 原意输出5行*号,使用外部 printf("max=%d",max(a,b)); 变量i 后只输出一行*号。 } int max(int a, int b) { int c; c=a>b?a:b; 局部变量a=8将外 return(c); 部变量a=3屏蔽 } 运行结果:max=8 < >

例 外部变量副作用

int i; main() { void prt(); for(i=0;i<5;i++) prt(); } void prt() { for(i=0;i<5;i++) printf(―%c‖,‘*‘); printf(―\n‖); }
运行结果:*****

C语言程序设计

第七章 函数

§7.9 变量的存储类别
? 动态存储方式与静态存储方式 ?变量分类:
? 按数据类型:整型、实型、字符型 ? 按作用域:全局变量、局部变量 ? 存储方式: ?静态存储:程序运行期间分配固定的存储空间。 ?动态存储:程序运行期间根据需要动态分配存储空间。

?内存用户区 ?生存期: 程序区 ? 静态变量:从程序开始执行到程序结束
? 动态变量:从包含该变量定义的函数开始执行至函数执行结束 全局变量、局部静态变量

静态存储区

<

>

动态存储区

形参变量 局部动态变量(auto register) 函数调用现场保护和返回地址等

C语言程序设计

第七章 函数

?auto变量
?函数内部无static声明的局部变量均为动态存储 类别,被分配在动态区 。 ?存储类别为自动时,声明符auto可省;自动变 量被 分配在动态区,未赋初值时,其值未定义, 每次调用重新赋值。 例如: int f(int a) /*定义f函数,a为形参*/ {auto int b,c=3; /*定义b、c为自动变量*/ … } 又如:auto int b,c=3; int b,c=3; /*两者等价*/ < >

C语言程序设计

第七章 函数

例 auto 变量的作用域
main() { int x=1; void prt(void); { int x=3; prt(); printf(―2nd x=%d\n‖,x); } printf(―1st x=%d\n‖,x); } void prt(void) { int x=5; printf(―3th x=%d\n‖,x); } < >

x=1作用域 x=3作用域 x=1作用域

运行结果: 3th x=5 2nd x=3 1st x=1

x=5作用域

C语言程序设计

第七章 函数

?用static声明局部变量
若希望函数调用结束后,局部变量的值保留,则指 定该变量为静态局部变量,用static对变量加以声明。 例 局部静态变量值具有可继承性 main() { void increment(void); 运行结果:1 increment(); 1 increment(); 1 increment(); } void increment(void) { int x=0; x++; printf(―%d\n‖,x); < > } main() { void increment(void); increment(); increment(); 运行结果:1 2 increment(); 3 } void increment(void) { static int x=0; x++; printf(―%d\n‖,x); }

C语言程序设计

第七章 函数

例7.17 考察静态局部变量的值 #include <stdio.h> void main( ) { int f(int) ; int a=2, i; for(i=0; i<3; i++) printf(―%d ‖, f(a)); } int f(int a) { auto b=0; static c=3; b=b+1; c=c+1; return(a + b + c); } 运行结果:7 8 9 < >
main( ) i a f(a) 0 2 f(2) 1 2 f(2) 2 2 f(2)

f(a) a b 2 0 1 2 0 1 2 0 1

c return(a+b+c) 3 4 return(7) 4 5 return(8) 5 6 return(9)

对静态局部变量的说明:
⑴分配在静态区,程序运行结束释放存储单元。 ⑵赋初值一次未赋初值时为0,前次结果保留。

⑶局部动态变量若未赋初值,其值不确定,局部 静态变量未赋初值,其值为0或‘\0‘(字符变量) 。
⑷静态局部变量在函数调用结束后虽存在,但其 它函数不能引用它。

C语言程序设计

第七章 函数

使用局部静态变量的场合
(1)需要保留上一次调用结束时的值 例7.18 打印1到5的阶乘值
main( ) i fac(i) 1 fac(1) 2 fac(2) 3 fac(3) 4 fac(4) 5 fac(5) fac(n) 输出结果 n f=f*n f=1 1 f=1*1 1!=1 2 f=1*2=2 2!=2 3 f=2*3=6 3!=6 4 f=6*4=24 4!=24 5 f=24*5=24 5!=120

#include <stdio.h> void main( ) {int fac(int n); int i; for(i=1; i<=5; i++) printf(―%d != %d\n‖, i, fac(i)); } int fac(int n) { static int f=1; f=f*n; return(f); }

(2)初始化后变量只被引用 而不改变其值,则用静 态局部变量较方便,以 免每次调用时重新赋值, 但会一直占用内存浪费 系统资源。 < >

C语言程序设计

第七章 函数

?register(寄存器型)变量
CPU内有寄存器可用来存放数据,若把数据声明为寄 存器类型,则将该类型的数据存放在寄存器中,其优点是: 减少数据与内存之间的交换频率,提高程序的效率和速度。 例7.19 使用寄存器变量

#include <stdio.h> void main( ) 运行结果: { long fac(long); 1!=1 long i, n; 2!=2 scanf(―%ld‖,&n); 3!=6 for(i=1; i<=n; i++) 4 ! = 24 printf(―%ld != %ld\ n‖, i, fac(i));} 5 ! = 120 long fac(long n) { register long i, f=1; for(i=1; i<=n; i++) < > f=f * i; return(f); }

CPU 寄存器组

内存

C语言程序设计

第七章 函数

寄存器类型变量的几点说明:
1. 局部自动变量类型和形参可定义为寄存器变量。 2. 不同C系统对寄存器的使用个数,对register变量的处 理方法不同,对寄存器变量的数据类型有限制。 3. 局部静态变量不能定义为寄存器变量。 4. long,double,float不能设为register型,因为超过寄存器 长度

<

>

C语言程序设计

第七章 函数

?用extern声明外部变量
外部变量也称全局变量,在函数外部定义,其作用域是从变量 的定义处开始,到本程序文件的未尾。在定义的作用域内,全局变 量可为程序中各个函数所引用。 可以用extern声明外部变量,以扩展外部变量的作用域。

<

? 在一个文件内声明外部变量 int max(int x, int y) 例 8.20 用extern声明外 ? 外部变量没在文件开头定义,其作用域为定义处到文 { int z; 部变量,扩展作用域 件结束。定义处之前的函数要使用,则在引用前用关 z=x>y ? x:y; 键字extern作?外部变量声明?。 return(z); 运行结果: 一般应将外部变量定义 } 13 放在程序最前面,从而 main( ) 省去extern声明 { extern int A,B; printf(―%d‖,max(A,B)); 可以省略为: } int A=13,B=-8; extern A,B; >

C语言程序设计

第七章 函数

例 用extern扩展作用域

运行结果: 1: x=0 y=0 2: x=135 y=246 3: x=135 y=246

<

>

main() { void gx(),gy(); extern int X,Y; printf(―1: x=%d\ty=%d\n‖,X,Y); Y=246; gx(); gy(); } void gx() { extern int X,Y; X=135; printf(―2: x=%d\ty=%d\n‖,X,Y); } int X,Y; void gy() { printf(―3: x=%d\ty=%d\n‖,X,Y); }

C语言程序设计

第七章 函数

?在多文件的程序中声明外部变量
? 如果一个程序由多个文件组成,而一个外部变量需要 在几个文件中引用,此时,可以在任一文件中定义该 外部变量,在其它文件中用extern加以声明 ? 若在每个文件中都定义该外部变量,则系统将提示 定义 ?重定义类型错?

定义

int global; extern float x; main() { int local; ┇ } file1.c < >

extern int global; static int number; func1() { ┇ }

float x; static int number; func2() { extern int global; ┇ } file3.c

声明

file2.c

声明

C语言程序设计

第七章 函数

例7.21 用extern将外部变量的作用域扩展到其它文件 程序的作用是给定b的值,输入a和m,求a×b和am的值。 #include <stdio.h> /*文件file1.c*/ int A; void main() { int power(int); int b=3,c,d,m; printf("Enter the number a and its power m:\n"); scanf("%d,%d",&A,&m); /*文件file2.c*/ c=A*b; extern A; printf("%d*%d=%d\n",A,b,c); int power(int n) d=power(m); { int i,y=1; printf("%d**%d=%d",A,m,d); for(i=1;i<=n;i++) } y*=A; return(y); < > }

C语言程序设计

第七章 函数

?用static声明外部变量
? 如果外部变量只允许本文件使用,不允许其它文件引 用,则定义时加static声明。称为?静态外部变量? ? 只在工程方法中有效,在文件包含中则不起作用 ? 常用于多人编同一程序,又使用同名变量时 ? 加或不加static声明的外部变量都是静态存储,但其作 用域不同

int global; extern float x; main() { int local; ┇ } file1.c < >

extern int global; static int number; func1() { ┇ } file2.c

float x; static int number; func2() { extern int global; ┇ } file3.c

C语言程序设计

第七章 函数

/*文件file1.c*/ #include ―file2.c‖ static int A; main( ) { A=5; printf(―A1=%d\ n‖, A); f1( ); printf(―A4=%d\ n‖,A); } /*文件file2.c */ extern int A; f1( ) { printf(―A2=%d\ n‖,A); A=A* A;printf(―A3=%d\ n‖,A); }

说明: A1=5 A2=5 A3=25 A4=25 如果file3.prj内容:file1.c file2.c 此时若有static 则编译指出: A不可被引用

<

>

⑴在运行file1.c时,无论有无static,其结 果都一样。 ⑵如果标识符A在file2.c中无定义, 也 可无static,这是因为用文件包含 的方法,相当把file2.c包含进file1.c 中来,使其成为file1.c的一部分了. (2)若用工程的方法,则在file1.c中去掉 #include ―file2.c‖ ,建立工程文件 file3.prj

C语言程序设计

第七章 函数

?关于变量的声明和定义
?函数:由?声明部分?和?执行语句?组成 ?声明部分:
? 对有关的标识符(变量,函数,结构体)的属性进行说明, 对于函数,声明和定义区别明显,声明是函数原型, 定义是函数本身,是一个独立的程序模块;

?变量的声明有两种情况
? 定义性声明:需建立存储空间,如int a;也称定义。 ? 引用性声明:不建立存储空间,如extern A ? 外部变量?定义性声明?只能一次,?引用性声明? 多次。 广义地讲,声明包括定义,但并非所有的声明都是定义; 如:int A;既包含声明又包含定义; extern A;只是声明,而无定义。 约定:建立存储空间的声明称定义;

<

>

不建立存储空间的声明称声明。

C语言程序设计

第七章 函数

?Static定义性声明变量作用二个:
? 局部变量用static定义性声明,分配的存储空间在程序 执行期间始终存在,但作用域 只限定义它的函数或分 程序。 ? 全局变量用static定义性声明,变量的作用域仅限本文 件模块

?Auto,register,static是在定义变量的基础上加上 这些关键字,不能单独作用。

<

>

C语言程序设计

第七章 函数

?存储类别小结
局部变量 存储类别 auto register 局部static 外部变量 外部static 外部

存储方式 动态 静态 存储区 动态区 寄存器 静态存储区 程序整个运行期间 生存期 函数调用开始至结束 作用域 定义变量的函数或复合语句内 本文件 其它文件 赋初值 每次函数调用时 编译时赋初值,只赋一次
未赋初值 不确定 自动赋初值0或空字符 ?局部变量默认为auto型 ?register型变量个数受限,且不能为long, double, float型 ?局部static变量具有全局寿命、局部可见性和可继承性 ?extern不是变量定义,可扩展外部变量作用域 < >

C语言程序设计

第七章 函数

例 文件file1.c int a; main( ) { ……. ……. f2; ……. a作用域 f1; a生存期: ……. } b生存期: f1( ) c生存期: { auto int b; ……… b作用域 f2; …….. } f2( ) { static int c; c作用域 ……… }

main

f2

main

f1

f2

f1

main

<

>

C语言程序设计

第七章 函数

§7.10 内部函数和外部函数
根据函数能否被其它源文件调用,将函数分为内 部函数和外部函数。

?内部函数——静态函数
?只能被本文件中其它函数所调用 ?定义形式: static 类型标识符 函数名(形参表) 如: static int fun(int a, int b) ?内部函数,其作用域仅限于定义它的所在文件。 此时,在其它的文件中可以有相同的函数名, 它们相互之间互不干扰。

<

>

C语言程序设计

第七章 函数

?外部函数
?能被其它文件中的函数所调用 ?定义形式: extern 类型标识符 函数名(形参表) 如:extern int fun(int a, int b) ?省略extern,隐含为外部函数 ?调用此函数的文件中也要用extern声明所用函数 是外部函数 skip 例7.22 有一个字符串,内有若干个字符,今输入一个字符, 要求程序将字符串中该字符删去。用外部函数实现。
分析:该问题可以用四个函数解决。 主函数main( ) , 删除字符函数delete_char( ) , 输入字符串函数enter_str( ) ,输出新字符串函数print_str( ) , 将各函数放入四个文件,用extern声明实现各文件中函数的调用。

<

>

C语言程序设计

第七章 函数

初始 删除后 /*文件file1.c*/ a a str[0] #include"file2.c" b b str[1] #include"file3.c" c d str[2] #include"file4.c" c \0 str[3] #include <stdio.h> d d str[4] c c str[5] void main() \0 \0 str[6] { extern enter_string(char str[80] ), ┇ ┇ ┇ extern delete_string(char str[],char ch ), \0 \0 str[79] extern print_string(char str[ ] ); i j str[i] !=?c‘ str[i] ← str[j++] char c; 0 0 str[0] !=?c‘ str[0] ← str[0]=a char str[80]; 1 enter_string(str); 1 2 str[1] !=?c‘ str[1] ← str[1]=b 2 str[2] !=?c‘ scanf(―%c‖,&c); 3 str[3] !=?c‘ delete_string(str,c); 4 3 str[4] !=?c‘ str[2] ← str[4]=d print_string(str); 5 str[5] !=?c‘ } ┇┇ ┇

<

>

79

str[79] !=?c‘ str[3] ← ?\0‘

C语言程序设计

第七章 函数

/*文件file2.c*/ #include ―stdio.h‖ void enter_string(char str[80]) { gets(str); }

输入: abccdc? c? 输出:abd

初始 删除后

/*文件file3.c*/ #include <stdio.h> void delete_string(char str[ ],char ch) { int i, j; for(i=j=0; str[i] !='\0' ; i++) if(str[i] != ch) str[j++]=str[i]; str[j]='\0'; } /*文件file4.c*/ #include <stdio.h> void print_string(char str[ ]) < > { printf(―%s‖,str);}

a b c c d c \0 ┇ \0

a b d \0 d c \0 ┇ \0

str[0] str[1] str[2] str[3] str[4] str[5] str[6] ┇ str[79]

i j str[i] !=?c‘ str[i] ← str[j++] 0 0 str[0] !=?c‘ str[0] ← str[0]=a 1 1 2 str[1] !=?c‘ str[1] ← str[1]=b 2 str[2] !=?c‘ 3 str[3] !=?c‘ 4 3 str[4] !=?c‘ str[2] ← str[4]=d 5 str[5] !=?c‘ ┇┇ ┇ 79 str[79] !=?c‘ str[3] ← ?\0‘

C语言程序设计

第七章 函数

§7.11 如何运行一个多文件的程序
?用Turbo C集成环境
?工程方法
? 建立工程文件名.prj,其中包含一个程序的各文件名 如:file1.c file2.c file3.c file4.c ? 在工程菜单项中设立工程文件名 ? 运行工程文件,按F9编译,再ctrl+F9运行。

?文件包含方法
? 在主函数的头部将本程序各文件用#include ―文件名.c‖ ? 运行该程序

<

>

C语言程序设计

第七章 函数

本章小结
? 函数包含一系列程序语句,它们被集中在一起并给它们起 一个名字; ? 每一个函数在被调用之前必须声明; ? 每一个函数都必须有一个相应于其原型的函数实现,给出 该函数的具体细节; ? 一个有返回值的函数一定要返回一个与其声明时类型相匹 配的值; ? 一个void型的函数没有任何返回值; ? 在函数内部定义的变量,包括函数的形式参数都是局部变 量,它们在函数的外部是不可见的; ? 当函数返回时,它精确地回到它被调用的那一点; ? 一般运用逐步求精的方法,从主函数开始逐步实现各个功 能函数。 < >

C语言程序设计

第九章 预处理命令

第9章 预处理命令
宏定义
―文件包含”处理 条件编译

C语言程序设计

第九章 预处理命令

?编译:对源程序进行词法、语法分析,生成 代码,优化等。 ?作用:在编译之前,对源程序中的特殊命令 做一些处理,生成扩展C源程序 ?种类:
?宏定义 ?文件包含 ?条件编译 #define #include #if #else #endif等

?格式:
??#‖开头 ?占单独书写行 ?语句尾不加分号 < >

C语言程序设计

第九章 预处理命令

§9.1 宏定义

宏定义命令

?不带参数的宏定义

宏体可缺省,表示宏名 定义过或取消宏体

?一般形式: #define 标识符 字符串 ?功能:用指定标识符(宏名)代替字符串序列(宏体)

<

>

如 #define 例YES 1 #define YES 1 #define NO 0 main() #define PI 3.1415926 { …….. YES原作用域 #define OUT printf(―Hello,World‖); } #undef YES ?定义位臵:任意(一般在函数外面) #define YES 0 ?作用域:从定义命令到文件结束 max() YES新作用域 ?#undef可终止宏名作用域 {…….. 格式: #undef } 宏名

C语言程序设计

第九章 预处理命令

例9.1 使用不带参数的宏定义 #include <stdio.h> 运行: input radius: 4? #define PI 3.1415926 l=25.1328 void main() s=50.2655 { float l,s,r,v; v=150.7966 printf("input radius : "); scanf("%f",&r); l=2.0*PI*r; s=PI*r*r; v=4.0/3.0*PI*r*r*r; printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v); }
?宏名一般用大写字母,与变量区别。 ?使用宏便于修改变量值,提高程序通用性。 < > 例 #define ARRAY_SIZE 1000 int array[ARRAY_SIZE] ;

C语言程序设计

第九章 预处理命令

?宏展开:预编译时,用宏体替换宏名---不作语法检查 if(x==YES) printf(―correct!\n‖); else if (x==NO) printf(―error!\n‖); 展开后: if(x==1) printf(―correct!\n‖); else if (x==0) printf(―error!\n‖); 如

?引号中的内容与宏名相同也不臵换
例 #define PI 3.14159 printf(―2*PI=%f\n‖,PI*2); 宏展开:printf(―2*PI=%f\n‖,3.14159*2); ?宏定义中使用必要的括号() 例 #define WIDTH 80 #define LENGTH (WIDTH+40) var=LENGTH*2; 宏展开:var= (80+40) *2;

<

>

C语言程序设计

第九章 预处理命令

?宏定义可嵌套,不能递归

例 #define WIDTH 80 #define LENGTH WIDTH+40 var=LENGTH*2; 宏展开:var= 80+40 *2; 例 #define MAX MAX+10 (? )

<

>

例9.2 在宏定义中引用已定义的宏名 #include <stdio.h> #define R 3.0 #define PI 3.1415926 #define L 2*PI*R 运行: #define S PI*R*R L=18.849556 void main() { printf("L=%f\nS=%f\n",L,S);} S=28.274333

C语言程序设计

第九章 预处理命令

?带参数的宏定义
?一般形式: #define 宏名(参数表) 宏体 ?功能:进行字符串替换,并进行参数替换 例 #define S(a,b) a*b ……….. 不能加空格 area=S(3,2); 宏展开: area=3*2; ?宏展开:形参用实参换,其它字符保留 ?宏体及各形参外一般应加括号() 例#define #define SPOWER(x) 例 (r) PI*r*r x*x x=4; y=6; 相当于定义了不带参宏 S,代表字符串?(r) PI*r*r‖ z=POWER(x+y); 宏展开:z=x+y*x+y; > 一般写成: #define POWER(x) ((x)*(x)) 宏展开: z=((x+y)*(x+y));

<

C语言程序设计

第九章 预处理命令

例9.3 使用带参数的宏 #include <stdio.h> #define PI 3.1415926 #define S(r) PI*r*r void main() { float a,area; a=3.6; area=S(a); printf("r=%f\narea=%f\n",a,area); }
?带参宏定义与函数的区别

运行: r=3.600000 area=40.715038

<

>

? 函数调用时,先求实参表达式的值,再带入形参。 宏只进行简单字符替换,不求值。 ? 函数调用在程序运行时处理和分配临时内存单元。 宏展开在编译时进行,不分配内存单元,无值传递和返值。 ? 函数要定义形实参且类型一致,宏无类型,其参数无类型。 ? 函数只有一个返回值,宏可以设法得到几个结果。

C语言程序设计

第九章 预处理命令

例9.4 使用宏带回几个结果 #include <stdio.h> #define PI 3.1415926 #define CIRCLE(R,L,S,V) L=2*PI*R;S=PI*R*R; V=4.0/3.0*PI*R*R*R void main() { float r,l,s,v; scanf("%f",&r); CIRCLE(r,l,s,v); printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v); } §9.1 数组作为函数参数 运行: 宏展开后: ?在函数调用过程中,直接或间接的调用自身。 3.5 ? void main() ?递归调用方式 r=3.50,l=21.99,s=38.48,v=179.59 { float r,l,s,v; scanf("%f",&r); ?直接递归调用:在函数体内又调用自身 l=2*3.1415926*r;s=3.1415926*r*r;v=4.0/3.0*3.1415926*r*r*r; < > printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v);}

C语言程序设计

第九章 预处理命令

? 宏展开使源程序变长,函数调用源程序不变长。 ? 宏替换不占运行时间,只占编译时间。 函数调用占运行时间。

例 用宏定义和函数实现同样的功能 #define MAX(x,y) (x)>(y)?(x):(y) ……. main() { int a,b,c,d,t; ……. t=MAX(a+b,c+d); …… } 宏展开:t=(a+b)>(c+d)?(a+b):(c+d); < > int max(int x,int y) { return(x>y?x:y); } main() { int a,b,c,d,t; ……. t=max(a+b,c+d); ……… }

C语言程序设计

第九章 预处理命令

例9.5 用宏代表输出格式 #include <stdio.h> #define PR printf #define NL "\n" #define D "%d" #define D1 D NL #define D2 D D NL #define D3 D D D NL #define D4 D D D D NL #define S "%s"

void main() { int a,b,c,d; char string[]="CHINA"; a=1;b=2;c=3;d=4; PR(D1,a); PR(D2,a,b); PR(D3,a,b,c); PR(D4,a,b,c,d); PR(S,string); } 运行结果: 1 12 123 1234 CHINA

<

>

C语言程序设计

第九章 预处理命令

§9.2 “文件包含?处理 <> 直接按标准目录搜索
“ ” 先在当前目录搜索,再搜索标准目录 ?功能:一个源文件可将另一个源文件的内容 可指定路径 全部包含进来 ?一般形式: #include ―文件名? 或 #include <文件名> ?处理过程:预编译时,用被包含文件的内容取 代该预处理命令,再将?包含?后的文件作 为一个源文件单位进行编译,得目标文件.obj
#include ―file2.c‖ file2.c

B A
A file2.c file1.c file1.c

<

>

C语言程序设计

第九章 预处理命令

例9.6 将例9.5改为文件包含 ⑴ 格式宏做成头文件format.h #define PR printf #define NL "\n" #define D "%d" #define D1 D NL #define D2 D D NL #define D3 D D D NL #define D4 D D D D NL #define S "%s"
运行结果: 1 12 123 1234 CHINA

⑵ 主文件file1.c #include <stdio.h> #include "format.h" void main() { int a,b,c,d; char string[]="CHINA"; a=1;b=2;c=3;d=4; PR(D1,a); PR(D2,a,b); PR(D3,a,b,c); PR(D4,a,b,c,d); PR(S,string); }

<

>

C语言程序设计

第九章 预处理命令

?被包含文件内容
?源文件(*.c) ?头文件(*.h)

宏定义 数据结构定义 函数说明等

B file2.c

C

?文件包含可嵌套
#include ―file2.c‖
A file1.c

file3.c

#include ―file3.c‖ C
B file3.c file2.c

#include ―file3.c‖ #include ―file2.c‖

A
file1.c

?预编译后已成为一个文件,因此file2.c中的全局 静态变量在file1.c中有效,不必再用extern声明。
< >

C语言程序设计

第九章 预处理命令

§9.3 条件编译
?功能:当文件中的部分内容在满足一定条件 才进行编译 #ifdef 标识符 ?几种形式: 程序段1
?形式1:
? 标识符已被#define命令 定义过,则编译程序段1, 反之编译程序段2

#else 程序段2 #endif

可以没有

<

>

例例 调试信息的输出 适应16位或32位计算机 #define #ifdef DEBUG COMPUTER_A ┆ INTEGER_SIZE 16 #define #ifdef DEBUG #else printf("x=%d,y=%d,z=%d\n",x,y,z); #define INTEGER_SIZE 32 #endif #endif

C语言程序设计

第九章 预处理命令

?形式2:
? 与形式1相反,标识符未被#define命令定义过,则编译 程序段1,反之编译程序段2

#ifndef 标识符 程序段1 #else 程序段2 #endif ?形式3:
? 表达式为真,则编译程序段1,反之编译程序段2

<

>

#if 表达式 程序段1 #else 程序段2 #endif

C语言程序设计

第九章 预处理命令

例9.7 输入字符串,根据需要设臵条件编译, 使字母改为大写或小写 #include <stdio.h> #define LETTER 1 /* 1大写,0小写 */ void main() { char str[20]="C Language",c; int i=0; while((c=str[I])!='\0') { i++; #if LETTER if(c>='a'&&c<='z') c=c-32; #else if(c>='A'&&c<='Z') c=c+32; #endif printf("%c",c);} printf(―\n"); }

<

>

C语言程序设计

第九章 预处理命令

?本章要求
?熟悉宏定义与宏展开的区别,宏与函数的区别。 ?熟悉文件包含命令#include的作用及预处理方法。 ?熟悉条件编译的使用。

?课后作业
?9.1,9.10,(读9.6题答案) ?9.5,9.9

?上机:实验8 ?预习:第10章 指针(重点、难点)

<

>

C语言程序设计

第八章 指针

第8章 指针-灵活多变
地址和指针的概念

变量的指针和指向变量的指针变量
数组与指针 字符串与指针 指向函数的指针 返回指针值的函数 指针数组和指向指针的指针 有关指针的数组类型和指针运算的小结

C语言程序设计

第八章 指针

?本章学习目标:
?认识到用地址作为一种数据类型的重要性。 ?理解指针包括地址和类型两种属性。 ?掌握指针运算符&和*。 ?能够通过地址引用调用在被调函数与主调函数之 间共享数据。 ?理解指针和数组的关系。 ?理解指向函数的指针的用法。

?C程序设计中使用指针可以:
?使程序简洁、紧凑、高效 ?有效地表示复杂的数据结构 ?动态分配内存,直接访问内存地址 > ?得到多于一个的函数返回值

<

C语言程序设计

第八章 指针

§8.1 地址和指针的概念
在程序中定义一个变量,在编译时就给 这个变量分配一个内存单元,同时根据 变量的类型决定这个内存单元的大小。 如:整型2字节,实型4字节。 2000
内存中每一个字节都有一个编号, 就是?地址?。
2002

内存用户数据区

3 6

变量 i 变量 j

3010

2000

变量 i_pointer

对每一个变量,它在内存中都有一个 存储位臵,这个位臵就是该变量的地址, 对变量值的存取是通过地址进行。 在C语言中这个地址被形象化地称为?指针?。 < > 指针:一个变量的地址。 指针变量:存放另一变量的地址(即指针)。

C语言程序设计

第八章 指针

8.2 变量的指针和指向变量的指针变量 ?定义一个指针变量
指针变量在使用前必须定义,使其指向特定类型 的变量,指针变量存放地址,必须定义为?指针类 型?。 ?定义的一般形式:基类型 *指针变量名; 例 int *p1,*p2; ? 基类型:用来指定指针变量可以指向的变量的类型。 float *q ; 将决定指针移动和运算时的移动量。 static char *name; 构成:[存储类型] 数据类型 注意: ? * :表示该变量为指针类型 1、int *p1, *p2; 与 int *p1, p2; 2、指针变量名是p1,p2 ,不是*p1,*p2 3、指针变量只能指向定义时所规定类型的变量 4、指针变量定义后,变量值不确定,应用前必须先赋值 < >

C语言程序设计

第八章 指针

?进一步理解&与*运算符:
指针运算符(?间接访问?运算符) 取地址运算符 i_pointer ?两者关系:互为逆运算 含义: 取指针所指向变量的内容 含义: 取变量的地址 单目运算符 &i_pointer 2000 单目运算符 ?理解 优先级: 2 优先级: 2 结合性:自右向左 结合性:自右向左

?含义

*i_pointer 10 i

…...

2000 2001 2002 2003 2004 2005 2006

整型变量i

10

i_pointer &i &(*i_pointer) i_pointer = &i = &(*i_pointer) i i = *i_pointer *(&i) *i_pointer = *(&i)
变量i_pointer

2000

指针变量

<

>

i_pointer-----指针变量,它的内容是地址量 *i_pointer----指针的目标变量,它的内容是数据 &i_pointer---指针变量占用内存的地址
…...

C语言程序设计

第八章 指针

?指针变量的初始化
一般形式:[存储类型] 数据类型 *指针名=初始地址值; 例 int i; int *p=&i;



例 int i; int *p=&i; int *p=&i; int i; int *q=p;
例 main( ) { int i; static int ..............

指针变量赋值: 赋给指针变量, int i, j; 不是赋给目标变量 int *p1, *p2; 变量必须已说明过 p1=&i; p2=&j ; 类型应一致 i=3; *p1=5; j=6; *p2=8;

<

>

}

2000 3 5 i 用已初始化指针变量作初值 2002 6 8 j ┇ *p=&i; 2000 p1 2002 p2 不能用auto变量的地址 (? ) 去初始化static型指针

C语言程序设计

第八章 指针

?指针变量的引用
例8.1 通过指针变量访问整型变量 运行结果: #include <stdio.h> a=100, b=10 void main( ) *p1=100, *p2=10 {int a, b, *p1, *p2 ; &a=ffd4, &b=ffd6 p1=ffd4, p2=ffd6 a=100; b=10; &p1=ffd8, &p2=ffda p1=&a; p2=&b; printf(―a=%d, b=%d\ n‖,a, b); printf(―* p1=%d, * p2=%d\ n‖, *p1, * p2); printf(―&a=%x,& b=%x\ n‖,&a, &b); printf(―p1=%x, p2=%x\ n‖, p1, p2); printf(―& p1=%x, &p2=%x\ n‖, &p1, & p2); 100 a } ffd4 10 b ffd6 ffd4 p1 ffd8 < > ffd6 p2 ffda

C语言程序设计

第八章 指针

关于 & 和 * 运算符的进一步说明:
* 、&:优先级同为2级, 结合性:从右向左。 1.若已执行: int a, b, * p1, * p2; p1=&a; p2=&b; a=100; b=10; 则 ① &* p1 ? &a (p1) &* p2 ? &b (p2) ②p2=&* p1 ? p2=&a 2. * & ap1 :先进行&a得a a的地址,再对p1 a的地址进行* 运算 a 即指向a地址所指向的变量,就是 a ,其值是 100 100 &a &a 3. 运算符 * ,++ :优先级为2, 结合性:从右到左 100 p2 ? a++ b p2 (* p1)++ b * p1++ &b ? * (p1++) 10 &a 10 意即: p1原指向a , 现在指向下一个地址了。 < >

C语言程序设计

第八章 指针

例8.2 输入a和b两个整数,用指针方法按先大后小顺序输出 #include <stdio.h> void main( ) 运行情况: {int *p1, *p2, *p, a, b; 5,9 ? scanf(―%d%d‖,&a,&b); p1=&a;p2=&b; a=5, b=9 if(a<b) max=9,min=5 {p=p1; p1=p2; p2=p; } printf(―\na=%d, b=%d\n‖, a, b); printf(―max=%d, min=%d\ n‖, *p1, *p2); } 换前 换后 ffd0 ffd6 ffd8 p1 ffd2 ffd8 ffd6 p2 ffd4 20 ffd6 p ffd6 5 5 a ffd8 9 9 b

只交换了指针的值, 没有交换变量的值

<

>

C语言程序设计

第八章 指针

?指针变量作为函数参数——地址传递
?特点:共享内存,―双向?传递
(main) 例8.3a 将数从大到小输出 变量a 2000 #include <stdio.h> 5 变量b 2002 void swap(int x,int y) 9 2004 { int temp; (swap) COPY 2006 变量x temp=x; 5 9 2008 值传递 变量y x=y; 5 9 200A 变量temp y=temp; } 5 void main() { int a,b; scanf("%d,%d",&a,&b); if(a<b) swap(a,b); printf("\n%d,%d\n",a,b);运行结果: 函数调用结束后,分配 } 5,9? 给x,y,temp单元释放 …... …...

<

>

5,9

C语言程序设计

第八章 指针

例8.3 将数从大到小输出 (使用指针变量作函数参数) (main) #include <stdio.h> 整型变量a 2000 void main() 9 5 整型变量b 2002 { void swap(int *p1, int *p2); 5 9 地址传递 指针pointer_1 2004 int a,b; 2000 2006 指针pointer_2 int *pointer_1,*pointer_2; 2002 2008 scanf("%d,%d",&a,&b); (swap) COPY 200A pointer_1=&a; pointer_2=&b; 指针p1 2000 if(a<b)swap(pointer_1,pointer_2); 指针p2 200C 2002 printf("\n%d,%d\n",a,b);} 整型p 200E 5 void swap(int *p1, int *p2) 2010 { int temp; temp=*p1; 运行情况: 问题:函数调用结束后, *p1=*p2; 分配给p1,p2,p单元释放否? 5,9 ? *p2=temp;}
…... ...

<

>

9,5

C语言程序设计

第八章 指针

例8.3b 将数从大到小输出 void swap(int *p1, int *p2) 2000 { int *temp; 2002 *temp=*p1; int x; 2004 int *temp=&x; *p1=*p2; 2006 *p2=*temp; 编译警告! } 2008 void main() 结果不对! COPY 200A { int a,b; 200C int *pointer_1,*pointer_2; 200E scanf("%d,%d",&a,&b); 2010 pointer_1=&a; pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); printf("\n%d,%d\n",a,b); } < >
运行结果:9,9

(main)

9 5 9 9 2000 2002
(swap)

2000 2002 ****
...

指针变量在使用前 必须赋值!

…...

整型变量a 整型变量b 指针pointer_1 指针pointer_2 指针p1 指针p2

假设2000

指针p

C语言程序设计

第八章 指针

例8.3c 将数从大到小输出 void swap(int x,int y) { int temp; temp=x; x=y; y=temp; } void main() 值传递 { int a,b; int *pointer_1,*pointer_2; COPY scanf("%d,%d",&a,&b); pointer_1=&a; pointer_2=&b; if(a<b) swap(*pointer_1,*pointer_2); printf("\n%d,%d\n",a,b); } < >
运行结果:5,9

2000 2002
2004 2006 2008 200A 200C 200E 2010

(main)

5 9 2000 2002
(swap)

9 5 9 5 5
...

…...

整型a 整型b pointer_1

pointer_2
整型x 整型y 整型t

C语言程序设计

第八章 指针

例8.3d 将数从大到小输出 #include <stdio.h> void swap(int *p1, int *p2) 2000 { int *p; 2002 地址传递 p=p1; 2004 p1=p2; 2006 p2=p;} 2008 void main() COPY { int a,b; 200A int *pointer_1,*pointer_2; 200C scanf("%d,%d",&a,&b); 200E pointer_1=&a; pointer_2=&b; 2010 if(a<b) swap(pointer_1,pointer_2); printf("%d,%d",*pointer_1,*pointer_2); } < >
运行结果:5,9

(main)

5 9 2000 2002
(swap)

2000 2002 2002 2000 2000 ****
...

…...

整型a 整型b pointer_1 pointer_2 指针p1 指针p2 指针p

C语言程序设计

第八章 指针

例8.4 输入a,b,c3个整数,按从大到小输出 运行情况: #include <stdio.h> 9 , 0 , 10 ? void main( ) 10 , 9 , 0 {void exchange(int *q1, int *q2, int *q3); int a,b,c,*p1,*p2,*p3; ffbc 9 0 temp scanf(―%d,%d,%d‖,&a,&b,&c); ffc2 ffd0 ffd2 pt1 p1=&a; p2=&b; p3=&c; ffc4 ffd4 ffd4 pt2 ffca ffd0 q1 exchange(p1, p2, p3); ffcc ffd2 q2 printf(―\n%d, %d, %d\ n‖,a, b, c);} ffce ffd4 q3 void exchange(int *q1, int *q2, int *q3) ffd0 9 10 10 a {void swap(int *pt1, int *pt2); ffd2 0 0 9 b if(*q1 < *q2) swap(q1, q2); ffd4 10 9 0 c ffd6 ffd0 p1 if(*q1 < *q3) swap(q1, q3); ffd8 ffd2 p2 if(*q2 < *q3) swap(q2, q3);} ffda ffd4 p3 void swap(int *pt1, int *pt2) {int temp; temp=*pt1; *pt1=*pt2; *pt2=temp;}
< >

C语言程序设计

第八章 指针

§8.3 数组与指针
?数组的指针:指数组的起始地址。 ?数组元素的指针:指数组元素的地址。
数组的地址?指针变量,指针变量就指向该数组了。

?引用数组元素: ⑴下标法:a[3] ⑵指针法:用指针变量指向所找的数组元素。 占内存少,运行速度快。

<

>

C语言程序设计

第八章 指针

?指向数组元素的指针
例:int a[10]; int *p; p=&a[0]; 或 p=a; /*定义后赋值,两者等价*/ 定义指针变量时赋初值: 例:int *p=&a[0]; int *p=a; 如 int i, *p; p=1000; i=p; (? ) (? )

不能把一个整数?p,也不能把p的值?整型变量 < >

C语言程序设计

第八章 指针

?通过指针引用数组元素
如果: int a[10]; int *p; p=&a[1]; /* p指向数组元素a[1] */ 则: *p=1 表示对p当前指向的数组元素a[1]赋予值1 而:p+1指向同一数组的下一个元素a[2]。
p的值(地址)加了2个字节,p+1=p+1×d(整型,d=2; 实型,d=4;字符型d=1)指针变量所指数组元素的地址的计算, 与数组数据类型有关。

<

设 p=&a[0] 则 ⑴ p+i和a+i就是a[i]的地址a+i×d ⑵ *(p+i)或*(a+i)是p+i或a+i指向的数组元素a[i] > ⑶ 指向数组的指针变量可带下标,p[i]与*(p+i)等价

C语言程序设计

第八章 指针

[] 变址运算符 表示数组元素的两种方法: a[i] ? *(a+i) 地址 地址 元素 元素 a a+1 a+2 a[0] a[1] a[2] a[3] a[9] ... a[0] *a a[1] *(a+1) a[2] *(a+2) p p+1 p+2 a[0] a[1] a[2] a[3] ... a[9] *p p[0] *(p+1) p[1] *(p+2) p[2]

a+9

a[9] *(a+9)

p+9

*(p+9) p[9]

下标法 < >

指针法

a[i] ? p[i] ? *(p+i) ?*(a+i)

C语言程序设计

第八章 指针

例8.5 用三种方法输出数组中全部元素的值
⑴ 下标法: #include <stdio.h> void main() {int a[10]; int i; for(i=0; i<10; i++) scanf("%d",&a[i]); printf("\n"); for(i=0; i<10; i++) printf("%d",a[i] );} 运行情况: 1234567890? 1234567890 ⑷ ⑵指针法和指针下标: 用数组名: #include #include<stdio.h> <stdio.h> void voidmain() main() {int {inta[10]; a[10]; int*p,i i; ; int for(i=0; for(i=0;i<10; i<10;i++) i++) scanf("%d",&a[i]); scanf("%d",&a[i]); printf("\n"); printf("\n"); for(p=a,i=0; i<10; for(i=0; i<10; i++)i++) printf("%d",*(p+i));} printf("%d",*(a+i));} ⑶ 指针法: #include <stdio.h> void main() {int a[10]; int *p,i; for(i=0; i<10; i++) scanf("%d",&a[i]); printf("\n"); for(p=a; p<(a+10); p++) printf("%d",*p );}

<

>

使用指针变量时要注意的问题: ⑴ p++: 合法,因为p是指针变量,++只能用于变量。 a++: 不合法,因为a是数组名,其值是数组元素的 首地址,是常量,程序运行期间值固定不变。 ⑵ 指针变量使用时要注意当前值(见例10.6).

C语言程序设计

第八章 指针

例8.6 用指针变量输出元素 #include <stdio.h> void main() { int *p,i,a[10]; p=a; for(i=0;i<10;i++) scanf(―%d‖,p++); printf(―\n‖); for(i=0;i<10;i++,p++) printf(―%d‖,*p); printf(―\n‖); 原因? }

运行情况: 能正确输出吗? 1234567890? 22153 234 0 0 30036 25202 11631 8259 8237 28483

例8.6 用指针变量输出元素 #include <stdio.h> void main() { int *p,i,a[10]; p=a; for(i=0;i<10;i++) scanf(―%d‖,p++); printf(―\n‖); p=a; /*或者p=&a[0]*/ for(i=0;i<10;i++,p++) printf(―%d‖,*p); printf(―\n‖); }
运行情况: 1234567890? 1234567890

<

>

C语言程序设计

第八章 指针

使用指针变量时要注意的问题: ⑶ 从上例可知,指针变量p可以指向数组以后的内存单元编 译不作检查。 例10.6 用指针变量输出元素 ⑷ 指针变量运算时要注意的几个问题:如果 p=a #include <stdio.h> void main() ① p++(或 p+=1 ),使p指向下一元素a[1]。则*p值成为a[1]。 int *p,i,a[10]; ② ++和* {优先级同为 2,结合性从右向左,则*p++等价于*(p++), 例 即先得到 输出a数组 100个元素 *p,再使p=p+1。例10.6可改为: p=a; p指向的变量的值 p=a; p=a; for(i=0;i<10;i++) ③ *(p++)与 *(++p)作用不同: while(p<a+100) while(p<a+100) scanf(―%d‖,p++); *(p++)先取 *p值,再p加1或 ;*(++p) 是p先加1,再取*p printf(―%d‖,*p++); { printf(―%d‖,*p); printf(― \n‖); 若p初值 &a[0],则 *(p++)得a[0]值,*(++p)得a[1]值。 p=a; /*或者p=&a[0]*/ ④ (*p)++表示 p所指向的元素值加 1。p++;} for(i=0;i<10;i++,p++) for(i=0;i<10;i++) ⑤ 如果p指向 a[i]元素,则: printf(―%d‖,*p); printf(―%d‖, *p++); *(p--)相当于 a[i--],先对 p进行 * 运算,再使p自减(加)。 printf(― n‖); ,先使p自加(减),再作 * 运算。 *(++p) 相当于\ a[++i] } 相当于a[--i],先使p自减(加),再作 * 运算。 *(--p) < >

C语言程序设计

第八章 指针

数组名作函数参数 ?用数组名作函数参数 void main( ) {f(int arr[ ], int n); 数组名作函数参数, int array[10]; 是地址传递 ┆ arr[0] 当用数组名做函数 array[0] f(array, 10); 实参时相当于将数组的 ┆ arr[1] 首地址传给被调函数的 array[1] } 形参,此时,形参数组 void f(int arr[ ], int n) 和实参数组占用的是同 ┋ { 一段内存,所以当在被 ┆ arr[9] 调函数中对形参数组元 array[9] } 素进行修改时,实参数 组中的数据也将被修改, 编译时arr按指针变量处 因为它们是同一个地址。 理,所以,此句与f(int *arr , int n)等价。 < >

C语言程序设计

第八章 指针

⑴ 实参与形参均用数组 例8.7 将数组a 中 n个整数按相反顺序存放。 #include <stdio.h> 思路:数组元素头尾对调。四种调用方式。 void main() {void inv(int x[ ], int n); int i,a[10]={3,7,9,11,0,6,7,5,4,2}; m=4 printf("The original array:\n"); for(i=0;i<10;i++) printf("%d,"a[i]); 0 1 2 3 4 5 6 7 8 9 printf("\n"); 7 5 9 11 7 9 5 4 2 4 7 0 6 6 0 11 7 2 3 inv(a,10); 3 printf("The array has been inverted:\n"); i i i i i j j j j j for(i=0;i<10;i++) printf("%d,",a[i]); printf("\n"); } void inv(int x[ ], int n) { int temp,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; temp=x[i]; x[i]=x[j]; x[j]=temp; } return; }

<

>

C语言程序设计

第八章 指针

⑵ 实参用数组,形参用指针变量 #include <stdio.h> void main() {void inv(int *x, int n); int i,a[10]={3,7,9,11,0,6,7,5,4,2}; printf("The original array:\n"); for(i=0;i<10;i++) printf("%d,"a[i]); printf("\n"); inv(a,10); printf("The array has been inverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); printf("\n"); } void inv(int *x, int n) { int temp,*p,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { temp=*i; *i=*j; *j=temp; } return; }

x i i i i p=x+m i j j j j j

a数组 3 2 7 4 9 5 11 7 0 6 6 0 7 11 5 9 4 7 2 3

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

<

>

C语言程序设计

第八章 指针

此句用意?

<

>

⑶例8.8 实参与形参均用指针变量 #include <stdio.h> void main() {void inv(int *x, int n); int i,arr[10],*p=arr; printf("The original array:\n"); for(i=0;i<10;i++,p++) scanf("%d",p); p=arr; inv(p,10); printf("The array has been inverted:\n"); for(p=arr;p<arr+10;p++) printf("%d",*p); printf(―\n"); } void inv(int *x, int n) { int *p, m, temp,*i,*j; m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { temp=*i; *i=*j; *j=temp; } return;}

C语言程序设计

第八章 指针

<

>

⑷ 实参用指针变量,形参用数组 #include <stdio.h> void main() {void inv(int x[ ], int n); int i,a[10],*p=a; for(i=0;i<10;i++,p++) scanf("%d",p); p=a; inv(p,10); printf("The array has been inverted:\n"); for(p=arr;p<arr+10;p++) printf("%d ",*p); printf(―\n "); } void inv(int x[ ], int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; } return; }

C语言程序设计

第八章 指针

例 从10个数中找出其中最大值和最小值 为了得到两个结果值,用两个全局变量max和min。
⑴ 实参和形参均用数组 int max, min; /* 全局变量*/ void max_min_value(int array[ ],int n) { int *p, *array_end; array_end=array+n; /*指向数组最后一个元素的后面 */ max=min=*array; /* 相当于max=min=array[0] */ for(p=array+1; p<array_end; p++) /* p指向array[1] */ if(*p > max) max=*p; else if(*p<min) min=*p; } main( ) { int i, number[10]; printf(―enter 10 integer numbers:\ n‖); for(i=0;i<10;i++) scanf(―%d‖,&number[i]); max_min_value(number,10); printf(―\nmax=%d, min=%d\n‖, max, min); }

<

>

C语言程序设计

第八章 指针

<

>

⑵ 实参和形参均用指针变量 int max, min; /* 全局变量*/ void max_min_value(int *array,int n) { int *p, *array_end; array_end=array+n; /*指向数组最后一个元素的后面 */ max=min=*array; /* 相当于max=min=array[0] */ for(p=array+1; p<array_end; p++) /* 使p指向array[1] */ if(*p > max) max=*p; else if(*p<min) min=*p; } main( ) { int i, number[10],*p; p=number; /* 使p指向number数组 */ printf(―enter 10 integer numbers:\ n‖); for(i=0;i<10;i++,p++) scanf(―%d‖,p); printf("the 10 integer numbers:\n"); for(p=number,i=0;i<10;i++,p++) printf("%d ",*p); p=number; max_min_value(p,10); printf(―\nmax=%d, min=%d\n‖, max, min); }

C语言程序设计

第八章 指针

归纳:用数组做函数参数有如下四种情况:
1、实参形参都用数组名: int a[10]; inv(int x[ ],int n) inv(a,10) { …... } 2、实参用数组名,形参用指针变量: int a[10]; inv(int *x,int n) inv(a,10) { …... } 3、实参形参都用指针变量: int a[10]; inv(int *x,int n) int *p=a; {……} inv(p,10) 4、实参用指针变量,形参用数组名: int a[10]; inv(int x[ ],int n) int *p=a; {…...} inv(p,10)

<

>

C语言程序设计

第八章 指针

?一级指针变量与一维数组的关系
int *p 与 int q[10] ? 数组名是指针(地址)常量 ? p=q; p+i 是q[i]的地址 ? 数组元素的表示方法:下标法和指针法, 即:若p=q, 则:p[i] ? q[i] ? *(p+i) ? *(q+i) ? 形参数组实质上是指针变量。 即:int q[ ] ? int *q ? 在定义指针变量(不是形参)时,不能把int *p 写成int p[]; ? 系统只给p分配能保存一个指针值的内存区(一般2字节); 而给q分配2*10字节的内存区

<

>

C语言程序设计

第八章 指针

例8.9 用选择法对10个整数排序
⑵ 实参和形参均用指针变量 void sort(int *x, int n) { int i,j,k,t; for(i=0;i<=n-1;i++) { k=i; for(j=i+1;j<n;j++) if(*(x+j)>*(x+k)) k=j; if(k!=i) {t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;} } }

<

>

⑴ 实参用指针变量,形参用数组 #include <stdio.h> void main() {void sort(int x[ ], int n); int *p,i,a[10]; p=a; for(i=0;i<10;i++) scanf("%d",p++); p=a; sort(p,10); for(p=a,i=0;i<10;i++) {printf("%d ",*p); p++;} } void sort(int x[ ], int n) { int i,j,k,t; for(i=0;i<=n-1;i++) { k=i; for(j=i+1;j<n;j++) if(x[j]>x[k]) k=j; if(k!=i) {t=x[i];x[i]=x[k];x[k]=t;} } }

C语言程序设计

第八章 指针

?多维数组与指针
?多维数组的地址(以二维数组为例) 如:int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
? 多维数组数据存储按先行后列顺序。 ? 每行都是一个一维数组,a[0],a[1],a[2]是一维数组名。 ? 每个一维数组含4个元素. 行地址 a数组 a a (2000) a[0] = 1 3 5 7 a[0] = 9 a+1 a[1] 11 13 15 = (2008) a[1] a[2] 17 19 21 23 a+2 a[2] a:二维数组首地址,0行首地址。 (2016)

a+1:第1行首地址为: a+1×4×2=2008
a+2:第2行首地址为: a+2×4×2=2016

<

> a+i:第i行首地址为: a+i×4×2

C语言程序设计

第八章 指针

行地址

? 数组名可以代表数组首地址,所以a[0]代表0行0列地址,&a[0][0]。 a[1]的值是&a[1][0],a[2]的值是&a[2][0]. ? a, a[0], a[1] ,a[2]本身不占内存,不存放数据,仅表示一个地址。 ? 列元素地址的表示: 列元素地址

? 用地址法表示列元素的值 a[0]+0 a[0]+1 a[0]+2 a[0]+3 a+0 a+1

列元素地址:a[1]+3 ? *(a+1)+3 ? &a[1][3]
a[1]+3

a+2

2000 1 2008 9 2016 17

2002 3 2010 11 2018 19

2004 5 2012 13 2020 21

2006 7 2014 15 2022 23

列元素值:*(a[2]+3) ? *(*(a+2)+3) ? a[2][3]

a[2]+0

a[i] ? *(a+i) 等价:第i行第0列的元素地址&a[i][0]

a[i]+j ? *(a+i)+j等价:第i行第j列的元素地址&a[i][j]

<

>

列元素值:*(a[i]+j) ? *(*(a+i)+j) ? a[i][j]

C语言程序设计

第八章 指针

int a[3][4];
a[0][0]

■行指针与列指针
? 行指针前加*转换为列指针:a→*a,a+1→*(a+1) ? 列指针前加&转换为行指针:a[0]→&a[0]

a[0][1] ■ a+i=&a[i]=a[i]=*(a+i) =&a[i][0],值相等,含义不同。 ?a+i ? &a[i],表示第i行首地址, a[0][2] 地址表示: 指向行 a[0][3] 行指针 ?a[i] ? *(a+i) ? &a[i][0],表 (1) a+1 a[1][0] (2) &a[1][0] 示第i行第0列元素地址,指向列 a[1][1]

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

(3) a[1] (4) *(a+1)

列指针 二维数组元素内容表示: (1)a[1][2] (2)*(a[1]+2) (3)*(*(a+1)+2) (4)*(&a[0][0]+1*4+2) < >

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

地址表示: (1) &a[1][2] (2) a[1]+2 (3) *(a+1)+2 (4) &a[0][0]+1*4+2

C语言程序设计

第八章 指针

表示形式 a a[0],*(a+0),*a

含义 二维数组名,数组首地址

地址 2000 2000 2008 2008 2012 13

第0行第0列元素地址
第1行首地址 第1行第0列元素地址 第1行第2列元素地址 第1行第2列元素值

a+1 a[1],*(a+1) a[1]+2,*(a+1)+2,&a[1][2]
*(a[1]+2),*(*(a+1)+2),a[1][2]

<

>

C语言程序设计

第八章 指针

例8.10 输出二维数组有关的值 #include <stdio.h> void main() { int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; printf("%d,%d\n",a,*a); printf("%d,%d\n",a[0],*(a+0)); printf("%d,%d\n",&a[0],*&a[0][0]); printf("%d,%d\n",a[1],a+1); printf("%d,%d\n",&a[1][0],*(a+1)+0); printf("%d,%d\n",a[2],*(a+2)); printf("%d,%d\n",&a[2],a+2); printf("%d,%d\n",a[1][0],*(*(a+1)+0)); } < >

运行结果: 158,158 158,158 158,158 166,166 166,166 174,174 174,174 9,9

C语言程序设计

第八章 指针

?指向多维数组的指针变量
? 指向数组元素的指针变量

例8.11 用指针变量输出数组元素的值 #include <stdio.h> void main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int *p; 运行结果: for(p=a[0];p<a[0]+12;p++) 1 3 5 7 { if((p-a[0])%4==0) printf("\n"); 9 11 13 15 printf("%4d ",*p); 17 19 21 23 } } p=*a; p=&a[0][0]; p=* (a+0); p=*(a+0); p=a;

<

>

C语言程序设计

第八章 指针

由此可见:顺序输出数组元素方法简单 而指定输出数组元素则要进行地址的计算 如二维数组为 n × m (n为行, m 为列) 首元素地址为 a[0] a[i][j]在数组中相对位臵的计算公式: m i * m + j ( m为每行元素个数) 位移量的计算: a[1][1]=1*4+1=5 a[2][3]=2*4+3=11 a[1][1] 若初值: p=a[0] 则: *(p+1*4+1)=*(p+5) ?a[1][1] a[2][3] i=2 *(p+2*4+3)=*(p+11) ?a[2][3] j=3 数组下标从0开始便于计算相对位臵

n

<

>

C语言程序设计

第八章 指针

? 指向由m个元素组成的一维数组的指针变量 ?定义形式: 数据类型 (*指针名)[一维数组维数]; int a[3][4]; 例 int (*p)[4]; a ( )不能少 p a[0][0] ?可让p指向二维数组某一行 或 *p+1 int (*p)[4]与int p[0]+1 *p[4]不同 p的值是一维数组的 a[0][1] 如 int a[3][4], (*p)[4]=a; *(*p+1)或 (*p)[1] 首地址,p是行指针 a[0][2] 一维数组指针变量维数和 a[0][3] 二维数组列数必须相同 a+1 p+1 a[1][0] a[1][1] a[1][2]

a+2

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

p[1]+2或 *(p+1)+2 *(*(p+1)+2) p+2

<

>

a[2][2]
a[2][3]

C语言程序设计

第八章 指针

例8.12 输出二维数组任一行任一列元素的值 #include <stdio.h> void main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int (*p)[4], i, j; p=a; scanf(―i=%d, j=%d‖, &i, &j); printf(―a[%d][%d]=%d\ n‖, i, j, *(*(p+i)+j)); }
运行结果: i=1, j=2? a[1][2]=13

a,a+0,p+0 a+1,p+1 1 a+2,p+2 9 17

3 11

5 13

7 15

<

>

19 21

23

C语言程序设计

第八章 指针

?多维数组的指针作函数参数
? 用指向变量的指针变量 ? 用指向一维数组的指针变量 ? 用二维数组名

若int a[3][4]; int (*p1)[4]=a; int *p2=a[0]; 实参 数组名a 数组名a 指针变量p1 指针变量p1 指针变量p2 < > 形参 数组名int x[][4] 指针变量int (*q)[4] 数组名int x[][4] 指针变量int (*q)[4] 指针变量int *q

C语言程序设计

第八章 指针

例8.13 3个学生各学4门课,计算总平均分,输出第n个学生成绩
#include <stdio.h> 函数说明 void main() { void average(float *p,int n); void search(float (*p)[4],int n); float score[3][4]= {{65,67,79,60},{80,87,90,81}, {90,99,100,98}}; average(*score,12); search(score,2); 列指针 } p float p[][4] p 行指针
65
52 87

79

60

<

>

80

90 100

81
98

90 99

void average(float *p,int n) { float *p_end, sum=0,aver; p_end=p+n-1; for(;p<=p_end;p++) sum=sum+(*p); aver=sum/n; printf("average=%5.2f\n",aver); } void search(float (*p)[4], int n) { int i; printf("score of No.%d :\n",n); for(i=0;i<4;i++) printf("%5.2f ",*(*(p+n)+i)); } ? p[n][i]

C语言程序设计

第八章 指针

例8.14 3个学生各学4门课,计算总平均分,并查找一门以上 课程不及格学生, 输出其各门课成绩 void search(float (*p)[4], int n) { int i,j,flag; p for(j=0;j<n;j++) 65 52 79 60 { flag=0; 80 87 90 81 for(i=0;i<4;i++) ? p[j][i] 90 99 100 98 if(*(*(p+j)+i)<60) flag=1; if(flag==1) { printf("No.%d is fail,his scores are:\n",j+1); for(i=0;i<4;i++) printf("%5.1f ",*(*(p+j)+i)); printf("\n"); #include <stdio.h> } void main() } { void search(float (*p)[4], int n); } float score[3][4]={{...},{...},{...}}; < > search(score,3); }

C语言程序设计

第八章 指针

?总结:二维数组与一维数组指针变量的关系
如 int a[5][10] 与 int (*p)[10]; ? 二维数组名是一个指向有10个元素的一维数组的指针常量 ? p=a+i 使 p指向二维数组的第i行 ? *(*(p+i)+j) ? a[i][j] ? 二维数组形参实际上是一维数组指针变量, 即 int x[ ][10] ? int (*x)[10] ? 变量定义(不是形参)时两者不等价 ? 系统只给p分配能保存一个指针值的内存区(一般2字节); 而给a分配2*5*10字节的内存区

<

>

C语言程序设计

第八章 指针

§8.4 字符串与指针
?字符串的表示形式
string 字符串: 用双引号括起的一串字符。 可赋给字符型的数组或指针变量, 可通过字符型数组名或字符型指针变量输出。
I l o v e C h i n a ! \0

?用字符数组实现 数组名,数组首地址 例10.15 定义字符数组 #include <stdio.h> string+7 void main( ) { char string[]=―I love China!‖; printf("%s\n",string); printf("%s\n",string+7); } 输出: string[4] ? *(string+4) I love Chine! 此句输出? Chine! < >

string[0] string[1] string[2] string[3] string[4] string[5] string[6] string[7] string[8] string[9] string[10] string[11] string[12] string[13]

C语言程序设计

第八章 指针

?用字符指针实现
? 字符串的指针就是字符串的首地址,即第一个字符的地 址, 可以使用字符指针变量来保存这个地址。 string ? 使用字符指针可以处理字符串 I ? 字符指针的定义及使用 ?定义和初始化。 l 例: char *string="I love China!"; o v ?在程序中可以直接把字符串常量赋给 e 一个指针变量。

例:char *string;
string="I love China!";

<

>

例10.16 定义字符指针 #include <stdio.h> void main( ) { char *string=―I love China!‖; printf(―%s\n‖,string);}

C h i n a ! \0

C语言程序设计

第八章 指针

string 改动后的例8.16 #include <stdio.h> void main( ) { char *string=―I love China!‖; printf(―%s\n‖,string); *string!=?\0‘ string+=7; while(*string) string { putchar(string[0]); string++; } }

I l o v e C h i n a ! \0

<

>

输出: I love Chine! Chine!

C语言程序设计

第八章 指针

?用下标法存取字符串中的字符 地址访问: 例10.17 将字符串a复制为字符串b a[ ]复制到b[ ] #include <stdio.h> void main( ) { char a[ ]="I am boy.",b[20]; *(a+i) = a[i] int i; for(i=0;*(a+i)!='\0';i++) *(b+i)=*(a+i); ? b[i]=a[i] *(b+i)='\0'; 下标法输出 printf("string a is: %s\n",a); printf("string b is: "); for(i=0;b[i]!='\0';i++) printf("%c",b[i]); 运行结果: printf("\n"); string a is: I am boy. string b is: I am boy. < > }

C语言程序设计

第八章 指针

例8.18 用指针变量实现例10.17 #include <stdio.h> void main( ) { char a[ ]=―I am boy.‖,b[20]; char *p1=a,*p2=b; int i; for( ; *p1!=?\0‘ ; p1++,p2++) {*p2=*p1;} p1=a; p2=b; *p2='\0'; printf(―string a is: %s\n‖, p1 a ); printf(―string b is: %s\n‖, p2 b ); }

p1

a I a m a

p2

b

p1

b 0 y . \0

p2

运行结果:
< >

string a is: I am boy. string b is: I am boy.

C语言程序设计

第八章 指针

?字符指针作函数参数
例8.19 用函数调用实现字符串的复制
⑴用字符数组作参数 #include <stdio.h> void main() {void copy_string(char from[],char to[]); char a[ ]="I am a teacher."; char b[ ]="You are a student."; printf("string_a=%s\n string_b=%s\n",a,b); printf(―copy string_a to string_b: \n"); copy_string(a,b); /* 数组名作参数是地址传递*/ printf(―\nstring_a=%s\nstring_b=%s\n",a,b); } void copy_string(char from[],char to[]) { int i=0; while(from[i]!='\0') { to[i]=from[i]; i++; } to[i]='\0'; }

a from

a I a m a

b to

t e a c h e r . \0

b I y o u a m a r a e t a e a s c h t e u d r . e \0 n tt .. \0 \0

C语言程序设计

第八章 指针

⑵字符指针变量作形参 #include <stdio.h> void main() { void copy_string(char *from,char *to); char *a="I am a teacher."; char *b="You are a

相关文章:
《C语言程序设计》课后习题答案(第四版)谭浩强
C语言程序设计》课后习题答案(第四版)谭浩强_工学_高等教育_教育专区。《C语言程序设计》课后习题答案(第四版)谭浩强 第1 章程序设计C 语言 1 1.1 ...
C程序设计第四版谭浩强最详细最好的答案(带截图的哦)
C程序设计第四版谭浩强最详细最好的答案(带截图的哦) 隐藏>> 习题三 1.假如我国国民生产总值的年增长率为 9%, 计算 10 年后我国国民生产总值与现在相比增长...
C语言程序设计(谭浩强)第四版_课后答案
C语言程序设计(谭浩强)第四版_课后答案_工学_高等教育_教育专区 暂无评价|0人阅读|0次下载|举报文档C语言程序设计(谭浩强)第四版_课后答案_工学_高等教育_教育...
C语言程序设计(谭浩强)第四版_课后答案
C语言程序设计(谭浩强)第四版_课后答案_理学_高等教育_教育专区 暂无评价|0人阅读|0次下载|举报文档C语言程序设计(谭浩强)第四版_课后答案_理学_高等教育_教育...
C程序设计(第四版)(谭浩强)完整版 课后习题答案
C程序设计(第四版)(谭浩强)完整版 课后习题答案_电子/电路_工程科技_专业资料。C程序设计(第四版)(谭浩强)第一 章课后习题答案 P006 1.1 向屏幕输出文字. ...
C程序设计(谭浩强第四版)试卷7 试卷及答案
C程序设计(谭浩强第四版)试卷7 试卷及答案_工学_高等教育_教育专区。C程序设计(谭浩强第四版)试卷7 试卷及答案一、单项选择题(20 题,每题 2 分,共 40 分...
C语言程序设计谭浩强(第四版)期末复习重点
C语言程序设计谭浩强(第四版)期末复习重点_理学_高等教育_教育专区。第一章 程序设计和 C 语言 1.1.什么是计算机程序程序 :一组计算机能识别和执行的指令。只要...
C语言谭浩强第四版例题
C语言谭浩强第四版例题_IT认证_资格考试/认证_教育专区。C程序设计(第四版)谭浩强 著例1.1 要求在屏幕上输入以下一行信息. This is a C program. 编写程序:...
C语言程序设计第四版第六章答案_谭浩强
C语言程序设计第四版第六章答案_谭浩强_计算机软件及应用_IT/计算机_专业资料。1、 用筛选法求 100 之内的素数。 解: #include <stdio.h> #include <math....
《C语言程序设计》课后习题答案(第四版)谭浩强 (1)
C语言程序设计》课后习题答案(第四版)谭浩强 (1)_理学_高等教育_教育专区。第 1 章程序设计C 语言 1 1.1 什么是计算机程序 1 1.2 什么是计算机语言...
更多相关标签:
c++程序设计谭浩强 | c程序设计第四版 | c语言程序设计 谭浩强 | c程序设计 谭浩强 pdf | c程序设计谭浩强视频 | c程序设计答案 谭浩强 | c程序设计 谭浩强害人 | c程序设计教程 谭浩强 |