第 8 章 综合应用

51
第8第 第第第第

Upload: halden

Post on 17-Jan-2016

85 views

Category:

Documents


3 download

DESCRIPTION

第 8 章 综合应用. 8.1 穷举法:打开问题的缺口. 8.1.1 穷举法的基本思想. 基本思想:. 将所有可能的状态例举出来,然后逐一检验是否满足条件,从而判断哪些是需要的解,哪些不是。. 问题 1 : 求解 1~1000 之间所有的素数。. 问题 2 : 求解满足在 1~1000 之间的两个数之和等于 1234 的所有解。. 问题 3 : 求解满足在 1~1000 之间的三个数,它们是直角三角形的三条边的所有解。. 第四章 串. 问题 1 的解决方法:. 对从 2 开始一直到 1000 的所有数去判断是否是素数,如果是则输出 。. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 8 章  综合应用

第 8 章 综合应用

Page 2: 第 8 章  综合应用

8.1 穷举法:打开问题的缺口

基本思想:将所有可能的状态例举出来,然后逐一检验是否满足条件,从而判断哪些是需要的解,哪些不是。

问题 1:求解 1~1000 之间所有的素数。

• 8.1.1 穷举法的基本思想

问题 2:求解满足在 1~1000 之间的两个数之和等于 1234的所有解。

问题 3:求解满足在 1~1000 之间的三个数,它们是直角三角形的三条边的所有解。

Page 3: 第 8 章  综合应用

第四章 串

对从 2开始一直到 1000 的所有数去判断是否是素数,如果是则输出。

for(i=2;i<1000;i++)

if(IsPrime(i)) printf(“%d\t”,i);

问题 2的解决方法:

for(a=1;a<=1000;a++)

for(b=1;b<=1000;b++)

if(a+b==1234)printf(“a=%d,b=%d\n”,a,b)

问题 1的解决方法:

两个数不妨设为 a和 b。该问题的就是求解满足 1≦a ≦1000, 1 ≦b ≦1000 而且 a+b=1234 的所有的 a和 b。

Page 4: 第 8 章  综合应用

第四章 串

问题 3的解答:

若设这三个数为 a,b,c ,那么问题的解满足:

(1) 1≦a≦1000 , 1≦b≦1000 , 1≦c≦1000;

(2) a2 = b2 + c2 或者 b2 =a2 +c2 或者 c2 =a2 + b2

for(a=1;a<=1000;a++)

for(b=1;b<=1000;b++)

for(c=1;c<=1000;c++)

if((a*a=b*b+c*c)||(b*b=a*a+c*c)

||(c*c=a*a+b*b))

printf(“a,b,c 分别是 %d,%d,%d\n”,a,b,c);

Page 5: 第 8 章  综合应用

第四章 串

解决问题的方式一般为:

for ( a1=a1min; a1<a1max;a1++ )

for(a2=a2min; a2<a2max;a2++)

……

for(an=anmin; an<anmax ; an++)

if( 状态( a1,a2,…an )满足检验条件)

输出问题的解

用穷举法的必备条件:

1.可以预先确定每种状态下的元素个数

2. 每种状态下元素 a1,…ai,…an 的可能值是一个连续的值域。称 ai 为穷举变量, ai∈ [amin, amax] 。

Page 6: 第 8 章  综合应用

例 8-2 百钱买百鸡

鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。凡百钱买百鸡,问鸡翁、母、雏各几何?

1:确定穷举变量以及穷举范围

2 :满足的条件

穷举变量:鸡翁 (cock) ,鸡母 (hen) ,鸡雏 (chick)

第四章 串

问题分析:

百钱: 5*cock+3*hen+chick/3==100

穷举范围:

cock∈[0,100/5]

hen∈[0,100/3] chick∈[0, ]

chick%3==0

99

百鸡: cock+hen+chick==100

Page 7: 第 8 章  综合应用

程序实现:

#include<stdio.h>

void main( )

{

int cock , hen , chick ;

for(cock=0;cock<=20;cock++)

for(hen=0;hen<=33;hen++)

for(chick=0;chick<=99;chich+=3)

if((cock+hen+chick==100)&&(5*cock+3*hen+chich/3==100))

printf(“100 钱买公鸡 %d 只,母鸡 %d 只,小鸡 %d 只 \n”,

cock , hen , chick);

}

第四章 串

Page 8: 第 8 章  综合应用

上述的程序采用的是三重循环实现穷举,事实上,我们使用二重循环就可以完成任务了。因为这三个循环变量之间不是独立的,而是有关系的,我们可以通过它们之间的关系重新确定穷举变量的范围。

cock : 0 , 1 ,……, 20 ;

第四章 串

hen : 0 , 1 ,……, (100-5*cock)/3 ;

chick : 100-cock-hen

1. 穷举变量的穷举范围:

2. 满足的条件:

百钱: 5*cock+3*hen+chick/3==100

小鸡数必须是 3的倍数: chick%3==0

Page 9: 第 8 章  综合应用

程序实现:#include<stdio.h>

void main(){

int cock,hen,chick;int maxhen;

for(cock=0;cock<=20;cock++){

maxhen=(100-5*cock)/3;

for(hen=0;hen<=maxhen;hen++){

chick=100-cock-hen;if((chick%3==0)&&(5*cock+3*hen+chick/3==100))printf(" 百钱买公鸡 %d 只,母鸡 %d 只,小鸡 %d 只 \n“,

cock,hen,chick);}

}}

第四章 串

Page 10: 第 8 章  综合应用

第四章 串

百钱买百鸡的问题中利用各穷举变量之间的关系提高了效率,由三重循环变为二重循环。这个例子说明,如果在穷举前预先对数据做一下分析,就可以提高穷举的效率。 通过这种方法,我们可以将问题 2转化为一重循环解决,问题 3也可以转化为二重循环来解决了。

问题 2求解:

for(a=1;a<=1000;a++)

{

b=1234-a;

if(b<=1000)

printf (“a=%d,b=%d\n”,a,b)

}

Page 11: 第 8 章  综合应用

对于某些问题,穷举变量的取值范围并没有确切的给出,此时要能够将问题答案范围内的状态与自然数建立一一对应,从而确定穷举变量的取值范围。

例 8-3 选人方案。班上要在 A,B,C,D,E,F 6 名同学中选派若干人去参加比赛,选择条件如下: E 和 F两人至少去一个; C 和 D两人去一个; D 和 E要么都去,要么都不去; A 、 B、 F三人中要去两个; 若 C不去,则 B也不去; C 和 F不能一起去。请仔细分析上述条件,找出参加比赛的人选

Page 12: 第 8 章  综合应用

对于该问题,我们很快就可以确定有 6个穷举变量,不妨就设为 a,b,c,d,e,f ,而每个变量的变化范围如何确定呢?

问题中所说的 6个条件(分别用 c1,c2,c3,c4,c5,c6 表示)表达如下: E 和 F两人至少去一个: c1=(e+f>=1) C 和 D两人去一个 : c2=(c+d==1) D 和 E要么都去,要么都不去: c3=(d+e==0||d+e==2) (或者 c3=(d+e!=1)) A 、 B、 F三人中要去两个: c4=(a+b+f==2) 若 C不去,则 B也不去 :c5=(c+b==0||c==1) C 和 F不能一起去 :c6=(c+f<=1)

6 名同学中的每一个同学都只会有“去”或“不去”两种选择,我们分别用自然数“ 1 ”和“ 0 ”来表示“去”和“不去”的状态,这样 6 个穷举变量的变化范围就确定了。

选人时,上述的 6个条件都要满足,即满足 c1+c2+c3+c4+c5+c6==6 的所有的 a,b,c,d,e,f 都是该问题的解。

Page 13: 第 8 章  综合应用

程序实现:#include<stdio.h>void main(){

int a,b,c,d,e,f;int c1,c2,c3,c4,c5,c6;for(a=0;a<=1;a++) for(b=0;b<=1;b++) for(c=0;c<=1;c++)

for(d=0;d<=1;d++) for(e=0;e<=1;e++) for(f=0;f<=1;f++) {

c1=e+f>=1;c2=c+d==1;

c3=(d+e==0)||(d+e==2);c4=a+b+f==2;c5=(c+b==0)||(c==1);c6=c+f<=1;

if(c1+c2+c3+c4+c5+c6==6)printf("a=%d,b=%d,c=%d,d=%d,e=%d,f=%d\n",a,b,c,d,e,f);}

} 第四章 串

Page 14: 第 8 章  综合应用

课堂练习:问题 1 :输出从 1 , 2 , 3 , 4 , 5 这 5 个数

中选取 3 个数的所有无复排列。问题 2 :输出从 1 , 2 , 3 , 4 , 5 这 5 个数

中选取 3 个数的所有无复组合。问题 3 :输出从 1 , 2 , 3 , 4 , 5 , 6 这 6

个数中选取 4 个数的所有无复排列,要求最后一位(个位数)是偶数。

Page 15: 第 8 章  综合应用

第四章 串

由于穷举法是要将所有的解的状态一一例举,因此,如果解空间较大,穷举量就太大,程序运行的就会太慢。所以要尽可能的减少穷举状态。 如何减少穷举量呢?

• 8.1.2 减少穷举量,提高穷举效率

问题 1:求解 1~1000 之间所有的素数。

前面我们已经利用穷举法将问题 1解决了,实际上,经过分析我们会发现穷举的次数无需 1000次,可以减半,因为我们知道除了 3,只要是偶数,就一定不会是素数。所以我们可以将所有大于 2的偶数排除,在剩余的奇数中寻找素数。

Page 16: 第 8 章  综合应用

第四章 串

解决方法如下:

for(i=3;i<1000;i+=2) if(IsPrime(i))printf(“%d\t”,i);

而对于素数 2,单独处理即可。

?请大家再想想,看是否还可以减少穷举量?

通过上面的问题,我们可以看到,如果我们在穷举之前对问题先进性分析,挖掘出问题隐含的条件,排除不可能的条件,就可以减少穷举量了。

Page 17: 第 8 章  综合应用

第四章 串

例 8-4 :寻找肇事汽车号码

一辆汽车肇事后逃逸了,目击者向交警描述了这个车号:这是一个 4位的十进制完全数,并且这 4 个数字从左向右一个比一个大。

分析问题:

1. 确定穷举变量和穷举范围:

穷举变量只有 1 个,不妨设为 n 。而 4位十进制的范围从 1000 到 9999 ,但是由于题目中告知这个数是一个完全数,既是说 n=i2 。因为 1000≤n≤9999 ,所以 32≤i≤99 。所以我们把对n 的穷举转化为对 i 的穷举,此时,穷举量大大减少了,有原来的 8999 个减少到 67 个。

Page 18: 第 8 章  综合应用

第四章 串

分析问题:2. 满足条件:四个数字从左到右一个比一个大。

如果找到 n=i2 ,满足 1000≤n≤9999 ,对组成 n 的 4 个数字分别用 num[0],num[1],num[2],num[3] 表示,那么上述的条件就可表示为:(num[0]<num[1])&&(num[1]<num[2])&&(num[2]<num[3])

Page 19: 第 8 章  综合应用

8.1.3 局部穷举例 8-5 :五人合伙夜间捕鱼问题分析: 设 A、 B、 C、 D、 E这五个人分得的鱼

分别是 fish[0]~fish[4];从题意中我们不难看出如下的关系式: fish[i+1]=(fish[i]-1)*4/5 , i=0,1,2,3.也就是说,只要我们知道了 fish[0], 则其它的

值我们就可以计算得出了。因此只让 fish[0]作为枚举变量就可以了。

Page 20: 第 8 章  综合应用

可是从问题中我们知道, fish[0] 的枚举范围并不好确定,因为它是最大的一个数。那么我们看一看其余的变量 fish[1]~fish[4] 中,哪一个作为枚举变量会更合适一些呢?

既然最大的那个数作为枚举变量不好确定枚举范围,我们来看一看让最小的那个数作为枚举变量行不行?

最小的数是 fish[4],根据题意,容易知道, fish[4]>=6.

既然如此,我们可以处理各人所得鱼数的关系如下:fish[i]=fish[i+1]*5/4+1 i=3,2,1,0

Page 21: 第 8 章  综合应用

因此我们有:int fish[5]={0,0,0,0,6};do

{for(i=3;i>=0;i--){

if(fish[i+1]%4!=0)break;else fish[i]=fish[i+1]*5/4+1;

}if(i>=0)

fish[4]=fish[4]+5;}while(i>=0);

Page 22: 第 8 章  综合应用

局部穷举的例子还可以回顾一下第三张习题 3.15. 我们可以只对张三做穷举即可。

类似的,习题 3.16 、 3.17、 3.18 、 3.19、3.20等都是可以用枚举解决的问题。

此外,著名的 N 皇后问题也可以用枚举的方法求解。

Page 23: 第 8 章  综合应用

N 皇后问题。将 N个皇后分别放置在一张 N*N的棋盘上,要求她们之间互不攻击,即任意两个皇后不同行、不同列、不同一对角线。

比如,当 N=4 时的一种方法如表所示:

i=1

i=2

i=3

i=4

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

Page 24: 第 8 章  综合应用

问题分析:我们可以使用穷举法解决 N 皇后问题。(先看 N=4 的情形。)

1.穷举变量: i,j,k,l;2. 穷举范围: 1<=i,j,k,m<=43. 穷举条件: 我们可以将皇后 1放置在二维数组的位置 a[1][i],皇

后 2放置在 a[2][j],皇后 3放置在 a[3][k],皇后 4放置在 a[4][m]. 所以不妨假设一种放置的方法为:那么,不同行就已经解决了,接下来要描述的就是不同列和不同对角线:

不同列:( j!=i ) &&( k!=i)&&(k!=j)&&(m!=i)&&(m!=j)&&(m!=k)

不同对角线:如果用 a[x][i] 和 a[y][j] 分别表示皇后 x和皇后 y的位置 i 和 j的话,那么她们不同对角线应该为:

|x=y|!=|i-j|

Page 25: 第 8 章  综合应用

void main(){

int b[5];int i,j,k,m;int x,y,t=0;

for(i=1;i<=4;i++) for(j=1;j<=4;j++)

for(k=1;k<=4;k++) for(m=1;m<=4;m++) if(j!=i&&k!=i&&k!=j&&m!=i&&m!=j&&m!=k)

{// 如果不同列 , 就赋给 b 中个元素 b[1]=i;b[2]=j;b[3]=k;b[4]=m;

// 如果不同对角线,就输出 if(!Isdia(2,j,1,i)&&!Isdia(3,k,1,i)&&!Isdia(3,k,2,j)&&

!Isdia(4,m,1,i)&&!Isdia(4,m,2,j)&&!Isdia(4,m,3,k)) for(x=1;x<=4;x++)

printf("%d",b[x]); printf("\n");}

}

Page 26: 第 8 章  综合应用

8.2 回溯法 N 皇后问题: 如果每行放置 1 个皇后,则行就不会出项冲突的现象。因此解

决的主要问题在于如何判断同列、同对角线的问题。 设皇后放置的位置数组为 a[N] 。则很容易根据 a[i] 与 a[j] 的

值是否相等来判定皇后 i 和皇后 j 是否同列。 而对于对角线的判断,与前面我们曾经讨论的一样,看是否满

足等式: j-i=|a[j]-a[i]|. 如果满足,则同对角线,否则,就不同对角线。

如果已经放置好了 i-1 个皇后,在放置第 i 个皇后的时候要与这前 i-1 个皇后去判断是否同列和同对角线,如果有位置 k ,使得皇后 i 与前 i-1 个皇后既不同行,也不同对角线,则令 a[i]=k 即可。但是如果没有位置 k 满足条件,那么就要回溯了。回到第 i-1 个皇后,重新放置第 i-1 个皇后的位置,如果也没有位置放置第 i-1 个皇后,则继续回溯到前一个皇后。当回溯到第0 个皇后的时候,无法回溯,则算法终止。

Page 27: 第 8 章  综合应用

非递归实现 N 皇后问题

void NQueen(int n){ int i,j,k;

int g; // 安全标志变量int a[20]; // 各皇后存放位置数组int x; // 判定是否同列或对角线的变量int s; // 统计个数的变量i=1;s=0;a[1]=1; // 初始状态while(1){ g=1; // 初始时认为安全

for(k=i-1;k>=1;k--){ x=a[i]-a[k];

if(x<0)x=-x; // 确保 x 非负if(x==0||x==i-k) // 如果同列或者同对角线

g=0; // 皇后 i 位置 a[i] 不安全}

if(i==n&&g==1) // 第 n 个皇后已经放好 , 则输出这组解{ s++;

printf(" 第 %d 个解是: ",s);for(j=1;j<=n;j++)

printf("%d",a[j]);printf("\n");

}if(i<n&&g==1) // 如果第 i 个皇后不是第 n 个皇后{ i++; // 去放置第 i+1 个皇后

a[i]=1; // 初始的位置仍然是 1continue;

}while(a[i]==n&&i>1)i--; // 放置皇后 i>1 的时候,所有位置都不安全,则回溯到第 i-1 个皇后if(a[i]==n&&i==1)break; // 如果回溯到第 1 个皇后,说明无解,退出

else a[i]=a[i]+1; // 尝试下一个位置}

}

Page 28: 第 8 章  综合应用

8.3 综合程序设计1 综合程序设计的目的:强化C语言结构化设计的知识个进一步锻炼动手能力。

2 综合程序设计的要求: 1 )选题。结合实际应用的要求,覆盖知识点,接近工程实际需要。

2 )设计。能够根据实际要求,训练自己的实际分析问题的能力、设计能力和编程能力,并养成良好的编程习惯。

3 )测试。通过不同类型的验证,测试程序的设计的完备性、全面性。

Page 29: 第 8 章  综合应用

在软件开发过程中的各种不同的活动如下

定义问题 需求分析 规划构建 软件架构 详细设计 编码与调试 单元测试 集成测试 集成 系统测试 保障维护

Page 30: 第 8 章  综合应用

综合程序设计的过程:前期准备:1 选题(定义问题):对要解决的问题进行清楚地陈述,要从客户的角度

来描述问题。2 需求分析:回答做什么!是对所定义问题的深入调查。是达成解决问题

的第一步。这一步常常被忽略,但是这是最重要的工作之一。重视需求有助于减少开始编程开发之后的系统变更情况。

3 软件架构(总体设计):这是软件设计的高层部分,是用于支撑更细节的设计的框架。架构的质量决定了系统的概念完整性,继而影响到系统的最终质量。软件架构主要包括如下几方面的内容:

1 )程序组织(模块划分) 2 )数据设计 3 )用户界面设计 4 )输入输出 5 )错误处理 ……

Page 31: 第 8 章  综合应用

构建实践(详细设计):1 约定。 1 )确定编码之前的设计工作。 2 )编码过程中对于名称、注释、代码的编写规则。 3 )编码时考虑性能因素,具体的描述。2 团队合作。 1 )是独自编程还是结队编程? 2 )如何实现各模块的接口?3 设计。 1 )数据结构设计具体描述 2 )菜单设计功能需求描述 3 )个模块功能设计描述。编码、集成和测试。

Page 32: 第 8 章  综合应用

实例:选题:简单通讯录管理。问题描述:一个简单的通讯录应该包含联系人的姓名、住宅电话、移动电话、分组、 E-mail 等等信息。实现一个简单的通讯录的管理,能够方便快捷的实现查询、插入、更新、删除、备份等等操作。

需求分析:1 )能够方便地查看联系人的信息。2 )能够更新联系人的信息,包括插入、删除、修改

等。3 )能够备份通讯录。4 )系统简单,易操作。

Page 33: 第 8 章  综合应用

软件架构(总体设计):( 1 )功能模块设计( 2 )模块接口设计( 3 )系统流程设计( 4 )数据结构设计

Page 34: 第 8 章  综合应用

系统功能:通信录管理

更新通信录查看通信录

新增联系人 删除联系人 编辑联系人

备份通信录

Page 35: 第 8 章  综合应用

各模块源文件 包含的函数、成分 功能主程序模块 tel.cpp main 总控函数、变量的的初值设置

头文件模块 tel.h

结构声明 联系人的数据结构类型

常量、变量 提供常数和全局变量

库函数以及函数原型声明 引用库函数及函数

菜单模块menu.cppMenu 主菜单及选择

SubMenu 子菜单及选择

浏览模块 brows.cpp

PrintHead 输出表头

PrintBottom 输出表尾

PrintOne 输出一个联系人

List 显示所有联系人

Print 输出表头和一个联系人

更新模块 edit.cpp

Input 输入联系人信息

New 新增联系人

Edit 编辑联系人

Delete 删除联系人

Select 为删除或修改选择联系人

排序模块 sort.cppSelectsort 选择法排序

SortByAlphabet 将联系人按姓名排序

文件存取模块 file.cpp

Load 将磁盘信息读入到内存 tel

Save 将 tel的内容存到磁盘中

Copy 复制通讯录文件

Page 36: 第 8 章  综合应用

通信录

排序索引

List

browse.cpp

通信录记录数

主程序模块与其它模块之间的关系结构图

tel.cpp

mainLoad

Save

file.cpp

Copy

通信录 排序索引

New

Edit

edit.cpp

Delete

通信录

排序索引通信录

排序索引

菜单代码

是否成功

记录数

通信录 排序索引

menu.cpp

Menu SubMenu2

菜单代码

Page 37: 第 8 章  综合应用

排 序 索引

通信录

联系人原名

菜单代码

排 序 索引通信录

联系人

序号

是 否 重名

通信录通信录

姓名

edit.cpp模块各函数间的关系结构图

New

DuplicateInput

Select

Edit

edit.cpp

Delete

sort.cpp

SortByAlphabet

List

Print

browse.cpp

Page 38: 第 8 章  综合应用

排序索引通信录

file.cpp模块各函数间的关系结构图

SortByAlphabet

sort.cpp

Copy

Load

Save

file.cpp

Page 39: 第 8 章  综合应用

系统流程图

开始

从数据文件读入通信录到 tel 数组

显示主菜单界面

查看通信录

备份通信录

更新通信录

退出

新增联系人

编辑联系人

删除联系人

返回主菜单

结束

显示更新通讯录菜单界面

Page 40: 第 8 章  综合应用

构建实践(详细设计):1. 数据结构设计。联系人的结构定义如下:typedef struct Telephone{

char name[20]; //姓名int group; //群组: 1.朋友 2. 同事 3.家人 4.其他char home[15]; //住宅电话char mobile[15]; //手机char email[20]; //Emailchar add[20]; //地址char memo[20]; //备注

}Tel;

Page 41: 第 8 章  综合应用

sort.cpp模块中利用指针数组对通信录排序,排序用的索引结构的定义如下:

typedef struct index{

int len; // 数组长度Tel *tel[MaxLen]; //指针数组

}Index;

Page 42: 第 8 章  综合应用

总复习数组和指针变量C 语言的指针概念就是内存地址,是内存的编

号。数组的每一个元素都有地址,凡是有地址的地方都可以使用指针。

尤其要注意的是:数组名是常量地址,不能变,可以将数组名赋给一个同种类型的指针,通过指针来间接访问数组元素。

Page 43: 第 8 章  综合应用

1 数组。读下面的程序,写出输出结果:#include<stdio.h>void main(){

int a[8]={10,3,30,5,67,35,2,49};int z, y, k;z=0; y=7; k=a[z];do{

while((z<y) && (a[y]>=k)) y --;if(z<y) { a[z]=a[y]; z++; }while((z<y) && (a[z]>=k)) z++;if(z<y) { a[y]=a[z]; y=y+1; }

}while(z != y);a[z]=k;for(z=0;z<7; z++)

printf("%d ",a[z]);printf("\n");

}

Page 44: 第 8 章  综合应用

2.字符串实际上是字符数组,结束标志对字符串很重要。读下面的程序,写出输出结果:

#include<stdio.h>int main(){

char s1[30]="Hello,";char s2[20]="every one !";

int i=0;for(i=0; s2[i] !='\0'; i++){

s1[i]=s2[i];

}s1[i]='\0';printf("%s",s1);return 0;

}

Page 45: 第 8 章  综合应用

3 结构数组。读下面的程序,写出输出结果:#include<stdio.h>void main(){

struct student{

char name[10];int s[4];

};

struct student stu[4]={{"John",80,70,60,0},{"Rose",90,70,80,0},{"Tom" ,70,50,60,0},{"Total",0,0,0,

0}};int i, j;

for(i=0; i<3; i++){

for(j=0; j<3; j++)stu[i].s[3] += stu[i].s[j]/3;

printf("%d,",stu[i].s[3]);}printf("\n");

}

Page 46: 第 8 章  综合应用

4 用指针变量访问数组元素:读下面程序,写出输出结果 #include<stdio.h> int sum(int *,int); int main() { int x1=0,x2=0,w=0; int a[ ]={1,2,3,4,5,6,7,8,9,10}; int *q=NULL; x1=3; x2=6; q = a+x1-1; w = x2-x1+1; printf("%d\n",sum(q,w)); return 0; } int sum(int *p, int ww) { int b=0; for(int i=0; i<ww; i++) { b += *p; p++; } return b; }

Page 47: 第 8 章  综合应用

文件文件是数据集合。这里涉及的文件是保存在计算机外存储器 ( 如磁盘 )上以“文件名”存取的数据集合。

按数据格式分,文件可分为文本文件和二进制文件两种。按计算机数据的实质,所有文件都是二进制 (字节流 )文件。

对文件的操作主要有:打开、关闭、读、写、文件定位等等。

Page 48: 第 8 章  综合应用

例 1 写一个程序计算文件 myfile.txt 中的字母、数字和其他字符的个数。

分析:从文件里一个一个字符读出来 ( 就象从键盘上一个一个字符输入一样 ) ,每读一个字符就立即统计字母、数字及其它字符的个数。

算法:(1)以“只读”方式打开文件 myfile.txt(2) 设三个变量分别对字母、数字、其它字符计数,并给初

值 0(3) 当文件不结束时,反复做: ①读一个字符 ②判断这个字符是字母、数字或其它字符,并计数(4)关闭文件(5) 输出结果。

Page 49: 第 8 章  综合应用

#include <stdio.h>void main(){

FILE *fp;int letters, numbers, other;char c;if( (fp=fopen("d:\\myfile.txt", "rb")) == NULL){

puts(" 不能打开文件 myfile.txt");return;

}letters=numbers=other=0;while( (c=fgetc(fp)) != EOF ) //读出字符,如果不是文件结束字符则循环做

if( c>='0' && c<='9' ) ++numbers;else if( (c>='A' && c<='Z' ) || (c>='a' && c<='z' )) ++letters;else ++other;fclose(fp);puts(" 统计结果 :");printf( "字母数 :%d\n 数字数 :%d\n其它字符数 :%d\n", letter

s, numbers, other);}

Page 50: 第 8 章  综合应用

例 2 写一个程序计算文件 “ data.txt” 的行数 .分析:什么叫“一行”?其实就是用了一个“回车键”或文件结束。回车键由两个字符组成,一是回车 (ASCII 为 13='\r')二是换行 (ASCII 为 10='\n') ,它们成对出现,因此只需判断其中一个即可。文本的行数比回车键的个数多 1, 只需要给计数器 ( 一个变量 ) 的初值赋 1 而不是 0(换言之,任何一个文件至少有一行 ).

算法:(1)以“只读”方式打开文件 data.txt(2) 行数计数器给初值 1(3) 当文件不结束时,反复做: ①读一个字符 ②如果是回车则行数增 1(4)关闭文件(5) 输出结果。

Page 51: 第 8 章  综合应用

程序:#include <stdio.h>void main(){FILE *fp;int lines=1;char c;if( (fp=fopen("d:\\data.txt", "rb")) == NULL){

puts( " 不能打开文件 data.txt");return;

}while( (c=fgetc(fp)) != EOF )

if( c=='\n' ) ++lines; // 如果读到一个换行符 , 也可以改成回车符fclose(fp);printf( "文本的行数 :%d\n",lines);

}