298
C 程序设计实践教程 编:张鸣华 副主编:寿宇文 曾台盛 审:孔令德

C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

  • Upload
    lydung

  • View
    227

  • Download
    0

Embed Size (px)

Citation preview

Page 1: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

C程序设计实践教程主 编:张鸣华

副主编:寿宇文 曾台盛 主 审:孔令德

Page 2: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

内容提要:本书以Microsoft Visual C++ 6.0、Dev-C++为开发环境,讲授编写程序的思路和方法。全

书共分为 9章,主要内容包括 C语言入门,程序设计基础,分支语句,函数,数组,指针,数据的组织处理及文件。全书以案例为背景,通过问题驱动的方式,由浅入深地引导读者进行理性地思考和有效地实践。本书引入ACM程序设计竞赛培训的学习方法,引导读者自主学习,培养其应用程序设计解决问题的能力。特别注重为后继的课程和编程实践打基础。本书的配套资源丰富,为读者提供了“程序设计在线测试平台”及无需网络支撑的

“程序设计单机测试系统”。为教师提供了 ppt课件和案例源代码。还提供考试和练习用的管理系统。本教程可作为高等院校理工科相关的程序设计类课程教材或教学参考书, 也可供对程序

设计感兴趣的普通读者学习参考。

Page 3: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

前言

“C语言程序设计”是计算机专业及与计算机有关联的理工类各专业重要的基础课程之一。程序设计类教学长期以来有着多种不同的教学模式和理念,产生了不同的效果。本书几位作者长期承担程序设计类的教学任务;带领学生参加 ACM/ICPC竞赛活动;组织学生进行多种创新与实践,积累了丰富的经验,取得了一定的成绩。师生共同创建了程序设计在线测试平台(简称 OJ),开发了考试中用到的系列软件,奠定了在这平台上的教学理念和教学方式:实践与思考。这本书就是根据这些学生在实践中学习方式、学习顺序来展开的。本书还参考了目前国

内外主要的程序设计教材和程序设计竞赛训练材料。本书以案例为背景,以问题驱动为教学模式,引导读者自主学习。本书的内容安排遵循学习规律,循序渐进。第 1章介绍 C语言的特点、开发平台、程序设计的步骤、OJ平台的使用,引导读者以实

践的方式入门。第 2章是程序设计基础,介绍数据表达方式、数据的输入与输出、赋值语句,引导读者

用顺序结构实现常规的数学计算编程。第 3章介绍关系运算、关系表达式,用流程图解释分支结构中的逻辑判断,还介绍了

ASCII码,将程序设计的范围展开。第 4章介绍循环问题的程序设计。使用大量流程图表达循环问题的算法,使读者容易掌

握思考和解决这类问题的方法。第 5章介绍自定义函数及使用方法,引导读者掌握程序模块化的设计方法,还由浅入

深地引导读者学习递归函数,培养抽象思维能力。函数的思想和方法在后继的章节中将不断深入地应用。第 6章介绍数组,强调了循环处理数组中数据元素的方法,培养读者处理批量数据的

能力。第 7章介绍指针。用浅显的例子来理解指针是地址,用实际应用来展开指针的使用。第 8章介绍结构体与共用体,培养数据的组织与处理能力。通过链表的学习,让读者综

合程序设计的方法,为学习数据结构奠定基础。第 9章介绍文件的使用。供需要深入学习 C语言的读者使用。

Page 4: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

本书各章中的进阶是本章内容深入或算法设计问题,来自 ACM类问题或后继课程中的局部环节,这有利于加强读者的思维训练、引导读者自主学习、培养读者解决问题的能力。而且,本书中进阶的内容不影响进度,可以滞后学习。本书各章都提供了大量习题,这些习题知识面广、趣味性强、思维层次深。本书光盘中的“程序设计单机测试系统(OfflineJudge)”是一个可独立运行的绿色软

件,与OJ有相似的功能,可以对 C、C++编写的代码进行测评,测评结果与OJ上的一致。内含本书中的 200多道例题与习题供读者练习。无需网络支撑。本书提供多个附录便于使用。主要有:关键字、常见错误、程序调试、库函数、常用字符

与ASCII码对照表、常用 C 库文件、预处理。本书由张鸣华主编,其中张鸣华编写了第 1、2、3、5、6章,曾台盛编写了第 4、8、9章,

寿宇文编写了第 7章。全书由张鸣华统稿,孔令德教授审阅。本书的代码由王文辉负责校对,本书关联的在线测评系统由王文辉首创、许建众开发考试时 IP 绑定功能、吴振深完善后台测试数据管理功能与多线程考试功能、陈松金开发考试成绩管理功能、吴俊开发考试时监控 U

盘和网络功能及考试点名功能、余宇航完善 OJ考试与练习两平台切换的功能等,配书的程序设计单机测评系统由曾坚坚、王吉生开发。本书的各个部分都由众多不层次学生试读,找出问题不断修改。本书的电子版已经使

用过 1 个学期,由张标汉、惠苗、董园、孙丽丽、魏晶晶、李渭提出意见并加以修改。本书的习题由以上教师负责。特别,我们的教改、ACM系列活动、写书的过程都得到福大吴英杰老师的指导。本书的

编写得到了广西师范学院邓育林老师的宝贵意见。对以上的各位参与者、支持者,我表示衷心的感谢。书中大部分的例题和习题边上有用括号指示的 4位数字,例如,(smu1112),是该题

在三明学院程序设计在线测试平台上基础区的编号。如果是(smp1112)指的是问题区的编号。三明学院在线测试平台的网址是:http://218.5.241.13:8060/oj。本书在输出结果中,行末出现的“↙”表示回车,指明这一行是输入数据。 “C语言程序设计”课程建议采用理论与实践一体化教学,前 8章的课时数为 80 左右。

本书为使用的老师提供了教学相关资料。请联系 [email protected] 。由于作者水平有限,本书可能存在很多不足,敬请读者批评指正。

Page 5: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击
Page 6: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

目录

C程序设计实践教程.......................................................................................................................1第 1章 C语言入门..........................................................................................................................1

1.1学习 C语言........................................................................................................................11.2 用Visual C++ 6.0 编写程序...............................................................................................31.3 用Dev-C++开发程序.........................................................................................................71.4 C语言的特点.....................................................................................................................9

1.4.1 C语言的结构...................................................................................................91.4.2 程序风格................................................................................................................10

1.5 程序流程图.......................................................................................................................111.6 开始设计一个程序...........................................................................................................121.7 在线测试平台(OJ)上的数据处理..............................................................................13习 题.....................................................................................................................................19

第 2章 程序设计基础....................................................................................................................202.1数据类型...........................................................................................................................202.2变量与常量.......................................................................................................................212.3 const修饰符.....................................................................................................................232.4 运算符和表达式...............................................................................................................242.5赋值语句...........................................................................................................................262.6 库函数..............................................................................................................................282.7 输入与输出函数...............................................................................................................29

2.7.1 printf()函数.......................................................................................................292.7.2 scanf()函数.......................................................................................................322.7.3 字符数据的输入输出............................................................................................34

2.8 案例及分析.......................................................................................................................352.9进阶...................................................................................................................................38习题........................................................................................................................................41

第 3章 逻辑思维及分支程序设计—分支语句............................................................................433.1 关系运算和关系表达式...................................................................................................433.2 逻辑运算符和逻辑表达式...............................................................................................443.3 分支结构..........................................................................................................................45

3.3.1 if语句...................................................................................................................453.3.2 switch语句...........................................................................................................50

3.4条件表达式.......................................................................................................................533.5 ASCII码...........................................................................................................................543.6 案例及分析.......................................................................................................................563.7 进阶..................................................................................................................................58习题........................................................................................................................................63

第 4章 循环问题设计--循环语句.................................................................................................674.1 循环结构..........................................................................................................................67

4.1.1 for语句..................................................................................................................67

Page 7: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

4.1.2 while 语句..............................................................................................................714.1.3 do while 语句.........................................................................................................724.1.4 三种循环语句的比较............................................................................................734.1.5 break 语句..............................................................................................................754.1.6 continue 语句.........................................................................................................76

4.2 循环的嵌套.......................................................................................................................774.3案例及分析.......................................................................................................................784.4 进阶..................................................................................................................................83习题........................................................................................................................................89

第 5章 过程封装与递归思想--函数.............................................................................................945.1 自定义函数.......................................................................................................................94

5.1.1 自定义函数的结构................................................................................................945.1.2 自定义函数的返回值............................................................................................955.1.3 自定义函数的调用与传参....................................................................................955.1.4 函数的定义与声明的区别和使用........................................................................97

5.2 全局变量与局部变量.......................................................................................................985.3 存储类型........................................................................................................................1005.4 函数的嵌套调用.............................................................................................................1025.5 函数的递归调用.............................................................................................................1035.6 案例及分析.....................................................................................................................1045.7 进阶................................................................................................................................109习题.......................................................................................................................................115

第 6章 批量数据处理--数组.......................................................................................................1206.1 一维数组........................................................................................................................120

6.1.1 一维数组的定义..................................................................................................1206.1.2 一维数组的引用..................................................................................................122

6.2 二维数组........................................................................................................................1266.2.1 二维数组的定义..................................................................................................1266.2.1 二维数组的引用..................................................................................................127

6.3 字符数组........................................................................................................................1286.3.1 字符数组的定义..................................................................................................1286.3.2 字符数组的使用..................................................................................................1296.3.3 字符串函数..........................................................................................................132

6.4 案例及分析.....................................................................................................................1336.5 进阶................................................................................................................................139习题......................................................................................................................................148

第 7章 间接访问--指针...............................................................................................................1637.1 指针................................................................................................................................163

7.1.1 变量的地址..........................................................................................................1637.1.2 指针变量的定义..................................................................................................1647.1.3 指针的动态内存分配..........................................................................................1667.1.4 指针的应用..........................................................................................................168

7.2 指针与数组间的关系.....................................................................................................1707.3 指针变量作为函数参数...............................................................................................172

Page 8: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

7.4 函数值为指针类型.......................................................................................................1757.5 指针数组.......................................................................................................................1767.6 双重指针.......................................................................................................................1787.7案例及分析...................................................................................................................1827.8 进阶...............................................................................................................................185习题......................................................................................................................................188

第 8章 数据的组织与处理--结构体、共用体、枚举与链表....................................................1948.1用 typedef声明的的类型名...........................................................................................1948.2 结构体与共用体.............................................................................................................195

8.2.1结构的定义..........................................................................................................1968.2.2 结构类型变量的使用..........................................................................................1988.2.3 结构数组..............................................................................................................2018.2.4 共用体..................................................................................................................204

8.3 指针与结构体.................................................................................................................2068.4返回值是结构体指针的函数.........................................................................................2088.5链表.................................................................................................................................210

8.5.1单链表的结构......................................................................................................2108.5.2单链表的建立与输出..........................................................................................2118.5.3单链表结点的插入..............................................................................................2148.5.4单链表结点的删除..............................................................................................217

8.6 枚举数据类型.................................................................................................................2208.7 案例及分析.....................................................................................................................2228.8 进阶................................................................................................................................230习题......................................................................................................................................236

第 9章 流的输入输出--文件.......................................................................................................2409.1认识文件.........................................................................................................................2409.2文件的打开与关闭.........................................................................................................2429.3读写文件的有关函数.....................................................................................................2459.4二进制文件.....................................................................................................................2499.5随机读写文件.................................................................................................................2519.6案例及分析.....................................................................................................................2529.7 进阶...............................................................................................................................254习题......................................................................................................................................260

附录A 关键字..............................................................................................................................262附录 B 常见错误..........................................................................................................................263附录 C 程序调试..........................................................................................................................266附录D 库函数..............................................................................................................................276附录 E 常用字符与ASCII码对照表..........................................................................................284附录 F 常用 C库文件..................................................................................................................286附录G 预处理..............................................................................................................................288参考文献......................................................................................................................................293

Page 9: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 1章 C语言入门

导学请读者先在电脑上安装 VC或DEV-C++,输入本章的程序并运行。理解 C语言的特点

和作用;认识程序的基本结构;理解简单的程序;用 freopen 将输入、输出的数据放在文件中处理。试着写一点简单的程序,再通过 OJ平台或本书提供的单机测评系统,在上面提交a+b的代码,熟悉以后的学习环境。

1.1学习 C语言计算机做任何一件事情都离不开人们为它编写的程序,用于程序设计的语言有很多,

其中 C语言有着悠久的历史,有着众多应用,同时也是一门很好的程序设计入门语言。事实上不同的高级语言有着很多相似之处,只要对入门的语言打好基础,就可以很容易掌握其他语言的应用。本教程学习 C语言的同时,不仅要学习编写 C语言的语法规则,重要的是要学会程序

设计的方法和思路。设计一个程序通常有下列一些步骤:(1)定义程序目标一开始,对程序做什么要有一个清晰的想法。考虑程序需要什么信息、进行什么样的操

作和计算,以及程序将要报告的信息。这是程序设计规划的阶段。(2)设计程序程序的输入、输出是什么;用什么样的数据结构组织数据;用什么样的方法设计程序;

用什么语句来实现。也就是说:程序设计=算法+数据结构+代码。可以用流程图表示程序设计过程,使得自己的思路更加清晰。(3)编写代码

1

Page 10: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

我们决定用 C语言编写代码,要确定一个编程环境,选择一个程序运行平台。C语言的开发平台较多,常用的 C语言 IDE(集成开发环境)有Microsoft Visual C+

+,Borland C++,Watcom C++ ,Borland C++ ,Borland C++ Builder,Borland C++ 3.1 for

DOS,Watcom C++ 11.0 for DOS,GNU DJGPP C++ , Lccwin32 C Compiler 3.1,Microsoft

C,High C,Turbo C,Dev-C++,C-Free, win-tc 等等。由于 C语言是 C++语言的子集,所以本书以Microsoft Visual C++(以下简称VC)平台为主进行讲解。

用 C语言设计出来的源代码是形如*.C 形式的文件,可以在 VC平台上编辑,也可以直接用记事本之类的文档编辑器生成。比如让计算机输出一句“How are you.”,可以这样写:

【程序清单 1.1】1. //How are you.

2. #include <stdio.h>

3. void main()

4. {

5. printf("How are you.\n");

6. }

每行前面的行号是便于阅读而加上的,不属于代码中的内容。(4)编译程序*.C的文件要编译成*.obj的文件,再链接成可执行的文件*.exe 才能运行。这个工作由

编译器完成。编译器是一个程序,其工作是将源代码转换为可执行的代码。可执行的代码是用计算机的本机语言或机器语言表示的代码。这种语言是由数字代码表示的详细指令组成 。C编译器将 C语言转换成特定的机器语言。C编译器还从 C的库中向最终程序加入代码。编译器还检查用户的程序是否为有效的 C语言程序。如果编译器发现错误,就将错误

报告给用户。没有发现错误时就生成可执行文件。(5)运行程序在VC中通过选择菜单或工具栏中的“运行”选项完成。运行时通过输入程序要求的数

据,就可以得到运行后的结果。(6)调试程序程序可以运行还不能保证结果是正确。可能会有一些编写的错误或是设计的错误,这

种错误在计算机中称之为 bug。调试就是要发现并修正程序错误,即 debug的过程。(7)维护程序程序在运行时,可能会发现问题,要对其进行修改,或增加新的功能。这个工作就是

2

Page 11: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

维护。

1.2 用Visual C++ 6.0 编写程序Visual C++ 6.0,简称 VC或者 VC6.0,是微软推出的一款 C++编译器(将“高级语

言”翻译为“机器语言(低级语言)”的程序)。Visual C++是一个功能强大的可视化软件开发工具,特别有强大的 debug 功能。自 1993年Microsoft公司推出Visual C++1.0后,随着其新版本的不断问世,Visual C++已成为专业程序员进行软件开发的首选工具。实际应用中,VC 占用内存资源少,是我们学习 C语言程序设计的良好平台。对于初学者,建议安装和使用Visual C++ 6.0。本书中的主要代码都是在VC中调试的。

请先安装 Visual C++ 6.0。注意,如果Windows7的操作系统不支持 Visual C++ 6.0,可以改装 Visual C++ 2010 版。

VC 最好在操作系统安装后就安装,特别要在 .net安装之前先安装,否则使用时容易死机。

【例 1.1】输出"Hello. C."。(smu1001)操作步骤如下:(1)建立工程从 Windows 的“开始” |“程序”栏选 择 Microsoft Visual Studio 6.0 菜单中的

MicrosoftVisual C++ 6.0菜单项,启动Visual C++ 集成开发环境。在菜单项中选中“文件”|

“新建”,就出现图 1.1的界面。在“工程”选项卡中选择 Win32 Console Application 选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用 Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图 1.2的界面,选择“一个空工程”,单击“完成”按钮,进入下一个页面,再单击“确定”按钮,这样工程就建好了,并在工程文件夹Hello中产生一个 Hello.dsw的工程文件。

3

Page 12: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 1.1 创建一个项目

图 1.2 创建控制台程序(2)添加文件单击“文件”|“新建”,在弹出的一个新建对话框中选择 C++ Source File,在“文件

名”中输入 1_1.c(注意文件名一定要有后缀.c,否则就成为 C++的文件),再单击“确4

Page 13: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

定”按钮,如图 1.3 所示,一个 C的文件就建立好了,同时打开了这个文件的编辑窗口。

图 1.3 建立文件 图 1.4是开发应用程序时一般的 Developer Studio(即 VC6.0的 IDE)窗口示意图 。

Developer Studio窗口由标题栏、菜单栏、工具栏、工作区窗口、源代码编辑窗口、输出窗口的状态栏组成。

图 1.4 Visual C++ 6.0 集成开发环境在工作区有一个类视图(ClassView)和一个文件视图(FileView)。展开文件视图

5

Page 14: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(FileView)后会出现 3 个文件的目录,依次为:Source File 用来存放一般的程序文件。Header File 用来存放头文件(含.h)。Resource File 用来存放资源文件。展开 Source File可以看到刚才建的文件 1_1.c。如图 1.5 所示。

图 1.5 工作区的展开图

(3)输入程序在编辑窗口输入【程序清单 1.2】,如图 1.6 所示。【程序清单 1.2】1. //功能:输出"Hello. C."

2. #include <stdio.h> // 预编译命令3. void main() // 主函数4. { // 主函数开始5. printf("Hello. C.\n"); // 用输出语句 printf输出"Hello. C."

6. }

图 1.6 代码编辑框(4)运行程序

6

Page 15: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

在 中, (Compile(Ctrl+F7))表示编译,即编译1_1.c,生成 1_1.obj,如果成功 会在输出框中的组建窗口显 示:1_1.obj - 0 error(s), 0

warning(s); (Build(F7))表示链接,即将 1_1.obj 链接成可执行文件 Hello.exe ,如

果成 功 会 在 输出 框中 的组 建 窗口 显 示 Hello.exe - 0 error(s), 0 warning(s) ;(BuildExecute)表示链接和执行,即执行 Hello.exe文件,并在弹出窗口显示结果,如图1.7 所示。

图 1.7 运行结果

1.3 用Dev-C++开发程序Dev-C++是一个开发 C/C++程序的免费的集成开发工具。大家可以在网络上下载和安装。

在Dev-C++上开发程序有如下几个主要操作:1.启动Dev C++

从“开始”|“所有程序”栏中找到 Dev-C++并运行,这样就启动了 Dev-C++程序,如图 1.8 所示。

7

Page 16: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 1.8 Dev-C++启动时的初始界面2.源程序的创建和编辑在Dev-C++中创建一个源程序的步骤如下。(1)在菜单栏中选择“文件”|“新建”|“源代码”,也可以按 Ctrl+N 键进入。(2)在新出现的空白窗口中输入自己的程序源码。【程序清单 1.3】1. #include <cstdlib> // 使用 system("pause");的头文件2. #include <stdio.h> // 预编译命令3. int main()//主函数,在Dev中主函数的类型不能是 void,因此需要返回值。4. { //主函数开始5. printf("Hello. C.\n"); // 用输出语句 printf输出"Hello. C."

6. system("pause"); // 为了能看到输出结果而加的7. return 0;

8. } // 主函数结束

(3)保存源程序,可以按 Ctrl+S,也可从文件菜单中选择保存。存盘的文件类型选 C

source files(*.c)。3.编译源程序编译程序的方法有多种,可以按 Ctrl+F9 键,也可以从菜单栏中选择运行|编译。还可以

从工具按钮中选择 按钮。如果没有错误,会在 Compile Progress对话框中显示 Errors和8

Page 17: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Warnings均为 0的状态,如图 1.9 所示,程序就可以运行了。

图 1.9 Compile Progress对话框4.运行程序要运行已编译成功的程序,也有多种不同的方法。可以按 Ctrl+F10,也可以选择运行|运

行,或单击工具栏中按钮 。这时就可以看到控制台窗口显示结果。5.打开和修改已有程序假如我们想修改以前编写好并已存盘的源程序,就需要用 Dec-C++重新打开它,在完

成编辑修改后,再编译运行。要打开已有源程序进行修改,同样也有多种方法。可以按 Ctrl+O 键,或者选择菜单文

件|打开工程或文件,或者单击工具栏上的按钮 。这样就可以进行修改,重新编译和运行。通过前面的讲解注意到,用Visual C++ 6.0和Dev-C++开发设计,有几个区别:(1)Dev-C++的主函数(main())只能是 int类型,而 Visual C++ 6.0的主函数可以是 int

类型,也可以是 void类型。本书后续代码中的main()函数大都使用 int类型。(2)Dev-C++的运行窗口要用“system("pause");”才可以停留、显示运行结果,而 VC

会在运行窗口中会提示:“按任意键继续”(英文是:“Press any key to continue”)。

9

Page 18: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1.4 C语言的特点

1.4.1 C语言的结构【例 1.2】求圆的面积(与 smu1006相似)。【程序清单 1.4】1. #include <stdio.h> // 预编译命令2. #include <cstdlib> // 使用 system("pause");的头文件3. #define PI 3.1415926//宏定义4. int main() // 主函数,在Dev中主函数的类型不能是 void。5. { //主函数开始6. double r=1.0,s;

7. s = PI*r*r;

8. printf("s=%lf\n",s); // 用输出语句 printf输出圆的面积9. system("pause"); // 为了能看到输出结果而加的,Dev环境下要加。10. return 0;

11. } //主函数结束

运行的结果为:s=3.141593

这段程序包括二个部分:以#开头的部分和主函数 int main(){return 0;}部分。其中:以符号#开头的的行,称为编译预处理。C编译器内置了预处理器,源代码中以“#”开始

的行将由预处理器进行处理。命令#include <stdio.h>是指添加头文件“stdio.h”到新建的程序中去。这个头文件是由 C

系统所提供的。用引号表示在自己定义的位置,用“<stdio.h >”(两端尖括号)表示这个头文件应该从标准位置寻找,一般是放在 include的文件夹内。我们使用的原因是因为它包含了 printf()的信息。C语言中提供了一些可以被直接拿来使用、能够完成某些特定功能的库函数,分别声明于不同的头文件中。

#define PI 3.1415926是宏定义。规定在这个程序中圆周率 PI代表 3.1415926。int main(){ return 0;}是每一个 C或 C++的程序都要有的,称为主函数。程序运行时,

从 int main(){…}的第一个语句开始执行。用户编写的程序的主要部分写在main函数里。printf()是输出语句。里面的“\n”表示换行。

10

Page 19: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

“//”表示后面的内容是注释部分,同样可以使用“/*注释内容*/”进行注释。注释内容不参与程序运行。为了使程序便于阅读和维护,增加注释是非常重要的。

“return 0;”意思是返回 0给操作系统,表示主函数 int main()内的程序运行结束,正常返回操作系统。注:#部分的使用见附录 G 预处理。

1.4.2 程序风格程序要有很好的可读性,易于修改和交流,因此要有个优美的、逻辑清晰的风格。一般

要遵循下列规则:(1)花括号“{}”成对出现;“{”后不写代码;除了 do{}while()、结构体之类的语句外,

“}”后不加代码;右花括号与所在的程序块左对齐;(2)左花括号后的代码要缩进一个 Tab位;(3)运算符两端各加一个空格;(4)适当增加注解,程序开始加上该程序说明的注解,循环块的右括号后加上指明哪

个循环的注解等等。为了美观和突出功能模块的意思,还可以考虑:(1)如果一行有多条语句,这些语句间最好用空格分开;(2)有时可以在较大功能块之间加一个空行;在VC上编写代码时,我们可以选中要调整的部分,按下 ALT+F8组合,VC 会为自动

我们调整缩进的尺度。

1.5 程序流程图为了表达程序设计的方法(即算法),我们常用程序流程图。常用的流程图符号如图

1.10。

图 1.10 常用程序流程图

11

起止框 输入、输出框

处理框 判断框

流程线 连接点

Page 20: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

还有其它的流程图符号读者可以从 Microsoft PowerPoint的自选图形中的流程图中、或从 Microsoft Visio中的流程图中、或其它地方得到。例如,要表达:如果 x>0,则 y=1,否则 y=-1。可以用图 1.11表示。

图 1.11 判断 y 值的流程图【例 1.3】按照如图 1.12 所示的流程图中的步骤操作,然后说出最终的结果。

图 1.12 寻找黑洞数的流程图注:a-b->n表示把 a-b的结果存入变量 n,即 n的值为 a-b。在这流程中,无论你输入多大的三位数(三位数字都不相同),最后得到的数一定是

495,这个数被称为黑洞数。

12

an, 14年7月15日,
此图已改
Page 21: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1.6 开始设计一个程序【例 1.3】计算 1+2+…+n。(SMU1002)

从思考、分析到解题的完整步骤如下:(1)随着 n的变化,式子中的项数无法具体确定,我们先按等差数列的特点写出计算

公式:1+2+…+n=(1+n)n/2;这是一个算法的设计过程。(2)确定用 n表示最终的项数,sum表示计算的结果,它们是整数类型,这是设计数

据类型和数据结构的过程。(3)程序流程的设计过程:先声明有两个整型变量 n,num。再由键盘输入 n的值。然后

计算,并把计算的结果存入变量 sum中。最后输出运行结果。如图 1.13 所示:

图 1.13 计算 1+2+…+n的流程图(4)按 C的语法写代码,如【程序清单 1.5】所示,这是代码设计的过程。【程序清单 1.5】1. #include <stdio.h>

2. int main()

3. {

4. int n,sum;

5. scanf("%d",&n); // 输入整数变量 n

6. sum = (1+n)*n/2; // 求和公式13

开始

设两个变量n,sum,分别表示项数和数列和输入n

求和sum

输出sum

结束

Page 22: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

7. printf("%d\n",sum);

8. return 0;

9. } (5)在VC中输入代码、调试、输出结果:

100↙5050

这是程序的运行过程。(6)如果程序运行不成功,或结果不符合要求,就要进行调试。大多数的程序都要经

历调试的过程。

1.7 在线测试平台(OJ)上的数据处理程序设计在线测试平台(Online Judge,简称 OJ)用来检测你写的程序源代码的正确

性。国外著名的OJ有UVA OJ、ural OJ等。国内著名的题库有北京大学题库、杭州电子工业大学题库、浙江大学题库等。目前大多数的大学都有自己的题库。国外的题库包括乌拉尔大学、瓦拉杜利德大学题库等。用户上网,就可以选择一个 OJ平台练习。这些著名的OJ平台主要针对的是ACM(国际大学生程序设计竞赛)。对于初学者,以及不能上网的读者,可以使用本书配的Offline Judeg。这个平台的题库与本书的例题与习题基本一致。

OJ平台以解决问题的方式来出题。每个问题分为问题描述(Description )、输入描述(Input)、输出描述( Output)、样例输入(Sample Input)、样例输出(Sample Output)5

个部分。输入的数据以文件的方式储存,你的程序要准确处理所给的所有数据。样例一般有单样例、有限个样例、若干个样例等。 输出的结果要与题目中的要求完全一致,包括空格、格式等。

【例 1.4】给你两个整数 a,b(0<=a,b<=1,000),计算 a+b的值。(smu1000)

这个问题在OJ平台上描述为如下形式(本书中,对问题的主要描述均采用以下方式表示,以后不再特别标注):

Problem 1000 A+B的问题Description

给你两个整数 a,b(0<=a<=1,000),计算 a+b的值。

Input

有多组测试数据,每组一行,每行有两个整数 a,b。

Output

14

Page 23: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

输出 a+b的值。

Sample Input

2 3

5 2

0 5

Sample Output

5

7

5

“Problem 1000”中的 1000是问题的编号,一般 OJ上的问题的编号是从 1000开始,本书的例题和习题上括号内标注的问题编号是三明学院OJ上的题号。对于 OJ上的每一个问题,你要从“Description”中理解要解决的问题;从“Input”和

“Sample Input”中理解输入数量的数量及输入方式。从“Output”和“Sample Output”中理解输出的要求。分析:当 a、b不止一组时,读入和处理的过程是一个循环的过程,我们可以使用

while(){}语句来实现。如【程序清单 1.6】的第 5~8行所示。【程序清单 1.6】1. #include<stdio.h>

2. int main()

3. {

4. int a, b;

5. while(scanf("%d%d", &a, &b) != EOF) //读取输入流中的所有数据6. {

7. printf("%d\n", a + b);

8. }

9. return 0;

10. }

程序说明:(1)while(条件){语句}指条件正确时循环执行{}内的语句;(2)EOF表示为数据流结束。在控制台上用 ctrl+z 键后再按回车来完成。(3)scanf()是输入语句。scanf("%d",&n)表示从键盘输入一个整数,并放入变量 n 所在

的地址中;!=表示为不等于; scanf("%d",&n)!=EOF表示输入的数据没有结束的情况,即输入数据成功。(4)第 4、5、6行意思是:判断语句“scanf("%d%d", &a, &b) != EOF”的结果作为while

循环的条件,为真时就执行循环体,也就是{}内的第 7行语句。(5)第 5行也可以写成 while(scanf("%d%d", &a, &b)== 2),表示循环条件是:正好有 2

15

Page 24: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

个数据输入。【程序清单 1.6】的运行过程如图 1.14 所示:

图 1.14 程序清单 1.6 的运行过程图图中^Z表示按下 Ctrl+Z 键。平时为了便于调试程序,输入、输出的数据可以放在文件中。例如【程序清单 1.7】的第 5

行表示:通过 freopen()打开 input.in文件,后面的输入语句将从文件中读出数据。如果要把 printf()的结果放入 output.out文件中,可以加上: freopen("output.out","w",stdout);所有数据都处理后加上:fclose(stdout);但是提交到 OJ上时要把这样的语句注释掉,因为 OJ不对程序中的文件处理语句进行处理。

input.in文件的创建方式:在菜单上选择:“文件”|“新建(CTRL+n)”|“文本文件”|“文件名”,输入 input.in,再

单击确定按钮,这样就在工程中创建一个名为 input.in的文本文件,可以从工作区中的FileView|Resource File中看到。打开并在 input.in中输入数据:

2 3

5 6

-5 8

10 -33【程序清单 1.7】1. #include<stdio.h>

2. int main()

3. {

4. int a, b;

5. freopen("input.in","r",stdin); // 从文件"input.in"中读出数据6. while(scanf("%d%d", &a, &b) != EOF)

7. {

8. printf("%d\n", a + b);

9. }

10. fclose(stdin); // 关闭文件11. return 0;

16

Page 25: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

12. }

运行的结果可以在 output.out文件中看到,里面的内容是:5113-233.下列是几种常见的 OJ上处理数据的方式(由于有些语句还没有学,可以等到要用

时再看):(1)输入的数据是 n 个案例的数据这时在 Input中的描述为:“先输入一个正整数 T,表示有 T种案例”。例如:Description

给你两个整数 a,b(0<=a<=1,000),计算 a+b的值。

Input

先输入一个正整数 T,表示有 T种案例,每个案例一行,每行有两个整数 a,b。

Output

每个案例先输出“Case id:”,id表示案例的序号,再输出 a+b的值。

Sample Input

3

2 3

5 2

0 5

Sample Output

Case 1:5

Case 2:7

Case 3:5

处理方式:用while(T--) {}循环 T 次的读入数据和处理数据的过程,也可以用 for(i=1;i<=T;i++)

{}进行循环。【程序清单 1.8】1. #include<stdio.h>

2. int main()

3. {

4. int T, a, b,id=1; // id是案例的序号,从 1开始5. scanf("%d ", &T) ; // T有 T种案例6. while(T--) // 循环 T 次7. {

8. scanf("%d%d", &a, &b);

9. printf("Case %d:%d\n",id++, a + b);

10. }

11. return 0;

12. }

17

Page 26: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(2)输入的数据有多组,最后以一个标记(如 0 0)结束这时在 Input中的描述中会出现“当输入为 0 0 时表示结束”之类的语句。例如:Description

给你两个整数 a,b(0<=a<=1,000),计算 a+b的值。

Input

有若干种案例,每个案例一行,每行有两个整数 a,b。 当输入为 0 0 时表示结束。Output

每个案例先输出“Case id:”,id表示案例的序号,再输出 a+b的值。

Sample Input

2 3

5 2

0 5

0 0

Sample Output

Case 1:5

Case 2:7

Case 3:5

处理方式:在循环条件中加上判断,如【程序清单 1.9】中的第 7、8行所示;或在循环体内加上终

止循环的判断语句,如【程序清单 1.10】中的第 5行所示。【程序清单 1.9】1. #include<stdio.h>

2. int main()

3. {

4. int a, b,id=1;//id是案例的序号,从 1开始5. while(scanf("%d%d", &a, &b) != EOF)

6. {

7. if(a==0&&b==0) // 如果输入为 0 0,输入的循环就结束8. break;

9. scanf("%d%d", &a, &b);

10. printf("Case %d:%d\n",id++, a + b);

11. }

12. return 0;

13. }

【程序清单 1.10】1. #include<stdio.h>

2. int main()

3. {

4. int a, b,id=1;//id是案例的序号,从 1开始

18

Page 27: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5. while(scanf("%d%d", &a, &b) != EOF&&!((a==0&&b==0)) // 如果 a、b同时为 0,就不执行循环体

6. {

7. scanf("%d%d", &a, &b);

8. printf("Case %d:%d\n",id++, a + b);

9. }

10. return 0;

11. }

19

Page 28: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习 题1.安装 VC或DEV-C++,分别输入本章的各个程序清单,并运行。2.一个激动的人一看到 2就说“Hello2”,看到 n就说“Hellon”。请编程实现。

(smu1541)输入有若干个正整数。输出Hello加上这个整数。如:

Sample Input:2

5

6

Sample Output:Hello2

Hello5

Hello6

3.请用“printf("");”语句编程,输出一些有创意的图形。

20

Page 29: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 2章 程序设计基础

导学本章是程序设计的基础,但学习时不要求面面俱到,要求能使用一些数据类型、按照 C

语言的语法编写科学计算方面的程序;能调用系统的函数;能处理简单的字符问题。本章的重点是用赋值语句、输入和输出语句实现顺序结构的程序设计。如果读者在程序调试时遇到问题时,请查阅附录 C 程序调试。

2.1数据类型在例 1.4中,要求两数和,先要声明两个变量来存放输入的数。这样的数可以是整数、

小数等。为表达不同类型的数据, C语言中提供多种数据类型,如表 2.1 所示。表 2.1 数据类型

数据类型 说明

基本类型

整型类型

基本整型(int) 代表有符号整数,占 4 个字节短整型(short int) 代表有符号整数,占 2 个字节长整型(long int) 代表有符号整数,占 8 个字节双长整型(long long int) 在 VC 中为:__int64,对应输入、输出的格式

是%I64d

字符型(char) 在 C++中增加了字符串(string)类型布尔型(bool) 在 C++中使用,C中不使用size_t类型 接受 sizeof()及用+-*联合的表达式的值

浮点类型单精度浮点型(float) 定义含小数的变量时使用,小数点后面的有效位

为 6~7位双精度浮点型(double) 定义含小数的变量时使用,小数点后面的有效位

为 15~16位枚举类型(enum) 用于将变量的值一一列出来 ,变量的值只限于列

举出来的值的范围内空类型(void)派生

指针类型(*) 可以把任一种数据类型定义为指针类型数组类型([ ]) 相同数据类型的元素按一定顺序排列的集合

21

Page 30: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

类型

结构体类型(struct) 自定义类型共用体类型(union) 自定义类型函数类型 函数的返回值可以是上面任一种数据类型不同变量占用的字节数可以用 sizeof(变量类型名)表达式来查看。例如,sizeof(int)可以

查看 int类型变量的字节数。另外,还可以在基本类型前加上修饰符来更具体地表示数据类型。主要的修饰符是:signed 有符号型unsigned 无符号型数据在存储单元中都是以补码形式存储的,存储单元中的第 1 个二进制位代表符号。不

同数据类型在存储单元中占用的字节数不一样,因而表达数的范围也不一样,如表 2.2、表2.3 所示。

表 2.2 整型数据常见的存储空间和值的范围类型 字 节

数取值范围

short int 2 -32768~32767,即-215~(215-1)int(long int) 4 -2147483648~2147483647,即-231~(231-1)unsigned short int 2 0~65535,即 0~(216-1)unsigned int 4 0~4294967295,即 0~(232-1)__int64( long long )

8 -9223372036854775808~9223372036854775807,即-263~(263-1)

signed char(char) 1 -128~127,即-27~(27-1)unsigned char 1 0~255,即 0~(28-1)

表 2.3 实型数据的有关情况类型 字节数 有效数字 数值范围(绝对值)

float 4 6 ±(3.4e-38~3.4e38)double 8 15 ±(1.7e-308~1.7e308)

说明:在VC中,double与 long double是一致的。

2.2变量与常量变量是内存中的一块区域,在程序运行过程中可以修改这块区域中存放的数值。变量

由两个要素构成:变量的名称和变量的类型。变量的名称是这个内存区域的唯一标识。变量22

Page 31: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

的类型决定了这个内存区域的的大小及对所存储数值的类型要求。在程序中,变量要先定义,再使用,被引用的变量要有初始值,否则系统会给出 0或一个无意义的值。

1.变量的定义一个变量在使用前要先定义它的类型。下列是三个定义变量类型的语句:int a,b;//定义两个整型变量double x1,x2=0.5;//定义两个双精度型的变量,其中 x2初始化为 0.5

char _ch;//定义一个字符型变量_ch

定义变量一般有以下三种格式:数据类型标识符 变量名;

数据类型标识符 变量名=初始值;

数据类型标识符 变量名 1[=初始值 1], 变量名 2[=初始值 2],…;

其中,变量类型标识符是一种数据类型;变量名是每个变量的名称,其命名的规则是:(1)要以字母或下划线开头。(2)可以由字母、数字和下划线组成。(3)不能与关键字(关键字见附录 A)同名。如 int、for、case等都不能作为变量名使用。(4)变量名区分大小写。(5)变量名的有效长度为 32 个字符。2.常量常量是程序需要访问的一个数据,它在程序的运行过程中不发生改变。常用的常量有

整型常量(如:123,0,-6)、实型常量(如:12.345、1.34e3,分别是浮点计数法与科学计数法)、字符常量(如:’A’、’a’、’9’、’+’,由一对单引号括起来的单个字符)、字符串常量(如:”12345”、”Hello”、”a+b”,由双引号括起来的一串字符)、转义字符(见 2.7.1

printf()函数)、符号常量等。符号常量是用 #define 语句定义的标识符,写在预编译处理。标识符的命名规则与变量

的命名规则相同。定义的形式是:#define <符号常量名> <常量>

例如:

#define MAX 100

#define PI 3.1415926

#define TRUE 1

23

Page 32: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

这里定义 MAX、PI、TRUE为符号常量,其值分别为 100、3.1415926、1。一些由常量符号代表的常量值在头文件 limits.h中已经有声明。例如,在文件 limits.h中

可以看到:#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */

#define INT_MAX 2147483647 /* maximum (signed) int value */

加上头文件 limits.h后,就可以使用 INT_MIN、INT_MAX。它们表示最小的整数和最大的整数。读者可以查阅该头文件了解详细信息。3.几种变量的使用方法下列代码是整型变量的使用方法。【程序清单 2.1】1. //int类型变量的用法2. #include <stdio.h>

3. int main()

4. {

5. int x; // 整型变量的定义6. scanf(“%d”,&x); // 整型变量的输入7. printf(“%d\n”,x); // 整型变量的输出8. return 0;

9. }

常见的几种变量的使用方法如表 2.3 所示。表 2.3 几种常见变量的使用

变量类型 变量的定义 变量的输入 变量的输出int int x; scanf(“%d”,&x); printf(“%d\n”,x);double double x; scanf(“%lf”,&x); printf(“%lf\n”,x);float float x; scanf(“%f”,&x); printf(“%f\n”,x);char char x; scanf(“%c”,&x); printf(“%c\n”,x);__int64 __int64 x; scanf(“%I64d”,&x); printf(“%I64d\n”,x);

变量要先定义,再使用。在 C语言中,几种不同的变量都要放在块首定义,而在 C++中,变量可以在任意位置定义。

2.3 const 修饰符我们可以使用 const关键字把一个变量声明转换成常量声明,如:const int months = 12;// months是一个符号常量,代表 12。

24

Page 33: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

也就是说 months 只能被引用,而不能被改变值。例如:

【程序清单 2.2】1. #include<stdio.h>

2. int main()

3. {

4. const int months = 12;

5. months =4; // 将出现错误6. printf("%d\n",months);

7. return 0;

8. }

第 5行试图改变months的值,将出现错误提示: error C2166: l-value specifies const object.

2.4 运算符和表达式运算是程序中最基本的操作,运算是通过运算符和表达式来实现的。例如,梯形上底

为 a、下底为 b、高为 h,求梯形面积 s的语句为:s = (a+b)*h/2;

语句中‘+’、‘*’、‘/’、‘()’、‘=’是运算符, (a+b)*h/2是表达式。这些运算符与操作数有一定的结合方法和先后顺序。它们与我们平时数学中运算符号与表达式的使用规则类似。

1. 运算符与优先级不同的运算符同在一个表达式中,有各自的先后顺序。表 2.3列出 C语言中主要运算符

的含义、优先级及结合和使用形式。表 2.4 运算符及优先级表

优先级

运 算符 名称或含义 使用形式 结 合方

向 说明1 [] 数组下标 数组名[常量表达式] 左到右

() 圆括号 (表达式)/函数名(形参表)

. 成员选 择(对象)

对象.成员名-> 成员选 择(指

针)对象指针->成员名

2 - 负号运算符 -表达式 右到左 单目 运算25

Page 34: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

符(类型) 强制类型转换 (数据类型)表达式++ 自增运算符 ++变量名/变量名++ 单目 运算

符-- 自减运算符 --变量名/变量名-- 单目 运算

符* 取值运算符 *指针变量 单目 运算

符& 取地址运算符 &变量名 单目 运算

符! 逻辑非运算符 !表达式 单目 运算

符~ 按位取反运算

符~表达式 单目 运算

符sizeof 长度运算符 sizeof(表达式)

3 / 除 表达式/表达式 左到右 双目 运算符

* 乘 表达式*表达式 双目 运算符

% 余数(取模) 整型表达式/整型表达式 双目 运算符

4 + 加 表达式+表达式 左到右 双目 运算符

- 减 表达式-表达式 双目 运算符

5 << 左移 变量<<表达式 左到右 双目 运算符

>> 右移 变量>>表达式 双目 运算符

6 > 大于 表达式>表达式 左到右 双目 运算符

>= 大于等于 表达式>=表达式 双目 运算符

< 小于 表达式<表达式 双目 运算符

<= 小于等于 表达式<=表达式 双目 运算26

Page 35: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

符7 == 等于 表达式==表达式 左到右 双目 运算

符!= 不等于 表达式!= 表达式 双目 运算

符8 & 按位与 表达式&表达式 左到右 双目 运算

符9 ^ 按位异或 表达式^表达式 左到右 双目 运算

符10 | 按位或 表达式|表达式 左到右 双目 运算

符11 && 逻辑与 表达式&&表达式 左到右 双目 运算

符12 || 逻辑或 表达式||表达式 左到右 双目 运算

符13 ?: 条件运算符 表达式 1? 表达式 2: 表达

式 3右到左 三目 运算

符14 = 赋值运算符 变量=表达式 右到左

/= 除后赋值 变量/=表达式*= 乘后赋值 变量*=表达式%= 取模后赋值 变量%=表达式+= 加后赋值 变量+=表达式-= 减后赋值 变量-=表达式<<= 左移后赋值 变量<<=表达式>>= 右移后赋值 变量>>=表达式&= 按位与后赋值 变量&=表达式^= 按位异或后赋

值变量^=表达式

|= 按位或后赋值 变量|=表达式15 , 逗号运算符 表达式,表达式,… 左到右 从 左 向 右

顺序同一优先级的运算符,运算次序由结合方向所决定。2. 表达式表达式是用运算符将运算对象连接形成的式子。常用的表达式有:(1)算术表达式:由算术运算符连接数值型运算对象构成,例如:3*(x+y)*(x+y);

27

Page 36: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(2)关系表达式:由关系运算符连接表达式构成,例如:x==0;(3)条件表达式:其格式为,条件表达式?表达式 1:表达式 2,例如:a>b?a,b;

(4)赋值表达式:由赋值运算符或自反赋值运算符(如:+=)连接表达式构成,例如:

x = a>b?a,b;

(5)逗号表达式:由逗号运算符连接表达式构成,x=0,y=1;(6)逻辑表达式:用逻辑运算符将关系表达式或逻辑量连接起来的式子,例如:

x==0||y==0

2.5 赋值语句给变量指定一个新值的过程称为变量的赋值,由赋值语句完成。赋值符号为“=”。赋值表达式的一般格式为:<变量>=<表达式>;

例如x = 3;

c = sin(3.1415926);

注意:(1)不同类型的变量之间赋值要进行强制转换其一般形式为:(类型名)(表达式)例如:int x=2,y=3;

double a;

a = (double)(x+y);//把 int型强制转换成 double型。(2)一般在“=”右边表达式中变量的值只是被使用,不会被改变。【例 2.1】一个学生有数学、英语、语文三门成绩,求总分和平均分。(smu1050)分析:在实际统计中,平均分会出现小数,其它是整数。 因此用 int 型变量

math、English、Chinese、sum分别表示数学、英语、语文、总分。用 double型变量 avage表示平28

Page 37: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

均分。程序的流程是:(1)输入math、English、Chinese的值;(2)计算 sum、avage;(3)输出 sum、avage。【程序清单 2.3】1. #include<stdio.h>

2. int main()

3. {

4. int math,English,Chinese,sum;

5. double avage;

6. printf("请输入数学 英语 语文成绩,数字间用空格隔开.\n");

7. scanf("%d%d%d",&math,&English,&Chinese); // %d与%d之间可以加空格8. sum = math+English+Chinese;

9. avage = (double)sum/3.0; // 这里的 double是用于强制转换。10. printf("总分=%d 平均分=%.2lf\n",sum,avage); // %.2lf 意思是 double类型的数据输出保

留两位小数 如果保留三位小数就%.3lf

11. return 0;

12. }

运行过程为:请输入数学 英语 语文成绩,数字间用空格隔开.

89 88 90↙总分=267 平均分=89.00

注意,有些与赋值相关的运算符还有:(1)+= 如 x += 5; 相当于 x =x+5;

(2)-= 如 x -= 5; 相当于 x =x-5;

(3)*= 如 x *= 5; 相当于 x =x*5;

(4)/= 如 x /= 5; 相当于 x =x/5;

(5)%= 如 x%=5; 相当于 x=x%5;

(6)++ 是自增运算符。如 i++; 表示先取 i的值,再将 i的值加 1;而++i是先把 i的值加 1,再使用。(7)-- 是自减运算符。如 i--; 表示先取 i的值,再将 i的值减 1;而--i是先把 i的值减

1,再使用。(8), 如 x=0,y=1;表示一句,按从左到右的顺序执行。从(1)到(5)形式的赋值语句是在原有的基础上进行“=”左侧给出的运算,还可以对其它

29

Page 38: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

的逻辑运算写这样的语句。

2.6 库函数函数是 C/C++语言中的一种程序组件单位,一个函数通常代表了一种数据处理的功能 。

C/C++提供的库函数也称为标准函数,见附录 D。如果要用数学函数,用户只需加上头文件(math.h)就可以直接使用。

【例 2.2】已知正方形的面积,求它的边长。(smu1030)分析:设正方形的的面积为 s,边长为 a,则 。在 C的库函数中已经提供了开方函数

sqrt(),只需在预编译中加入#include<math.h>就可以。【程序清单 2.4】1. #include<stdio.h>

2. #include<math.h> // 为了使用开方运算加的函数头文件3. int main()

4. {

5. double s=10.2,a;

6. a = sqrt(s); // 调用开方函数 sqrt(),计算结果赋值给 a

7. printf("a=%f\n",a);

8. return 0;

9. }

运行结果为:

a=3.193744库函数的调用就是按函数指定的参数个数及类型,将实际值传入,其函数值可以作为表达式或表达中的一部分进行使用。

2.7 输入与输出函数在预编译部分加入头文件 stdio.h后,可以使用 printf()、scanf()进行格式化的输出

与输入。

30

Page 39: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2.7.1 printf()函数printf()函数的作用是按控制字符规定的格式向终端(或系统隐含的输出设备)输出

指定的输出项。下面分别介绍 printf()函数的格式、格式字符、转义字符及 printf()函数的值。

1.格式printf的一般格式为:printf(”原样输出的字符及格式控制”,输出表列);其中输出表列中的变量与格式控制的个数及类型要一致。先看一段代码。【程序清单 2.5】1. #include <stdio.h>

2. int main()

3. {

4. int x=12,y=-10000;

5. float f=3.1415926;

6. double e=0.0000666000;

7. char c='a';

8. printf("x=%d,y=%d\n",x,y);

9. printf("f=%f,f=%.2f\n",f,f);

10. printf("e=%.2lf\te=%lf\te=%g\n",e,e,e);

11. printf("c=%c,c=%d\n",c,c);

12. printf("The end.\n");

13. return 0;

14. }运行结果为:

x=12,y=-10000

f=3.141593,f=3.14

e=0.00 e=0.000067 e=6.66e-005

c=a,c=97

The end.

程序说明:(1)第 8行表示输出 x、y。其中"x=%d,y=%d\n"内含原样输出的字符“x=,y=”和对输出

31

Page 40: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

表列格式进行控制的字符“%d”,“%d”表示要输出有符号的十进制整数, “\n”表示换行其中“\”是转义字符,“n”表示换行;(2)第 9行表示输出变量 f、f,浮点数对应的格式是%f,第 1 个 f按系统默认的方式

显示,即显示小数点后的 6位,第 2 个 f按小数点后输出两位的方式显示;(3)第 10行表示三次输出 e,第一次取小数 2位;第二次按系统指定的方式,取小数

点后 6位;第三次去掉多余的 0,并按 e-记数法表示。“\t”表示将当前位置移到下一个 tab

位置;(4)第 11行表示分别以字符和整数的方式输出字符 c,其中,用整数的方式输出字符

c,也就是 c的ASC码;(5)第 12行输出“The end.”并换行。

2.格式字符常用的格式字符如表 2.5 所示。

表 2.5 printf函数中常用的转换说明符转换说明 输出说明%c 一个字符%d和%i 有符号的十进制整数%e和%E 以指数形式输出实数,例如 2.3e+2、2.3E+2等,用 e还是 E与%后一致%f 以小数形式输出单、双精度数,隐含输出 6位小数%g和%G 根据数值不同自动选择%f或%e(%E)中总的位数最短的形式输出,

并去掉无意义的 0%o 输出无符号八进制数%p 输出指针%s 输出字符串%u 以无符号十进制形式输出整数%x和%X 使用十六进制数字 0f(0F)的无符号十六进制整数%% 打印一个百分号

%后可以带附加可选格式,形如%-m.nlf,“-”表示在显示域内向左对齐,不写表示向右看齐;“m”表示数据的长度;“n”表示小数点后的位数;“l”还可以用于长整型整数,加在格式符 d、o、x、u前面。

3.转义字符转义字符及其作用如表 2.6 所示。

表 2.6 转义字符及其作用32

Page 41: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

转义字符 输出结果\’ 输出一个英文状态下的单撇号“’”,单撇号“’”可

以直接打印\” 输出一个英文状态下的双撇号“””\? 输出一个英文状态下的问号“?”\\ 输出一个反斜线“\”\a 产生声音(alert)\b 将当前位置后退一个字符(backspace)\f 将当前的位置移到下一页的开头(form feed)\n 将当前的位置移到下一行的开头\r 将当前的位置移到本行的开头(carriage return)\t 将当前的位置移到下一个 tab位置\v 将当前的位置移到下一个垂直制表对齐点\o、\oo或\ooo其中 o代表一个八进制数字

与该八进制码对应的ASCII 字符\xh[h…]其中 h代表一个十六进制数字

与该十六进制码对应的ASCII 字符

【例 2.3】按如下格式输出工资表姓名 性别 基本工资张三 男 2056.8

李四 男 3210.5

分析:由于工资表中的上下的数据要对齐,数据间的间隔要一致,因此我们使用“ \t”让每个

数据占一个 Tab位置。【程序清单 2.6】1. #include <stdio.h>

2. int main()

3. {

4. printf("%s\t%s\t%s\n","姓名","性别","基本工资");

5. printf("%s\t%s\t%.1f\n","张三","男",2056.8);

6. printf("%s\t%s\t%.1f\n","李四","男",3210.5);

7. return 0;

8. }

4.printf()函数的值printf()函数的值是输出的字符个数及数值变量(int、float、double等)个数的和。请读者自

33

Page 42: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

己验证。

2.7.2 scanf()函数scanf()函数的作用是从键盘上按指定的格式输入数据。下面分别介绍 scanf()函数

的格式、格式字符、及 scanf()函数的值。1.格式scanf函数的一般格式为:scanf(“格式控制”,地址表列);

先看下列代码:【程序清单 2.7】1. #include <stdio.h>

2. int main()

3. {

4. int a;

5. char c;

6. double d;

7. float f;

8. scanf("%d%c%lf%f",&a,&c,&d,&f); // 只能 d与 f间用空格,如 8f88.8 6.666

9. printf("%d %c %lf %f\n",a,c,d,f);

10. scanf("%d %c %lf %f",&a,&c,&d,&f); // 各数据间用空格,如 8 f 88.8 6.666

11. printf("%d %c %lf %f\n",a,c,d,f);

12. scanf("%d,%c,%lf,%f",&a,&c,&d,&f); // 各数据间用“,”号,如 8,f,88.8,6.666

13. printf("%d %c %lf %f\n",a,c,d,f);

14. scanf("a=%d c=%c d=%lf f=%f",&a,&c,&d,&f); // 前一个输入不可回车,紧接着输入 a=8 c=f

d=88.8 f=6.666

15. printf("%d %c %lf %f\n",a,c,d,f);

16. return 0;

17. }运行的过程为:8f88.8 6.666↙

8 f 88.800000 6.666000

8 f 88.8 6.666↙

8 f 88.800000 6.666000

34

Page 43: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

8,f,88.8,6.666↙

8 f 88.8 00000 6.666000

a=8 c=f d=88.8 f=6.666↙

8 f 88.8 00000 6.666000以上的每一行分别对应程序中的第 8~15行。也就是说输入数据的顺序与格式要与格式控制内的完全一致。注意:地址表列中的变量一定要使用地址,也就是在一般变量前加上“&”。任一类型

变量的变量名代表变量的值,变量名前面加上&就是这变量的地址。例如:int x;中,x用于存放变量的值,&x是这变量的地址。

2.格式字符scanf()中%后的格式字符与 printf中的一致。

表 2.7 scanf函数中常用的格式字符转换说明 输入说明%c 输入一个字符,空格也是字符%d和%i 输入有符号的十进制整数%e , %E ,%g,%G

与%f的作用同%f 以小数或指数形式输入实数%o 输入无符号的八进制数%s 输入一个字符串%u 输入无符号的十进制整数%x和%X 输入无符号十六进制整数scanf函数中常用的格式附加字符有“l”、 “h”、 域宽。其中,附加字符“l”用来输入长

整型数据(如:%ld,%lo,%lu,%lx,%lf,%le);“h”:用于输入短整型数据(如:%hd,%ho,%hx);域宽:指定输入数据所占的宽度,如 scanf("%6lf",&a);输入的数只取 6位。在格式控制中的其它字符为照样输入的部分。

3.scanf()的函数值scanf()的函数值是输入变量的个数。如 scanf("%6lf",&a)的值为 1,scanf("%6lf%d",&a,

%b)的值为 2。【例 2.4】先输出提示行“请你按格式YYYY-MM-DD输入一个日期,结束请按回车。”,

再从键盘输入一个日期,然后按格式“你输入的日期是 YYYY年MM月DD日。”输出这个日期。

【程序清单 2.8】1. #include <stdio.h>

35

Page 44: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2. int main()

3. {

4. int year,month,day;

5. printf("请你按格式YYYY-MM-DD输入一个日期,结束请按回车。\n");

6. scanf("%d-%d-%d",&year,&month,&day);

7. printf("你输入的日期是%d年%d月%d日。\n",year,month,day);

8. return 0;

9. }运行过程为:请你按格式YYYY-MM-DD输入一个日期,结束请按回车。2013-9-23↙

你输入的日期是 2013年 9月 23日。注意:(1)执行第 6行时,输入的年月日日之间要有一个“-”号,与 scanf中的格式一致;(2)为了使输出的结果与要求一致,可以把结果复制到 printf()的引号中,再把数据

部分用格式替代。即,第 7行复制“你输入的日期是 YYYY年MM月 DD日。”后,将YYYY、MM、DAY 都改成%d就可以。

2.7.3 字符数据的输入输出单个字符的输入、输出除了用 printf()、scanf()实现外,还可以用 putchar()函数和

getchar()函数实现。putchar函数的一般格式为:putchar(c);

putchar是 put charcter的缩写,c是 char型的变量。表示输出一个字符 c。getchar函数的一般格式为:getchar();

getchar是 get charcter的缩写,getchar()的值是 char类型的。表示输入一个字符 c,包括空格、回车等。一般可以用来读回车字符,以免影响下面的输入

【例 2.5】从键盘上输入Hi,然后输出到屏幕。分析:Hi中有 2 个字符分别用 c1、c2表示,先用 getchar()输入,再用 putchar()输出。【程序清单 2.9】1. #include <stdio.h>

36

Page 45: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2. int main()

3. {

4. char c1,c2;

5. c1 = getchar(); // 输入一个字符6. c2 = getchar();

7. putchar(c1); // 输出一个字符8. putchar(c2);

9. putchar('\n'); // 换行10. return 0;

11. }输入Hi

输出结果为:Hi

2.8 案例及分析【例 2.6】求若干个数的和。(smu1005)分析:由于若干个数是不定的数,因此用 n表示任一个数,s表示和。开始 s=0,每读一个数

就加到 s中,当所有的数被读后,s就为所求。如图 2.1 所示。

图 2.1 例 2.6的流程图

37

开始

结束

是否有n输入Y N

int n,s=0;

s=s+n输 出s

Page 46: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

【程序清单 2.10】1. #include<stdio.h>

2. void main()

3. {

4. int s=0,n;//s 放这些数的和,开始为零5. while(scanf("%d",&n)!=EOF)

6. {

7. s=s+n; // 每读入一个数,就加一次到 S中8. }

9. printf("%d\n",s); // 输出这些数的和10. }

【例 2.7】已知三角形△ABC的三边 a、b、c求这三角形∠A的度数。(smu1542)分析:输入的是 double类型的变量 a、b、c的值,输出的是∠A的度数。计算公式是:

, A=acos(cos A)*180/π。【程序清单 2.11】1. #include <stdio.h>

2. #include <math.h>

3. #define PI 3.1415926

4. int main()

5. {

6. double a,b,c,A,CA;//设计变量7. while(scanf("%lf %lf %lf",&a,&b,&c)!=EOF) // 读入数据8. {

9. CA = (b*b+c*c-a*a)/2/b/c; // 计算角A的余弦值10. A = acos(CA)*180/PI; // 计算反余弦函数,结果转化成度11. printf("%.1lf\n",A); // 输出角A,并换行12. }

13. return 0;

14. }运行的过程为:5 3 4↙90.03 3 3↙60.0

38

Page 47: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

【例 2.8】输入若干组 x、y的值,编程计算表达式 x^y的值,分别输出它们的整数部分和小数部分。(smu1081)分析:x^y对应函数 pow(x,y);而 double modf(double val, double *iptr)函数是把 val的小数部

分作为值算出,整数部分存到 iptr指向的单元。【程序清单 2.12】1. #include <stdio.h>

2. #include <math.h>

3. int main()

4. {

5. double x,y,val,fraction,integer;

6. while(scanf("%lf %lf",&x,&y)!=EOF) // 读入输入流中的各组数据7. {

8. val = pow(x,y);

9. fraction = modf(val,&integer);

10. printf("The whole and fractional parts are %.0lf and %lf\n", integer,fraction);

11. }

12. return 0;

13. }运行过程为:2.1 2↙The whole and fractional parts are 4 and 0.410000

4.5 6.7↙The whole and fractional parts are 23797 and 0.089408

注意:第 9行的函数 modf(val,&integer)中第 2 个参数的变量类型是地址,也就是指针类型,要把变量 integer的地址传入。

【例 2.9】交换两变量 a、b的值。分析:我们可以借用一个与 a、b同类型的变量空间 temp来交换,如图 2.2 所示。

39

Page 48: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 2.2 变量 a,b 交换图【程序清单 2.13】1. #include <stdio.h>

2. int main()

3. {

4. int a=5,b=-6,temp;

5. printf("交换前 a=%d,b=%d\n",a,b);

6. //交换 a、b

7. temp = a; //把 a的值存入 temp中8. a = b; //把 b的值存入 a中,a原有的值消失,但已经存在 temp中9. b = temp;//把 temp的值存入到 b中10. printf("交换后 a=%d,b=%d\n",a,b);

11. return 0;

12. }

运行的结果为:交换前 a=5, b=-6

交换后 a=-6, b=5

程序中在第 7~9行的 3 个语句,就把 a、b的值对换了。

2.9进阶每个数据在计算机内的表示是二进制数,也就是每个数都有若干位 0或 1组成,位及

位之间可以进行一些运算。C语言提供的位运算有:&(按位与)、|(按位或)、̂(按位异或)、~(取反)、<<(左移)、>>(右移)。它们是将参加运算的数据按二进制位进行运算。位运算可以节省计算机内的运行时间。(1)&(按位与)表示:如果两个相应的二进制位都为 1,结果为 1,否则为 0。例如:

51&21=17,如图 2.3 所示:

40

Page 49: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 2.3 “&”运算图(2)|(按位或)表示:如果两个相应的二进制位至少有一个为 1,结果为 1,否则为 0。

例如:51|21=55,如图 2.4 所示:

图 2.4 “|”运算图(3)^(按位异或)表示:如果两个相应的二进制位相同,结果为 0,否则为 1,有与 0

异或保留原值的特点。例如:51^21=38,如 2.5 所示:

图 2.5 “^|”运算图(4)~(取反)表示:对一个二进制数按位取反,即 0 改为 1,1 改为 0。例如: ~ 00110011 11001100

(5)<<(左移)表示:将一个二进制数左移若干位,右边补 0。如 a=8 时,左移一位就是: 0001000 0010000

即 a<<1的值为 16。左移 1 位相当于该数乘以 2,左移 n 位相当于该数乘以 2n。(6)>>(右移)表示:将一个二进制数右移若干位,左边补 0。如 a=8 时,右移一位就是:

0001000 0000100

即 a>>1的值为 4。右移 1 位相当于该数除以 2,右移 n 位相当于该数除以 2n。【任务 2.1】请你编程计算下列位运算的结果。2&3、2|3、2^3、~2、2<<1、2>>1

分析:可以直接用 printf()函数输出位运算的表达式。【程序清单 2.14】

41

Page 50: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include <stdio.h>

2. int main()

3. {

4. printf("2&3=%d\n",2&3);

5. printf("2|3=%d\n",2|3);

6. printf("2^3=%d\n",2^3);

7. printf("~2=%d\n",~2);

8. printf("2<<1=%d\n",2<<1);

9. printf("2>>1=%d\n",2>>1);

10. return 0;

11. }运行的结果为:2&3=2

2|3=3

2^3=1

~2=-3

2<<1=4

2>>1=1

思考:请你将各个数转成二进制数,再尝试位运算,并观察结果。提示:位运算有很多应用,可以加快程序在机内的运行时间,比如整除运算 x/2,相当

于 x的二进制数右移一位,可以表示成 x>>1。同样对于 x*2,可以表示成 x<<1。请有兴趣的读者深入钻研。

42

Page 51: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题

1.计算 ,x=1、2、3。(smu1544)

2.计算 。(smu1545)

3.计算 。(smu1546)4.请你编程输出:“!@#$~%^&*()_+|\=-"": ”。(smu1031)5.请输出“%%”。(smu1045)

6.输入一个用 24小时制表示的时间(h:m),请你编程将它转换为 12小时制表示的时间后输出。(smu1305)

7.输入球的半径,请求出它们的体积。∏取 3.14159。 球的体积公式为:v=4πR³/3。(smu1328)

8.学 C语言了,可以编程解决很多问题,但没有一个 C语言中的函数是会四舍五入的,请你编程解决这个问题。如输入 2.055 0.154 10.159 99.999,你将要输出 2.06 0.15 10.16

100.00。(smu1525)9.求平面上两点的距离。(smu1037)

10.任意输入一个正整数,请编程指出它的个位数。(smu1009)

11.1724年,德国人华伦海特制定了华氏温标,他把一定浓度的盐水凝固时的温度定为 0℉,把纯水的冰点温度定为 32 ℉,把标准大气压下水的沸点温度定为 212℉,中间分为 180等份,每一等份代表 1 度,这就是华氏温标,用符号 F表示。而摄氏温度是 C,冰点时温度为 0摄氏度,沸点为 100摄氏度。请你能编程把华氏温度转成摄氏温度。(转换公式是:c=(f-32)*5/9)(smu1039)

12.在平面上,已知□ABCD中的三个点 ABC的坐标,请编程求出第四个点 D。(smu1184)

13.有六个 三角函数: sin( x)、 cos( x)、 tan( x)、 cot( x) =1/

43

Page 52: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

tan(x)、csc(x)=1/sin(x)、sec(x)=1/cos(x)。同一个角的六个三角函数相加会得到什么。请你编程计算。(smu1089)

14.给你平面上有三个点A、B、C的坐标,求∠ABC的大小。(smu1172)15.已知三角形的两边和夹角的度数,请按公式 S=a*b*sin(C)/2(这里 a、b是三角

形的两边,C是这两边的夹角)求三角形的面积。其中 π取 3.1415926。(smu1275)16.当 x 很小时 e^x≈1+x,现在对不同的 x,请你求出它们的误差的绝对值。(smu1092)

17.输入一个十六进制数 ,输出相应的十进制数。十六进制的基数是0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f。如:输入 a1,输出 161。(smu1095)

18.数在生活中有各种各样的表示法。时间的小时是 24进制,时间的分是 60进制,计算机内的数用二进制,我们平时用十进制。请你把一个十进制的数转成八进制和十六进制。(smu1040)

19.游戏大王今天的作业是按序求下列逗号表达式的值。(smu1155)a = 3+x,6+x;

a = (3+x,6+x);

a = ((x=3*5,x*4),x+5);

a = x=3,6*3;

a = (x=3,6*3);

对不同的 x,游戏大王请你编程求出 a的值。20.统计伙食费。例如,某个学生早餐 3 元,午餐 7 元,晚餐 7 元,这个月的天数为 30

天,那么请编程统计出他这个月的伙食费。(smu1330)

44

Page 53: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 3章 逻辑思维及分支程序设计—分支语

导学这一章的重点是掌握 if、switch语句和条件表达式的使用、理解和使用ASCII码。请读者

先掌握例题中的逻辑判断方式,再尽量解决习题中的问题。

3.1 关系运算和关系表达式在程序中,常常要表达两个量之间的大小关系,关系运算符就是对两个量之间进行比

较的运算符,如表 3.1 所示。表 3.1 C的关系运算符

关系运算符 含义 样例< 小于 a<b<= 小于或等于 m+n<=10> 大于 x>y-3>= 大于或等于 6>=9= = 等于 x-y= =z!= 不等于 c!=d

由关系运算符将两个表达式连接而成的式子称为关系表达式。一个关系表达式的值是一个逻辑值,关系运算的结果是一个逻辑值,当关系表达式成立时,其值为真,常用‘1’

表示;当关系表达式不成立时其值为假,常用‘0’表示。在 C语言中,非 0的数被认为真,0为假。在 C++中,可以直接用 true和 false分别表示真假。关于优先次序:

45

Page 54: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(1)表 3.1中前 4种运算符的优先级别相同,后 2种也相同。前 4种高于后 2种。(2)关系运算符的优先级低于算术运算符。(3)关系运算符的优先级高于赋值运算符。注意:作为相等的比较运算符不可写成‘=’。

3.2 逻辑运算符和逻辑表达式关系运算的结果是 1 个逻辑值,真(true)或假(false),逻辑值之间可以进行与、或、

非的运算。对两个逻辑量之间进行运算的运算符是逻辑运算符,如表 3.2 所示。表 3.2 逻辑运算符及其含义

运算符 含义 样例 说明&& 逻辑与 a&&b 如果 a和 b 都为真,则结果为真,否则为假|| 逻辑或 a||b 如果 a和 b有一个以上为真,则结果为真,否则为假! 逻辑非 !a 如果 a为真,则!a为假;如果 a为假,则!a为真由逻辑运算符将两个表达式连接而成的式子称为逻辑表达式。逻辑表达式的值与关系

表达式的值一样,为真或假。表 3.3 显示 a和 b各种组合的逻辑运算真值表。表 3.3 逻辑运算真值表

a b a&&b a||b !a !b

真 真 真 真 假 假真 假 假 真 假 真假 真 假 真 真 假假 假 假 假 真 真一个逻辑表达式中可以包含多个逻辑运算符,这些运算符的优先次序如下:(1)! &&||,即“!”为三者中最高的。(2)逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算术运算符。例如:(a>b)&&(x= =y) 可以写成 a>b && x= =y

(!a)||(x<y) 可以写成 !a || x<y

在逻辑运算中,不是所有的逻辑运算符都被执行,只有在必须执行下一个逻辑运算符才能求出解时,才执行该运算符。如:(1)对于 a && b && c,只有 a为真时才判断 b,a和 b 都为真时才判断 c。(2)对于 a || b || c,只要 a为真,就不必判断 b和 c,c要当 a和 b 都为假时才会被判

断到。46

Page 55: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

注意:对数学中表示多个数据间的比较关系,表达式要加以拆分机器才可识别。例如:当你要表达: -10<x<10

在代码中要拆成 -10<x && x<10

3.3 分支结构

3.3.1 if语句if语句有三种形式:形式 1(如图 3.1 所示):if ( 表达式 )

{

语句/语句组}

图 3.1 if语句图如果表达式 的值为真(非零),则其后的语句/语句组 被执行。如果表达式的值为假

(等于零),则其后的语句/语句组 被忽略。

形式 2(如图 3.2 所示):if ( 表达式 ) {语句/语句组 1

47

表达式

语句/语句组

真 假

Page 56: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

}else{语句/语句组 2

}

图 3.2 if else 图如果表达式 的值为真(非零),则其后的语句/语句组 1 被执行,语句/语句组 2 被忽

略。如果表达式的值为假(等于零),则其后的语句/语句组 1 被忽略,语句/语句组 2 被执行。

形式 3(如图 3.3 所示):if ( 表达式 1 ) {语句/语句组 1

}else if( 表达式 2 ){语句/语句组 2

}else {语句/语句组 3

}

48

表达式

语句/语句组1

语句/语句组2

Page 57: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 3.3 if …else if…else 图如果表达式 1的值为真(非零),则其后的语句/语句组 1 被执行;如果表达式 1的值

为假,则判断表达式 2的值;如果表达式 2的值为真(非零),则其后的语句/语句组 2 被执行,为假(等于零),则其后的语句/语句组 2 被忽略,语句/语句组 3 被执行。注意:(1)语句/语句组中只有一句时,其外的{}可以省略,但是为了代码的逻辑性和以后

增加语句的方便性,最好都要有{};(2)else if 可以有多个。【例 3.1】求下列分段函数的值。(smu1090)

分析:执行一次计算的过程如图 3.4表示:

49

表达式1

语句/语句组1

语句/语句组2

表达式2真 假

语句/语句组3

Page 58: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 3.4 分段函数流程图【程序清单 3.1】1. #include<stdio.h>

2. int main()

3. {

4. double x,y;

5. scanf("%lf",&x);

6. if(x>=0)

7. {

8. y = 2*x+1;

9. }

10. else

11. {

12. y = 1;

13. }

14. printf("y=%lf\n",y);

15. return 0;

16. }

运行过程为:2↙

y=5.000000

if语句可以嵌套使用。在没有大括号来标识的情况下,else语句被解释成与它最近的 if

语句共同构成一句。例如:if ( i > 0 ) /* 没有大括号 */ if ( j > i )

50

开始

结束

定义x,y

输入x

输出y

x≥0Y N

y=2x+1 y=1

Page 59: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

x = j; else x = i;如果上面的例子中 else是与第一个 if配对的,则应该写成如下格式:if ( i > 0 ) { /* 加上括号 */ if ( j > i ) x = j;}else x = i;

【例 3.2】三角形按边的分类如下:

从键盘输入三角形的三边,请你编程判断这个三角形的类型。结果只能是等边三角形、等腰三角形、不等腰三角形中的一种。分析:设三角形的三边分别为 a、b、c,则判断的过程如图 3.5 所示:

51

三角形等边三角形

不等边三角形等腰三角形

不等腰三角形

Page 60: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 3.5 判断三角形类型流程图【程序清单 3.2】1. #include<stdio.h>

2. int main()

3. {

4. int a,b,c;

5. printf("请输入三角形三边\n");

6. scanf ("%d%d%d",&a,&b,&c);

7. if(a+b>c&&a+c>b&&b+c>a) // 三角形两边之和大于第三边8. {

9. if(a==b&&a==c&&b==c)

10. {

11. printf("等边三角形\n");

12. }

13. else if(a==b||a==c||b==c)

14. {

15. printf("等腰三角形\n");

16. }

17. else

18. printf("不是等腰三角形\n");

19. }

20. else

21. printf("构不成三角形\n");

22. return 0;

23. }

52

开始

结束

a+b>c&&a+c>b&&b+c>aY N

请输入三角形的三边a,b,c

构不成三角形a==b&&a==c&&b==c

等边三角形 a==b||a==c || b==c

Y N

等腰三角形 不是等腰三角形Y N

Page 61: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

运行过程为:请输入三角形三边3 4 5↙不是等腰三角形思考:你是否有更简便的判断方法。

3.3.2 switch语句条件语句 if对条件判断的结果只有 2 个分支真和假,要控制比较复杂的条件分支操作

就要使用 switch 和 case 语句。switch 语句常用的结构是:switch ( 表达式 ){

case 常量 1 : 语句/语句组 1;break;case 常量 2 : 语句/语句组 2;break;…case 常量 n: 语句/语句组 n; break;default : 语句/语句组 n+1;

}如图 3.6 所示。

图 3.6 switch 流程图switch 语句可以包含任意数目的 case 条件, 但是不能有两个 case 后面的常量表达式完

全相同。进入 switch 语句后,首先表达式 的值被计算、并与 case 后面的常量表达式逐一匹配,当与某一条 case分支的常量表达式匹配成功时,则开始执行它后面的语句/语句组 ,然后顺序执行之后的所有语句,直到遇见一个整个 switch 语句结束,或者遇到一个 break

53

表达式

语句/语句组1 语句/语句组2 语句/语句组n 语句/语句组n+1…

常量1 常量2 常量n default

Page 62: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

语句时结束(break 语句后面会有介绍)。 如果表达式的值与所有的常量表达式的值都不相同,则从 default后面的语句开始执行到 switch 语句结束。各 case分支后的“常量表达式值”必须是整数类型或字符型的。如果各个 case 分支后面的语句/语句组彼此独立,即在执行完某个 case 后面的语句/语

句组后,不需要顺序执行下面的语句,可以用 break 语句将这些分支完全隔开。在 switch语句中,如果遇到 break语句,则整个 switch语句结束。

default 分支处理除了明确列出的所有常量表达式以外的情况。switch语句中只能有一个 default 分支,它不必只出现在最后,事实上它可以出现在任何 case 出现的地方。 switch 后面的表达式 与 case 后面的常量表达式 必须类型相同。可以多个 case语句对应一个语句或语句组。例如:

switch ( 表达式 ){

case 常量 1 : case 常量 2 : …case 常量 n: 语句/语句组 n;default : 语句/语句组 n+1;

}如果把 switch格式写成:switch ( 表达式 ){

case 常量 1 : 语句/语句组 1;case 常量 2 : 语句/语句组 2;…case 常量 n: 语句/语句组 n;default : 语句/语句组 n+1;

}则意味着各个 case的情况都会逐个被判断。例如:【例 3.3】对于任意输入的数字(1~7),输出对应的星期。(smu1086)

分析:这是一个使用 switch语句的问题,输入的整数 n就是 switch中的判断表达式,n

的值由键盘输入,n可以有若干次输入。【程序清单 3.3】1. #include<stdio.h>

2. int main()

54

Page 63: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

3. {

4. int n;

5. while(scanf("%d",&n)!=EOF)

6. {

7. switch(n)

8. {

9. case 1:printf("Monday\n");break;

10. case 2:printf("Tuesday\n");break;

11. case 3:printf("Wednesday\n");break;

12. case 4:printf("Thursday\n");break;

13. case 5:printf("Friday\n");break;

14. case 6:printf("Saturday\n");break;

15. case 7:printf("Sunday\n");break;

16.

17. default: printf("Error.\n");

18.

19. }

20. }//while

21. return 0;

22. }

运行过程为:1↙Monday4↙Thursday7↙Sunday5↙Friday象 if语句一样,case语句也可以嵌套使用,请大家自己尝试。

3.4条件表达式【例 3.4】找出两个数中的最大数。(smu1004)

分析:将 a、b 两数的最大值放入 c中,可以直接用:if(a>b)

c = a;

else

55

Page 64: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

c = b;

也可以用:c = a>b?a:b;

这就是条件表达式,其格式是:(条件表达式)?A:B;

其中,A、B是一个值,意思是条件表达式的值为真时就取A的值,否则取 B的值。如图 3.7 所示。

图 3.7 条件表达式流程图【程序清单 3.4】1. #include<stdio.h>

2. int main()

3. {

4. int a,b;

5. scanf("%d%d",&a,&b);

6. printf("The max number is %d.\n",(a>b)?a:b);

7. //可以写成:(a>b)?printf("The max number is %d.\n",a):printf("The max number is %d.\n",b);

8. return 0;

9. }

运行过程为:4 5↙The max number is 5.

3.5 ASCII码在计算机中,所有的数据在存储和运算时都要使用二进制数表示,而具体用哪些二进

制数字表示哪个符号,就要有个相同的编码规则。ASCII 编码 就是美国有关的标准化组织出台的一套标准字符编码。

56

条件表达式

执行A 执行B

真 假

Page 65: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

ASCII 码使用指定的 7 位或 8 位二进制数组合来表示 128 或 256 种可能的字符,见附录 E——常用字符与ASCII码对照表。标准ASCII 码也叫基础ASCII码,使用 7 位二进制数来表示所有的大写和小写字母、数字 0 ~9、标点符号、以及在美式英语中使用的特殊控制字符,共有 128 个。后 128 个称为扩展 ASCII 码,目前许多基于 x86 的系统都支持使用扩展(或

“高”)ASCII。扩展ASCII 码允许将每个字符的第 8 位用于确定附加的 128 个特殊符号字符、外来语字母和图形符号。同时还要注意,在标准 ASCII中,其最高位用作奇偶校验位,奇偶校验是指在代码传

送过程中用来检验是否出现错误的一种方法。本书讨论和使用的是标准ASCII码。当 char类型的变量值用 int类型表示时就是对应的 ASCII码值,反之,把 int类型的变

量值看作ASCII码,用 char类型输出的是对应的字符(smu1054)。如【程序清单 3.5】所示。【程序清单 3.5】1. #include <stdio.h>

2. int main()

3. {

4. int a=98;

5. char ch='*';

6. printf("%d %c\n",a,a); // 前者看作是 a的值,后者是ASCII码为 a对应的字符7. printf("%d %c\n",ch,ch); // 前者对应的是ASCII码,后者看作是字符

8. return 0;

9. }

运行结果为:98 b

42 *

【程序清单 3.5】中,a是整型变量,按“%d”的形式输出是 a的值 98,按“%c”形式输出是 ASCII码为 a=98对应的字符 b。同样,ch为字符型变量,按“%c”形式输出就是字符,按“%d”的形式输出是它的ASCII码。

【例 3.5】有时我们要将一个小写字母改成大写字母,请你编程实现之。(smu1019)

分析:由ASCII码表看出,将输入的小写字符的 ASCII码减 32,就是相应的大写字母的ASCII码,再按字符方式输出就可以。

【程序清单 3.6】1. #include<stdio.h>

57

Page 66: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2. int main()

3. {

4. char h;

5. while(scanf("%c",&h)!=EOF)

6. {

7. getchar(); // 读回车字符8. printf("%c\n",h-32); // 大写字符的ASCII码比小写字符的ASCII码小 32

9. } // while

10. return 0;

11. }

运行过程为:f↙F

t↙T

y↙Y

思考:如果对于输入的字符,是大写就转小写,是小写就转大写,如何设计程序。

3.6 案例及分析

【例 3.6】对于每个输入的正整数,判断是否能被 3整除,能输出“Yes”,不能就输出”No“。(smu1008)

分析:

设输入的正整数有若干个,我们用循环处理。一个数 x能被 3带整除,就是除以 3的余数为 0,即 x%3==0。

【程序清单 3.7】1. #include <stdio.h>

2. int main()

3. {

4. int x;

5. while(scanf("%d",&x)!=EOF)

6. {

7. if(x%3==0) // 判断 x能否被 3整除8. {

9. printf("%s\n","Yes");

58

Page 67: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

10. }

11. else

12. {

13. printf("%s\n","No");

14. }

15. } // while

16. return 0;

17. }

运行的过程为:6↙Yes7↙No90↙Yes-5↙No

【例 3.7】求一元二次方程的根,并将两根按从小到大的顺序输出。(SMU1018)分析:设一元二次方程为 ax2+bx+c=0,判别式为 d = b*b-4*a*c;

一次计算的流程如图 3.8 所示:

图 3.8 求一元二次方程的根的流程图59

输入a,b,c

a=0

d=b²-4ac

d<0

求两根x1,x2

输出两根x1,x2

Y

N

N

Y

Page 68: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

【程序清单 3.8】1. #include <stdio.h>

2. #include <math.h>//为了调用系统函数3. int main()

4. {

5. double a,b,c,x1,x2,d,p,q,tx;

6. while (scanf("%lf%lf%lf",&a,&b,&c)!=EOF)

7. {

8. if(a==0)

9. continue;

10. d = b*b-4*a*c; // 计算判别式11. if(d<0)

12. {

13. printf("Unanswered\n");

14. continue;

15. }

16. else

17. {

18. p = -b/(2*a);

19. q = sqrt(d)/(2*a);//开方函数20. x1 = p-q;

21. x2 = p+q;

22.

23. }

24. if(x1<x2) // 使大根在前25. {

26. tx = x1; x1 = x2; x2 = tx;

27. }

28. printf("x1=%.2lf x2=%.2lf\n",x1,x2);

29. }

30. return 0;

31. }

运行过程为:1 2 1↙x1=-1.00 x2=-1.00

1 -2 -3↙x1=3.00 x2=-1.00

3.7 进阶【任务 3.1】有 n 个数,请你编程计算它们最大的数、最小数及平均数。(smu1234)

60

Page 69: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Input

输入的数有若干个,都是 int类型,放在文件 intput.in中,数字之间用空格隔开。Output

输出这些数的最大的数、最小数及平均数。要求平均数的结果保留小数点后两位。Sample Input

90 80 88 -100 98888 3333

Sample Output

最大数是=98888,最小数=-100,平均数=17063.17

分析:求和的方法是:开始设和为 0,每读入一个 x就加入到和中。当所有的数读入后,就求

出和了。求最大数的方法是:开始设最大数 max是机内最小数(或者是问题中的最小数),每

读入一个数 x就判断是否会大于这个 max,会的话就用 x替换 max的值。这样每次对读数的操作后,都保证了max是目前的最大值。求最小数的方法是:开始设最小数 min是机内最大数(或者是问题中的最大数),每

读入一个数 x就判断是否会小于这个 min,会的话就用 x替换 min的值。这样每次对读数的操作后,都保证了min是目前的最小值。

【程序清单 3.9】1. #include <stdio.h>

2. #include <limits.h> // 为了获得机内的最大数 INT_MAX和最小数 INT_MIN

3.

4. int main()

5. {

6. double average;

7. int x,max=INT_MIN,min=INT_MAX,sum=0,num=0;

8. while(scanf("%d",&x)!=EOF) // 每次读入一个数,读到文件尾9. {

10. sum += x; // 求和11. if(x>max) max = x;

12. if(x<min) min = x;

13. num++; // 每次多一个数,相当于计数器14. }

15. average = (double)sum/num; // 求平均数,由于类型不一致,需要强制转换16. printf("最大数是=%d,最小数=%d,平均数=%.2lf\n",max,min,average);

17. return 0;

18. }

运行过程为:90 80 88 -100 98888 3333↙

61

Page 70: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

^Z

最大数是=98888,最小数=-100,平均数=17063.17

程序说明:(1)求最大数时,开始的 max一定是问题中的数或比问题中的数小,以保证后面的

最大数能被正确判断,否则答案会不对。例如对于 3、5、8、-2,如果取max=9,则 max的值永远不会改变。同样,求最小数时,开始的min一定是问题中的数,或比问题中的数大。为了保险起见,一般用机内或问题中的最小数和最大数来代替。(2)32位机的最大数是 16进制的 7fffffff,最小数是 16进制的 80000000。其实只要加

上头文件 limits.h,就可以得到最大数 INT_MAX和最小数 INT_MIN。(3)第 15行中 average是 double型,而 sum和 num是 int型,因此要进行强制转换,

也就是前面加上转换后的类型。【任务 3.2】Excel表中列的序号(smp1251)

Description

Excel表如图 3.9 所示,列的序号是A、B、…、Z,AA、…。如果序号是用 1、2、…编号,那么从 A到ZZZ就对应 1到 18278的数字。请你编程将 A、B、…、Z,AA、…、ZZZ 从字母转变成数字。

图 3.9 Excel表Input

输入有若干个案例,每个案例 1行。每行的第 1 个数据是 1、2或 3,表示后面大写字母的个数,接着后面是指定个数的大写字母。

Ouput

每个案例输出一行,前部分是输入的大写字母,后部分是对应的序号,中间为“:”。Sample Input

1 B

2 AA

2 BA

3 ABC

1 Z

3 ZZZ

62

Page 71: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Sample Output

B:2

AA:27

BA:53

ABC:676

ZZZ:18278

分析:(1)A、B、…、Z的ASCII码是 65、66、…、90。要对应 1、2、…、26,只要减去 64就可以,

相当于减去A的ASCII码后再加 1,如 B的序号就是:’B’-‘A’+1。(2)从 AA到 ZZZ变化过程是:有一位从 Z变到 A后,它前一位的字母就转为升序

的字母,如 BZ的下一个是 CA,把字母看成数,这就是 26进制的数,我们只要将各位上的字母对应的数字乘以以 26为底的权就可以。如 AB的数字序号为:A的序号*26+B的序号,即: (‘A’-‘A’+1)*26+(‘B’-‘A’+1)。而 ZZZ 的数字序号为:(’Z’-‘A’+1)*26*26+

(’Z’-‘A’+1)*26+(’Z’-‘A’+)【程序清单 3.10】1. #include<stdio.h>

2. int main()

3. {

4. char w1,w2,w3;

5. int k,ans;

6. while(scanf("%d",&k)!=EOF)//读入每行的第 1 个数据7. {

8. switch(k) // 第 1 个数据的可能是 1、2、3

9. {

10. case 1:

11. {

12. getchar(); // 读取 k后的空格13. w1 = getchar(); // 将读取的字母放入w1中14. ans = w1-'A'+1; // 计算w1对应的序号15. // getchar(); //回车号可以由下一个 scanf()处理16. printf("%c:%d\n",w1,ans);//输出结果17. }

18. break;

19. case 2:

20. {

21. getchar();

22. w1 = getchar(); // 将读取的第 1 个字母放入w1中23. w2 = getchar(); // 将读取的第 2 个字母放入w2中24. //getchar() ;//回车号可以由下一个 scanf()处理

63

Page 72: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

25. ans = (w1-'A'+1)*26+(w2-'A'+1); // 计算序号26. printf("%c%c:%d\n",w1,w2,ans);

27. }

28. break;

29. case 3:

30. {

31. getchar();

32. w1 = getchar(); // 将读取的第 1 个字母放入w1中33. w2 = getchar(); // 将读取的第 2 个字母放入w2中34. w3 = getchar(); // 将读取的第 3 个字母放入w3中35. //getchar();//回车号可以由下一个 scanf()处理36. ans = (w1-'A'+1)*26*26+(w2-'A'+1)*26+(w3-'A'+1);//计算序号37. printf("%c%c%c:%d\n",w1,w2,w3,ans);

38. }

39. break;

40. }

41. }

42. return 0;

43. }

注意:用 getchar()语句读取一个字符时,是紧接着前面读过的部分往后读,并且把空格、回车等都当着字符,因此,要把多余的空格、回车读过。但第 15、24、35行的 getchar()可以省略,因为回车符可以由下 1 个 scanf()处理。

64

Page 73: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题1. 有三个数 a、b、c。请你编程将他们从小到大输出。(smu1068)

2.考试后,大家都有个成绩,请你编程判断每 5 个人中,最高分比最低分多多少。输入:125 225 250 50 80

36 69 98 78 55

输出:200

62

3.很多人喜欢 6,认为 6是顺利的意思,就是 6的倍数也喜欢。由键盘输入一串数,请你编程找出这样的数。(smu1022)

输入:1 5 7 6 3 12 72 99 22 18

输出:6 12 72 18

4.对任意输入的数,请你编程输出它在机内的 16位的原码。例如 7的原码是:0000000000000111,-7的原码是 1000000000000111。最左的一位是符号位,0为正,1为负。(smu1362)

5.输入三个非负数 a、b、c,如果能构成三角形就求出它的面积。如果不能构成三角形就输出“No”。请你编程实现。(smu1011)

6.在平面直角坐标系中有一矩形,左下角坐标是(a,b),右上角坐标是(c,d);矩形的边平行于坐标轴,现在有一系列点(xi,yi),i=0,...,n,请你判断它们是否在矩形内或上。(smu1135)

7.平面上的三个点A(0,0),B(1,0),C(0,2)。按A->B->C是逆时针,按 C-B-A是顺时针。给你平面三点的顺序,请你判断是逆时针还是顺时针。(smu1161)

8.输入线段 AB、CD的两端点,判断两线段是否相交。(smu1203)9.在平面上给你两条线段端点坐标,请你编程判断它们是否垂直。(smu1284)10. 给你两圆的圆心和半径,请你编程判断两圆的位置关系。两圆的位置关系有相离、

相切、相交、内切、内含。当两圆有公共部分时,求公共部分的面积。相切或相离时公共部分的面积为 0。(smu1270)

65

Page 74: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

11.2007年 12月的银行存款利息如下:(smu1036)1年期定期存款利息为 4.14%;

2年期定期存款利息为 4.68%;

3年期定期存款利息为 5.4%;

5年期定期存款利息为 5.85%;

告诉你存的钱的数目M,存的定期种类 S(S 只能为 1、2、3、5中的一种),及存的年限 N,求到期日能取回的本息是多少?

12.企业发放的奖金根据利润提成。利润 I低于 100000 元的奖金可提 10%;利润高于100000 元,低于 200000 元的(100000<I<=200000)时,低于 100000 元的部分按 10%提成,高于 100000 元的部分,可提成 7.5%;200000<I<=400000 时,低于 200000 部分按前面的方法,高于 200000 元的部分按 5%提成;400000<I<=600000 元时,高于 400000 元的部分按3%提成;600000<I<=1000000 时,高于 600000 元的部分按 1.5%提成;I>1000000 元的部分按 1%提成。从键盘输入当月利润 I,求应发奖金总数。(smu1088)

13.有一个城市出租汽车的计费规则是 3公里(含 3公里)基本费 6 元,超过 3公里,每一公里 1.4 元。现在请你输入具体的公里数 x(0<x<1000),并编程计算 x公里所需的费用,计算结果保留 2位有效数字。(smu1196)

14.彩虹,又称天虹,简称虹,是气象中的一种光学现象。当太阳光照射到空气中的水滴,光线被折射及反射,在天空上形成拱形的七彩光谱,雨后常见。形状弯曲,色彩艳丽。东亚、中国对于七色光的最普遍说法是(从外至内):红、橙、黄、绿、青、蓝、紫。现在我们用字母 R、O、Y、G、I、B、P分别表示这七种颜色:红、橙、黄、绿、青、蓝、紫的编码。(smu1471) 请编程实现:输入一个字母,输出它所对应的颜色。若输入的字母不是上面的这 7 个字母,则输出“ERROR”。

15.赤橙黄绿青蓝紫, 谁持彩练当空舞?这是毛泽东诗词里的一句,一个节目的主题就是要选出其中颜色的组合,为了少写字,把赤、橙、黄、绿、青、蓝、紫分别对应成1 、2、3、4、5、6、7。每次输入两个数字,请你编程输出相应的颜色。(smu1483)

如输入:12,输出:12=赤橙16.考试成绩的等级规则是:A等为 85分以上,B等为 70~84分,C等为 60~69分,

D等为 60分以下。请你编程实现这个转换。例如,输入A,输出 85~100。(smu1027)

66

Page 75: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

17.老师习惯把学生成绩按百分制转为等级制,请你帮忙完成这个工作。规则如下:95分以上为“A+”,90-94分为“A”,85-89分为“A-”,80-84分为“B+”,75-79分为“B”,70-74分为“B-”,60-69分为“C”,60分以下为“D”(smu1527)

如输入:83.5

输出:

B+

18.某校学生评比采用绩点制,规则是:90分以上(含 90分,下同)算 5点,80分以上算 4点,70分以上算 3点,60分以上算 2点,不及格算 0点,请根据某个学生的成绩及学分计算该生该门课程所获得的绩点。

输入一个学生某门课的成绩及学分数,输出该生该门课程所获得的绩点数(结果保留一位小数)

输入样例85 1.5

输出样例6.0

19.用户输入运算数和四则运算符,请你编程输出运算结果。当输入运算符不是"+"、"-"、"*"或"/"时提示出错,当输入除数为 0 时也提示出错。(smu1051)

输入样例:2+3

8*5

9-20

6/0

输出样例:5.0

40.0

-11.0

error

20.从键盘上输入若干个大写字母,依次输出它的小写字母。(smu1020)

21.为使电文保密,往往按一定规律将其转换成密码,收报人再按约定的规律将其译回原文。例如,可以按以下规律将电文变成密码:每个字母变成它后继的第 2 个字母,例如:将字母A变成 C,a变成 c,Y变成A,Z变成 B,“Hello!”变成“Jgnnq!”。请你编程将输入的信息转换成密码。(smu1055)

22.点名。有些老师很喜欢点名,他们有时候采取抽点的方式。给出班级的人数,以及老师要抽点的人数,那么总共有几种抽点的情况呢?(smu1195)

67

Page 76: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

如输入:

3 2

5 3

20 5

输出:

3

10

15504

23.奖学金(smu1529)某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:

(1) 院士奖学金,每人 8000 元,期末平均成绩高于 80分(>80),并且在本学期内发表 1篇或 1篇以上论文的学生均可获得;

(2) 五四奖学金,每人 4000 元,期末平均成绩高于 85分(>85),并且班级评议成绩高于 80分(>80)的学生均可获得;

(3) 成绩优秀奖,每人 2000 元,期末平均成绩高于 90分(>90)的学生均可获得; (4) 西部奖学金,每人 1000 元,期末平均成绩高于 85分(>85)的西部省份学生均可获得; (5) 班级贡献奖,每人 850 元,班级评议成绩高于 80分(>80)的学生干部均可获得;只要符合条件就可以得奖,每项奖学金的获奖人数没有限制,每名学生也可以同时获得多项奖学金。例如姚林的期末平均成绩是 87分,班级评议成绩 82分,同时他还是一位学生干部, 那么他可以同

时获得五四奖学金和班级贡献奖,奖金总数是 4850 元。 现在给出若干学生的相关数据,请计算哪些同学获得的奖金总数最高(假设总有同学能满足获得奖

学金的条件)。

输入 输入的第一行是一个整数N(1 <= N <= 100),表示学生的总数。 接下来的N行每行是一位学生的数据,从左向右依次是姓名,期末平均成绩, 班级评议成绩,是否是学生干部,是否是西部省份学生,以及发表的论文数。 姓名是由大小写英文字母组成的长度不超过 20的字符串(不含空格); 期末平均成绩和班级评议成绩都是 0到 100之间的整数(包括 0和 100); 是否是学生干部和是否是西部省份学生分别用一个字符表示,Y表示是,N表示不是; 发表的论文数是 0到 10的整数(包括 0和 10)。每两个相邻数据项之间用一个空格分隔。输出输出包括三行,第一行是获得最多奖金的学生的姓名,第二行是这名学生获得的奖金总数。如果有两

位或两位以上的学生获得的奖金最多,输出他们之中在输入文件中出现最早的学生的姓名。第三行是这N

个学生获得的奖学金的总数。输入样例4

YaoLin 87 82 Y N 0

ChenRuiyi 88 78 N Y 1

LiXin 92 88 N N 0

ZhangQin 83 87 Y N 1

输出样例ChenRuiyi

9000

68

Page 77: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

28700

24.判断某一年是否闰年。闰年的条件是:被 4整除,并且不被 100整除,或者被 400

整除。(smu1449)

69

Page 78: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 4章 循环问题设计--循环语句

导学请读者选择一个有关循环的问题分别用三种循环语句解决,这样就容易掌握循环结构

的编程。循环控制比较复杂,用流程图表达可以使用思路更为清晰。在调试时请用Debug 查看循环内变量的值,这样对程序条理的理解就显得十分清晰。

4.1 循环结构在程序设计中,常常要重复处理同样的问题,比如,要判断 n 个数是不是素数,求 n

个三角形的面积、求数列的前 n项和等等。要在程序中写不定的 n 次处理代码,用顺序结构无法完成。因此要用循环结构。C语言的循环控制语句有 for、while、do-while 三种。

4.1.1 for语句【例 4.1】 请编写程序输出 n行的“ Welcome”。分析:要输出多行相同内容的文本,如果已知行数 n,并且 n 比较小,可以用前面学过的顺

序结构直接重复多次调用 printf函数实现,当行数较大或者 n不确定的情况,该方法就不适用或无法使用。本题要重复 n 次,可以使用一个计数器变量 i来统计重复的次数。统计的流程为(如图

4.1 所示):(1) 计数器的初值为 0,;(2) 判断 i<n是否成立,如果成立就做:输出一行文本;计数器的个数增加 1,如果

不成立,该处理程序段结束。

70

Page 79: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(3) 重复步骤(2)。

图 4.1 例 4.1 流程图这个循环过程可以表达为:for(i=0;i<n;i++) {输出一行“Welcome”;

}for的()里面有 3 个部分,i=0是赋初值,i<n是判断循环是否继续的条件,i++表示

每循环一次,i的值加 1。见【程序清单 4.1】中的 7~11行。【程序清单 4.1】1. //用 for循环2. #include <stdio.h>

3. int main()

4. {

5. int n,i;

6. scanf("%d",&n);

7. for(i=0;i<n;i++) // 计数器变量 i 从 0开始,每循环 1 次增 1,当 i<n 时,继续循环

8. //当循环 n 次后,i=n,循环条件不成立,结束循环9. {

10. printf("Welcome\n");//输出要求的一行内容11. }

12. return 0;

13. }

运行的过程为:5↙Welcome

71

Page 80: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

WelcomeWelcomeWelcomeWelcomefor语句一般形式为:

for(表达式 1;表达式 2;表达式 3) {循环语句/语句组;

} 表达式 1通常用来给循环变量赋初值,一般是赋值表达式,如例 4.1的 i=1。也允许在

for语句外给循环变量赋初值,此时可以省略该表达式。表达式 2 通常是循环条件,一般为关系表达式或逻辑表达式,如例 4.1中第 8行的

i<=n。表达式 3 通常可用来修改循环变量的值,一般是赋值语句, 例 4.1的第 8行 i++。三个表达式由两个分号(不可缺少)隔开,这三个表达式都可以是逗号表达式, 即每

个表达式都可由多个表达式组成。三个表达式都是任选项,都可以省略。for语句的执行过程如下(如图 4.2 所示):(1)首先计算表达式 1的值。(2)再计算表达式 2的值,若值为真(非 0)则执行循环体一次, 否则跳出循环。

(3)然后计算表达式 3的值,转回第(2)步重复执行。

图 4.2 for循环图 在整个 for循环过程中,表达式 1 只计算一次,表达式 2和表达式 3 则可能计算多次。

72

Page 81: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

循环体可能多次执行,也可能一次都不执行。【例 4.2】 请编写程序实现:逆序输出不大于 n的连续自然数。分析:输出一趟 n~1的流程图如图 4.3 所示:

图 4.3 例 4.2 流程图【程序清单 4.2】1. //用 for循环2. #include <stdio.h>

3. int main()

4. {

5. int n,i;

6. while(scanf("%d",&n)!=EOF) // 输入 n

7. {

8. if(n<=0)

9. break;

10. else

11. {

12. for(i = n;i>0;i--) // i 从 n逆序循环到 1

13. {

14. printf("%d ",i);

15. }

16. printf("\n");

17. }

18. }

19. return 0;

20. }

运行过程为:4↙

73

Page 82: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

4 3 2 18↙8 7 6 5 4 3 2 1

4.1.2 while 语句while 语句重复执行一个语句或语句组,直到某个特定的条件表达式的值为假。它的语

法表示如下:while ( 表达式 ) {循环语句/语句组;

}式中的表达式 必须是数值表达式。while 语句执行过程如下(如图 4.4 所示):

(1) 表达式 被计算。(2) 如果表达式的值为假,while 下面的语句被忽略,程序直接转到 while 后面的语

句执行。

(3) 如果表达式的值为真(非零),语句/语句组被执行。

图 4.4 while循环图用while语句重写【例 4.2】的代码。【程序清单 4.3】1. //用while循环2. #include<stdio.h>

3. int main()

4. {

5. int n;

6. while(scanf("%d",&n)!=EOF) // 对多组输入数据循环

74

Page 83: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

7. {

8. while(n>0) // 循环条件9. {

10. printf("%d ",i);

11. n = n-1; // 控制循环次数12. }

13. printf("\n");

14. }

15. return 0;

16. }

4.1.3 do while 语句do-while 语句重复执行一个语句或语句组,直到某个特定的条件表达式的值为假。下面

是它的语法表示:

do 语句/语句组 while ( 表达式 ) ;

do-while 语句中,表达式是在语句/语句组 被执行之后计算的。所以 do 后面的语句/语句组至少被执行一次。 其中表达式 必须是一个数值表达式。do-while 语句的执行过程如下(如图 4.5 所示):

(1) 执行 do 后面的语句/语句组;(2) 计算表达式。如果其值为假,则 do-while 语句结束,程序继续执行它后面的语句。

如果表达式 的值为真(非零),跳转回(1)重复执行 do-while 语句。

图 4.5 do{}while()循环图用 do while语句重写【例 4.2】的代码。【程序清单 4.4】

75

Page 84: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include<stdio.h>

2. int main()

3. {

4. int n;

5. while(scanf("%d",&n)!=EOF)

6. {

7. if(n<=0)

8. break;

9. else

10. {

11. do//先执行12. {

13. printf("%d ",n);

14. n--;

15. }while(n>0);//再判断16. printf("\n");

17. }

18. }

19. return 0;

20. }

4.1.4 三种循环语句的比较for循环与while的区别在于:for循环在结构中突出循环变量的初值、终止条件、循环变

量的步长。而 while循环中只突出循环终止条件。把 for循环改为while或 do-while循环,只需把表达式 1 放在循环体之前,表达式 2作为循环判定条件,表达式 3 放在循环体的最后一句即可。while循环与 do-while循环的区别在于:while循环如果循环条件不满足,则不执行循环体,循环次数有可能为 0;do-while循环至少会执行一次循环体,因为它一开始是先执行一次循环体后才开始判断循环条件看是否继续循环。

【例 4.3】求数列 1+3+5+…+n的和。(smu1002)

分析:这个数列的求和,可以看成是每次加入一个通项,加 n 个通项的循环过程,通项 i的规

律是每次在原数上加 2,如图 4.6 所示。

76

Page 85: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 4.6 例 4.8 流程图

【程序清单 4.5】1. //用 for循环2. #include <stdio.h>

3. int main()

4. {

5. int i,sum=0,n=101;

6. for(i = 1;i<=n;i+=2)

7. sum += i;

8. printf("%d\n",sum);

9. return 0;

10. }

【程序清单 4.6】1. //用while循环2. #include <stdio.h>

3. int main()

4. {

5. int i,sum=0,n=101;

6. i=1;

7. while(i<=n)

8. {

9. sum += i;

10. i += 2;

11. }

12. printf("%d\n",sum);

13. return 0;

14. }

【程序清单 4.7】1. //用 do-while循环2. #include <stdio.h>

3. int main()

4. {

5. int i,sum=0,n=101;

6. i=1;

7. do

8. {

9. sum += i;

10. i += 2;

11. } while(i<=n);

12. printf("%d\n",sum);

13. return 0;

14. }

提示:(1)一般来说,当确定循环次数的时候用 for语句控制循环比较直观,而当循环次数

不确定,循环条件确定的时候用while语句控制循环较方便。(2)for语句及while语句结尾不要乱加“;”号,否则循环体会变空语句。(3)do-while语句最后要加“;”号,否则编译出错。(4)for语句的表达式 3的变化应使得表达式 2往逻辑假(即循环不成立)的方向变

化,否则会造成死循环。(5)for循环变量的类型也可以是字符类型(char)。

77

Page 86: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

思考:请用三种循环分别输出 26 个大写字母(smu1068)。在 C语言中,还可以使用 goto语句构成循环。该语句的格式是:goto 标号;意思是强

行跳转到标号所指的语句开始执行。但 goto语句的使用容易使程序的逻辑顺序混乱,因此不赞成使用。本书对 goto语句不再展开讨论,请有兴趣的读者自学。

4.1.5 break 语句在执行循环的过程中,有时需要终止循环,让程序跳到循环体外去,这时可以使用

break语句。break语句的一般形式为:

break;

break 只能用在 switch 语句或循环语句中, 其作用是跳出 switch语句或跳出本层循环,转去执行后面的程序。读下列程序,指出程序运行的结果。【程序清单 4.8】

1. #include <stdio.h>

2. int main()

3. {

4. int i,j;

5. for ( i = 0; i < 10; i++ ){ /*内循环中的 break语句执行后返回到这里 */

6. for ( j = 1; j <= 5; j++) {

7. if ( (i+j)% 5 ==0 ) {

8. printf("i= %d j=%d\n", i, j);

9. break; // 中断循环变量是 j的循环10. }

11. } //for j

12. } //for i

13. return 0;

14. }

这段程序中,i 从 0循环到 9,每次 j 从 1循环到 5,第 8到 11行的作用是:当 i+j是 5

的整数倍时,则输出 i和 j的值,并跳出 j循环,开始下一轮的 i循环。此代码的作用就是找出所两个数和为 5的倍数的各种情况。

运行结果为:i= 0 j=5

78

Page 87: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

i= 1 j=4

i= 2 j=3

i= 3 j=2

i= 4 j=1

i= 5 j=5

i= 6 j=4

i= 7 j=3

i= 8 j=2

i= 9 j=1

4.1.6 continue 语句在执行循环的过程中,有时需要跳过某次循环,这时可以使用 continue语句。continue 语句的一般形式为:continue;

continue用在 do、for、或 while 语句中,使得其后的语句被忽略,直接执行下一次循环。do、for、或 while 语句的下一轮循环用如下方法确定:

(1)对于 do 或 while 语句, 下一轮循环从计算条件表达式的值开始。(2)对于 for 语句,下一轮循环从计算第一个循环控制条件表达式的值开始。

读下列程序,并指出最终 x、y的值。【例 4.4】统计正数的个数Input 有多组测试数据,每组一行,每行的第 1 个数是整数表示后面数字的个数。如果是 0或

负数,表示此行不统计。 Output 输出正数的个数。 Sample Input 2 3 -65 2 0 -5 7 80 -11 -9 Sample Output 130分析:本题要循环处理每行的数据,但当第 1 个数是 0或负数时,就要不处理,我们可以使

79

Page 88: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

用 continue语句跳过,如【程序清单 4.9】中的第 8行,continue 将 n<0的情况跳过。【程序清单 4.9】

1. #include <stdio.h>

2. #include <math.h>

3. int main()

4. {

5. int i,num,n,x;

6. while(scanf("%d",&n)!=EOF)

7. {

8. if(n<=0) continue; // 如果 n<0,跳到下一次循环执行9. num = 0;

10. while(n--)

11. {

12. scanf("%d",&x);

13. if(x>0) num++;

14. }

15. printf("%d\n",num);

16. }

17. return 0;

18. }

4.2 循环的嵌套当一个循环体中又包含循环结构时,称之为嵌套循环。处于外部的循环称为外循环,

处于内部的循环称为内循环,整个内循环部分仅仅是作为外循环的循环体中的一条语句而已。C语言三种循环的循环体都可以包含任何一种完整的循环结构。

【例 4.5】在屏幕上输出m行 n列由”*”号组成的矩形。例如,当m=4,n=5,图形如下所示。********************分析:本问题可以看成是输出一行“*”号 m 次,相当于循环m 次,即: for(i=1;i<=m;i++){输出一行“*”号;

}。80

Page 89: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

一行“*”号又有 n 个“*”号组成,可以看成把 1 个“*”循环 n 次,写成:for(j=1;j<=n;j++) printf(“*”);合起来就是循环嵌套,如【程序清单 4.10】的第 7~12行所示。【程序清单 4.10】1. #include <stdio.h>

2. int main()

3. {

4. int i,j,m,n;

5. while(scanf(“%d%d”,&m,&n)!=EOF)

6. {

7. for(i=1;i<=m;i++) // 控制输出行数8. {

9. for(j=1;j<=n;j++)

10. printf(“*”); // 每行输出对应的*号数11. printf(“\n”); // 输出换行12. }13. }

14. return 0;

15. }

4.3案例及分析【例 4.6】用“*”号输出直角三角形。(smu1044)

***************分析:本题输出的图形与前面矩形的区别在于每行星号个数不同,但认真观察该图形

中星号的规律可以发现,如果对每行从 1开始编号,则每行星号的个数跟行号一致,即内层循环的终止个数为 i,见【程序清单 4.11】的第 12行。

【程序清单 4.11】1. //双重循环2. #include <stdio.h>

3. int main()

4. {

81

Page 90: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5. int i,j,n;

6. char c=’*’; // 字符变量 c保存要输出的符号7. // 如要输出其他符号的同样图形,只需修改本句即可8. while(scanf(“%d”,&n)!=EOF)

9. {

10. for(i=1;i<=n;i++) // 控制输出行数11. {

12. for(j=1;j<=i;j++) // 控制输出每行“*”的个数13. putchar(c); // 每次输出一个“*”14. printf(“\n”); // 每输出一行后换行15. }

16. }

17. return 0;

18. }

运行结果如图 4.7 所示:

图 4.7 程序清单 4.11的运行结果图【例 4.7】求两个正整数 a,b的最大公约数,一般把 a,b的最大公约数记为:gcd(a,b)。

(smu1013)

分析:a,b的最大公约数 r就是能被 a和 b整除的最大正整数。我们可以穷举小于 a、b的所有

的数,找出其中能同时被 a和 b整除的最大数。为了提高效率,可以从 a、b 两个数中的较小数开始判定。不妨设 a 较小,让 i=a,开始判断 i|a与 i|b是否同时成立;不成立时将 i减一后再次判断,直到满足,这时的 i就是 a,b的最大公约数。因为 a、b互质时最大公约数是 1,所以可以设置循环条件为 i 大于 1。程序流程图如图 4.8 所示:

82

an, 14年7月16日,
此图的位置最好在结果下
Page 91: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 4.8 例 4.7 流程图【程序清单 4.12】1. #include <stdio.h>

2. int main()

3. {

4. int i,a,b,t;

5. while(scanf(“%d%d”,&a,&b)!=EOF)

6. {

7. if(a>b)

8. {

9. t = a; a = b; b = t;

10. } //保证 a为两个数中较小的数11. for(i=a;i>1;i--) // 从 a开始倒着判定12. {

13. if(a%i==0&&b%i==0)

14. break; // 找到满足条件的 i退出循环,如果一直不成立,

15. // 当 i等于 1 时也会结束循环,所以循环结束时 i为最大公约数16. }

17. printf(“%d\n”,i);

18. }

19. return 0;

20. }

83

Page 92: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

运行结果为:24 18 ↙632 24↙8说明:这种方法求最大公约数很耗时,一般采用辗转相除法。对于两个正整数 a、b,有 q 和 r使得:a=q*b+r,这里 q是商,r是余数,由整除性可知,

a、b的最大公约数与 b、r的最大公约数一样,而 b、r 比 a、b小了很多。我们把 b、r当成 a、b,再继续这个过程,当 r变化到 0 时,对应的 b就是最大公约数。例如,求 gcd(30,18),其过程见表 4.1。

表 4.1 计算 gcd(30,18)a b r

第 1 次 30 18 12

第 2 次 18 12 6

第 3 次 12 6 0

即 gcd(30,18)=gcd(18,12)=gcd(12,6)=gcd(6,0)=6。辗转相除法的流程如图 4.9 所示。

图 4.9 求 gcd(a,b)的流程图 请读者用辗转相除法重写这个问题的代码.

【例 4.8】判断一个数是否为素数。(smu1012)

分析:根据素数的定义,即除了 1和本身之外没有其它因子,所以判断一个数 a是否为素数,可以从 2到 a-1依次看能否整除 a,如果都不可以,a即为素数,否则,a为合数。

【程序清单 4.13】84

Page 93: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include <stdio.h>

2. int main()

3. {

4. int i,a;

5. while(scanf(“%d”,&a)!=EOF)

6. {

7. for(i=2;i<a;i++)

8. {

9. if(a%i==0)

10. break; //从 2开始到 a-1 判断能否整除 a,// 如果可以就强行退出循环

11. }

12. if(i==a)

13. printf(“%d是素数\n”,a); //结束循环时如果 i等于 a 说明 a是素数14. else

15. printf(“%d不是素数,是合数\n”,a);

16. }

17. return 0;

18. }

运行结果为:2

2是素数11

11是素数6

6不是素数,是合数13

13是素数15

15不是素数,是合数101

101是素数提示:其实判定 a是否为素数,只需从 2到 a的平方根进行判断是否整除 a即可,请试

着修改本例。【例 4.8】在屏幕上输出九九乘法表。(smu1307)

分析:九九乘法表有 9行,要进行 9 次循环。第一行有 1 个等式,第 2行有 2 个等式,…,第

i行有 i 个等式,即第 i行要进行 i 次循环。如果用 i 控制行循环(i:1~9),用 j 控制列循环(j:1~i),则第 i行、第 j列要输出的等式是:j*i=乘积的结果。

【程序清单 4.14】85

Page 94: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include <stdio.h>

2. int main()

3. {

4. int i,j;

5. for(i=1;i<=9;i++) // 控制输出行数6. {

7. for(j=1;j<=i;j++)

8. printf(“%d*%d=%d “,j,i,i*j); // 每行输出对应个数的乘式9. printf(“\n”); //输出换行10. }

11. return 0;

12. }

运行结果如图 4.10 所示:

图 4.10 九九乘法表

4.4 进阶【任务 4.1】对于一个正整数请你求出它的位数。例如 123456是 6位数。(smu1024)

分析:我们把一个数除以 10后,整数位就少 1,如果只有一位,除以 10后,这个数的整数位

就变成 0,即,没有整数位。只要用一个计数器累计这样操作的次数就可以求得这个正整数的位数。

【程序清单 4.15】1. #include <stdio.h>

2. int main()

3. {

4. int n,count;// count为计数器5. while(scanf(“%d”,&n)!=EOF)

86

Page 95: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

6. {

7. count = 0; // 每次计算位数应重新初始化计数器 count为 0

8. while(n) // 条件表达式表示 n不为 0,可改为 n!=0

9. {

10. n /= 10; // 把 n整除 10,等同于去掉最后一位数据11. count++; // 计数器加 1

12. }

13. printf(“这是一个%d位数\n”,count); // 当 n为 0 结束循环,等于这个正整数的所14. // 有位都删除,count统计的就是删除的位数,即这个正整数的位数

15. }

16. return 0;

17. }

运行过程为:123456↙这是一个 6位数18749↙这是一个 5位数1230↙这是一个 5位数9↙这是一个 1位数18↙这是一个 2位数提示:本题的处理方法如果结合 n%10求余数,可以为有关整数拆分的题目做参考;如

果把 10 改为 R,此设计的方法可以用来把十进制整数转化为 R进制整数。【任务 4.2】输出如下图形 A BBB CCCCC分析:本题与前面例 4.5的区别在于每行符号不同,个数也不同,并且为等腰三角形。但认真

观察该图形可以发现图形中每行符号前的空格数是逐一递减的,而符号的个数是每行增加两个,因此每行用 2 个循环处理,第 1 个循环处理空格,第 2 个循环处理字母。如果对行从1开始编号,共有 i行,第 i行就有 n-i 个空格、有 2i-1 个字母。字母可以用‘A’+i-1表示。

【程序清单 4.16】1. #include <stdio.h>

2. int main()

3. {

87

Page 96: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

4. int i,j,n;

5. char c=’A’; // 字符变量 c保存要输出的符号

6. while(scanf(“%d”,&n)!=EOF)

7. {

8. for(i=1;i<=n;i++) // 控制输出行数9. {

10. for(j=1;j<=n-i;j++)

11. putchar(‘ ‘); // 每行输出对应个数的空格12. for(j=1;j<=2*i-1;j++)

13. putchar(c+i-1); // 每行输出对应个数的符号,符号内容由表达式 c+i-1

14. // 得到,根据行号 i来进行相应变化15. printf(“\n”); // 输出换行16. }

17. }

18. return 0;

19. }

运行结果如图 4.11 所示:

图 4.11 程序清单 4.17的运行结果图【任务 4.3】某校有 4位同学出外春游,其中有一人做了好事不留名。感谢信来后,辅导

员问他们谁做的。A 说:不是我。B 说:是 C。C 说:是D。D 说:C胡说。已知 3 个人说的是真话,一个人说的是假话。现在要根据这些信息,找出做了好事的人。

(smu1144)

分析:答案只能在A、B、C、D四个人中,我们用 1 个 char类型的变量 k来表示答案,枚举这 4

种情况。88

Page 97: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

“A 说:不是我”为真时相当于“k!='A'”;“B 说:是 C。”为真时相当于“k=='C'”;“C 说:是D。”为真时相当于“k=='D'”;“D 说:C胡说。”为真时相当于“k!='D'”。为真时,逻辑表达式的值为 1。3 个人说真话,1 个人说假话,就是有 3 个逻辑表达式

值为 1,1 个为 0,即(k!='A')+(k=='C')+(k=='D')+(k!='D')的值为 3。【程序清单 4.17】1. #include <stdio.h>

2. int main()

3. {

4. int sum;

5. char k;

6. for(k='A';k<='D';k++)//枚举各种情况7. {

8. sum = (k!='A')+(k=='C')+(k=='D')+(k!='D'); // 3 个人说,1 个人说假话。9. if(sum==3)

10. printf("%c\n",k);

11. }

12. return 0;

13. }

运行结果为:C【任务 4.4】猜数。由计算机随机产生一个 100以内的整数 n,请编程实现猜的过程。分析:利用 C语言随机函数生成随机数,利用二分思想进行猜数,先猜 n/2,然后根据

提示进行相应范围的猜测,直到猜对结果。【程序清单 4.18】1. #include <stdio.h>

2. #include <stdlib.h>

3. #include <time.h>

4. int main()

5. {

6. int a,n;

7. char c;

8. srand(time(NULL)); // 随机数初始化种子,如果没有本句,程序每次执行的随机数系列会相同

9. do

10. {

11. n=rand()%101; // 生成 0到 100的随机数89

Page 98: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

12. printf("请猜数(0-100):\n");

13. scanf("%d",&a);

14. while(a!=n)

15. {

16. if(a<n)

17. printf("猜错了,请输入大于%d的数\n",a);

18. else

19. printf("猜错了,请输入小于%d的数\n",a);

20. scanf("%d",&a);

21. }

22. printf("恭喜你答对了!是否再来一局[Y/N]\n");

23. getchar();

24. c=getchar();

25. }

26. while(c=='Y');

27. return 0;

28. }

运行过程为:请猜数(0-100):

50↙猜错了,请输入小于 50的数25↙猜错了,请输入大于 25的数28↙猜错了,请输入小于 28的数26↙恭喜你答对了!是否再来一局[Y/N]

N

【任务 4.5】有多少位是 1(smu1378)

Description

把一个正数转成二进制数后,各位数字分别是 0或 1,请你编程统计有多少位是 1。例如 11的二进制数是 1011,共有三位是 1。

Input

输入有若干行,每行一个正整数。Ouput

输出对应二进制数的 1的个数。Sample Input

11

1

721

Sample Output

3

1

90

Page 99: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5

分析:一个整数占 4 个字节,1 个字节是 8位,整数在机内的表示是 32位,各位的权值由左到右分别是:20,21,22,…,231。只要把这个整数与各位的权值进行与的运算,其值就是这位的值。把值为 1的位统计出来,就得到本题的解。例如(11)10=(00000000000000000000000000001011)2与 20,21,22,…,231分别进

行与运算后得:1、1、0、1、0、…、0(省略部分为 0,共有 32位)。这些 1相加为 3,就是 11

的二进制数中 1的个数。【程序清单 4.19】1. #include <stdio.h>

2. int main(void)

3. {

4. int n;

5. while (EOF != scanf("%d",&n))

6. {

7. int i;

8. int c = 0,k=1;

9. for (i = 0; i < sizeof(int) * 8; i ++) //循环 32 次10. {

11. if(n & k) c++;

12. k = k<<1; //k<<1相当于 k*2,依次遍历各位的权值13. //if ((n >> i) & 1) c ++;

14. }

15. printf("%d\n",c);

16. }

17. return 0;

18. }

运行过程为:1↙15↙211↙3说明:(1)第 11、12行可以改成第 13行中注释的部分,n>>i相当于右移 i位,再与 1进行与

运算后就是第 i位的值。(2)本题还可以对正整数用除 2取余的方法得到二进制数的各位。

91

Page 100: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题1.求两个正整数 a,b的最小公倍数。(smu1014)

2.对于任意一个正整数,请求出各位数字的和。(smu1023)

3.陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 个苹果。陶陶的身高是110cm,家里有个 30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。现在给你每个苹果的高度,请编程统计陶陶能摘得到的苹果。比如苹果的高度为:100 200 150 140 129 134 167 198 200 111,程序将要得出 6。(smu1530)

4.津津一周的学习时间分别是 5、6、7、5、5、0、0小时,他妈妈望子成龙每天加了很多学习任务,所加的时间分别是 3、2、2、3、4、4、6小时。只要一天超过 8小时,津津就不高兴,请编程统计不高兴的天数。如本例中是 3。

5.有一个数列是 1/2+2/3+3/4+……,编程求前 n项的和。(smu1277)6.求 1~N(N 最大可以到 100000)之间的所有同构数。一个数出现在它的平方数的右端,

这个数称为同构数。(N 最大可以到 100000),如:5出现在 25的右侧 5是同构数25出现在 625的右侧 25也是同构数 (smu1101)

7. 大名鼎鼎的孙悟空爱吃桃。第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第 n天准备吃的时候只剩下一个桃子。请帮悟空算一下,他第一天开始吃的时候桃子一共有多少个呢?(smu1061)

如输入:2 4

输出:4 22

8.小明喜欢大大小小的平行四边形图案。下列就是用“*”组成的一个平行四边形图案:***** *****   *****    *****     ***** 请你编程实现。 要求输入 5 时就输出 5行的平行四边形图案,输入 n 时就输出 n行的平行四边形图案。

9.请编程输出如下的三角形:(smu1067)######

92

Page 101: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

  #####    ####      ###        ##          # 输入正整数 n,输出这样有 n行的三角形图案。10.计算多项式 7+72+73+...+7n的值,n由键盘输入。(smu1100)11.用牛顿迭代法求下面方程在 1.5 附近的根:(smu1108)

23-4x2+3x-6=0

12.一辆肇事汽车的号码是 4位十进制数。目击者向交警描述这个车号:这是一个完全平方数;这 4 个数从左至右一个比一个大。请帮助交警寻找肇事者,即找出肇事车号。 (smu1154)

13.两个乒乓球队各出 3 人进行比赛。甲队为A、B、C共 3 人,乙队为X、Y、Z共 3 人。已经抽签决定了比赛名单。有人向队员打听比赛的名单,A 说他不和 X 比,C 说他不和X 、Z 比,请编程序找出 3对赛手的名单。(smu1141)

14. 5位跳水高手将参加 10m高台跳水决赛,有好事者让 5 人根据实力预测比赛结果。(smu1146)     A 选手说:B第二,我第三。

B 选手说:我第二,E第四。

C 选手说:我第一,D第二。

D 选手说:C 最后,我第三。

E 选手说:我第四,A第一。 决赛成绩公布之后,每位选手都只说对了一半,即一对一错。请编程解出比赛的实际名次。

15. A、B、C是小学老师,各教 2门课,互不重复。共有 6门课:语文、算术、政治、地理、音乐和美术。已知:

(1)政治老师和算术老师是邻居。

(2)地理老师比语文老师年龄大。

(3)B 最年轻。

(4)A经常对地理老师和算术老师讲他看过的文学作品。

(5)B经常和音乐老师、语文老师一起游泳。

请编程输出A、B、C各教哪门课。 (smu1147)93

Page 102: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

16.校田径运动会上A、B、C、D、E分别获百米、四百米、跳高、跳远和三级跳冠军。 (smu1148)观众甲说:B获三级跳冠军,D获跳高冠军。

观众乙说:A获百米冠军,E获跳高冠军。

观众丙说:C获跳远冠军,D获四百米冠军。

观众丁说: B获跳高冠军,E获三级跳冠军。

实际情况是每人说对一半。请编程求出A、B、C、D、E各获哪项冠军。

17.我国有 4 大淡水湖。(smu1152)

A 说:洞庭湖最大,洪泽湖最小,鄱阳湖第三。

B 说:洪泽湖最大,洞庭湖最小,鄱阳湖第二,太湖第三。

C 说:洪泽湖最小,洞庭湖第三。

D 说:鄱阳湖最大,太湖最小,洪泽湖第二,洞庭湖第三。

4 个人每人只答对一个,请编程给出 4 个湖从大到小的顺序。

18.有代号是A、B、C、D、E的五位同学安排周一到周五做值日。A 说不做周一,B 说他要在A 做的第二天做。C 说要选周五,D 说要在 E的前一天做。请编程满足他们的要求。(smu1166)

19.已知某年某月的 1 号是星期几。请打印出这个月的月历。(smu1167)

20.用二分法求 f(x)=e^x-6=0的根。精确度 ε取 0.001。e取 2.718282。(smu1168)21. C语言单元测试总共 6题,班上有三位同学A、B、C。他们各自对自己做的题数都

做了预测。A 说:一定比 B多做,C 说:我有神助,全做没问题,B 说:这次的内容可能时间不够,做的要比 C少。测试后的结果是:最少的做出了 4题,每人做的题数不一样,而且都说对了。请编程判断他们的做题数。(smu1183)

22. a3 = b3 + c3 + d3为完美立方等式。例如 123 = 63 + 83 + 103 。编写一个程序,对任给的正整数 N (N≤100),寻找所有的四元组(a, b, c, d),使得 a3 = b3 + c3 + d3,其中 1<a, b,

c, d ≤N。(smu1175)23.打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立

方和等于该数本身。 ABC=A^3+B^3+C^3 。例如:153=1^3+5^3+3^3。(smu1058)

24.对任意一个 正数数 n 请你找出它除本身外的所有因数。如 12 的因数是:1 、2 、3、4、6。(smu1063)

94

Page 103: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

25. 一个数如果恰好等于它的因子之和 ,这个数就称为“完数”。例如,6的因子为1,2,3,而 6=1+2+3,因此 6是“完数”。编程找出 1000之内的所有完数,每个完数的输出格式为:6 its factor are 1,2,3 。(smu1059)

26.对于给定的正整数 n,请编程求 n!尾部有多少个 0。(smu1186)

27.用矩形法求定积分 (smu1192)。28.现有编号是 1、2、3、4、5的五人当选班长、副班长和学习委员职务,请输出所有的可

能。(smu1200)29.直线 y=2x把平面分成三个部分:直线上、直线上方、直线下方。已知 n 个点,请编

程统计并输出各部分有多少个点。(smu1202)30.打印由“*”组成的直角三角形。(smu1276)输入有若干行,每行一个整数 n,表示打印出一个 n行的图形。第 i行有 2i-1 个'*'号。如:

n=4 时,输出:

****************31.有 n 个长方体已量出长、宽、高为 a、b、c,请编程求出它们的体积。(smu1280)

32. 哥德巴赫猜想。要求输入一个大于 6的偶数,证明能由两个素数相加得到,并输出第一组满足条件的值 。(smu1526)例如输入 8,输出 3+5=8

33.假定某牧场中每只公牛每天吃 3捆草,每只母牛每天吃 2捆草,每只小牛每天吃半捆草。现牧场中有 100头牛,每天消耗 100捆草,问此 100头牛中公牛、母牛、小牛各几只,请编程列出公牛、母牛、小牛各几只所有可能的情况。(smu1333)

34.请按字典序输出由 1,2,3,4,5,6,7,8,9中组成的三位上升数的所有可能。上升 abc是指 a<b<c。(smu1339)

35.找一个三位数,使得各位数字不同,并且各位数字和是 10,并按从小到大输出,如 109、127、……、901、910。(smu1351)

36.编程计算:一块砖长 20厘米,宽 12厘米,厚 6厘米。要堆成正方体至少需要这样的砖头多少块?(smu1396)

95

Page 104: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

37.π是一个无理数,有时使用数值 3.14近似表示。通常使用下面的公式求 π2的近似值:(smu1482)

                           

请编程求 π2的近似值。38. 素数无处不在,比如表示日期的数字 19880101就是一个素数,请你编程找出

1988年 1月 1日(即 19880101)到 1989年 12月 31日(即 19891231)的日期数中所有的素数。39.把一个各位数字都不相同的 4位数重新组合,组合后的最大数减去最小数就得到

一个新数,再把这个新数进行同样的操作,这个操作若干次后就会重复。这个重复的数就是黑洞数,请编程找一个 4位的黑洞数。

96

Page 105: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 5章 过程封装与递归思想--函数

导学本章主要学习使用函数—结构化的方法编程。学好函数,重在掌握函数传参的技术;

理解变量的作用域;正确使用全局变量和局部变量;正确设置函数的返回值类型;正确调用函数。再进一步学一下递归函数,它是以后学习数据结构的基础。

5.1 自定义函数C语言是通过函数调用来组织程序的,main()函数是系统起始调用的函数。在 C语言中,

还有两种不同的函数:库函数和用户自定函数。库函数由 C系统提供,使用方式可参见 2.5

库函数;而用户自定义函数则需要用户根据程序要求进行定义后,方可在程序中使用。

5.1.1 自定义函数的结构自定义函数的一般形式如下:返回值类型 函数名 ([参数 1类型 参数名 1, 参数 2类型 参数名 2,……]){语句 1; // 语句可能与参数有关语句 2; // 语句可能与参数有关……return 返回值; // 如果返回值类型为 void,则不用返回语句

}其中,返回值类型表示该函数如果被调用,它执行完之后向调用它的程序返回何种数

据类型的值。函数名是程序员自己定义的、能够表明函数用途的标识符号,命名规则与变量的命名规则相同。参数是可选的,有些函数没有参数,有些可以有一至多个参数。每个参数都应说明其类型,以便调用它的程序可以填入正确的参数值。小括号和大括号是必须的。语句中可以把参数当作变量来使用。例如,求两数的最大值函数可能写成:

97

Page 106: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

int max(int a,int b)//用户自定义的函数{

return a>b?a:b;}

5.1.2 自定义函数的返回值函数的返回值是通过函数体中的 return语句获得的。如果函数不需要返回值,则函数要声明成 void类型,例如:void show()

{

printf("The answer is:\n");

}

函数体内只有一个输出语句,无需有返回值。return语句可以出现在函数体内任意位置,一旦执行,就意味着该函数执行结束,返

回到调用点,而 return语句后面的所有语句都不会被执行。如果把求两数最大值的函数写成:

int max(int a, int b)

{

if(a>=b)

return a;

else

return b;

printf(“该语句不会被执行”);//用来验证 return

}

这时由于 if(a>=b)的判断,return a与 return b 只有一句被执行,而 printf(“该语句不会被执行”)这句不会被执行,因此我们不必写多余的语句,这个函数应该写成:

int max(int a, int b)

{

if(a>=b) return a;

else return b;

}

98

Page 107: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5.1.3 自定义函数的调用与传参函数调用的方法是通过“函数名()”来实现,“()”内按定义的顺序列出要传递的实

参的值,这个过程叫做函数的传参。【例 5.1】 求两数的最大值。(smu1004)

【程序清单 5.1】1. #include<stdio.h>

2. int max(int a,int b) //用户自定义的函数3. {

4. return a>b?a:b;

5. }

6. int main()

7. {

8. int a=10,b=20;

9. printf("%d,%d的最大值=%d\n",a,b,max(a,b)); // max(a,b)调用函数10. return 0;

11. }

运行结果为:10,20的最大值=20

从【程序清单 5.1】看出:(1)函数值的类型,也就函数名前面声明的类型应与 return语句后表达式的类型一致。(2)函数的调用与库函数的调用一致,就是按形式参数表中的参数个数和类型将实际

值放入。(3)在【程序清单 5.1】中,max(a,b)就是将 a与 b的值(10和 20)传给max(int a,int b)

中的 a和 b。在max(int a,int b)中 a、b是形式参数,而在max(a,b)中 a、b是实参。传参的过程如图 5.1 所示。

图 5.1 函数的传参实参与形参可以用不同的变量名。看下列改写的【程序清单 5.2】【程序清单 5.2】

99

Page 108: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include<stdio.h>

2. int max(int a,int b) //形参为 a、b

3. {

4. return a>b?a:b;

5. }

6. int main()

7. {

8. int m=10,n=20;

9.

10. printf("%d,%d的最大值=%d\n",m,n,max(m,n)); // 实参是m、n

11. printf("-5,-8的最大值=%d\n",max(-5,-8)); // max(-5,-8)的实参是-5、-8

12. return 0;

13. }

运行结果为:10,20的最大值=20

-5,-8的最大值=-5

传参只是对变量的值进行拷贝,不改变原来的值。如:【程序清单 5.3】1. #include <stdio.h>

2. void change(int a,int b)

3. {

4. a = a+10; b = b*2;

5. printf("在函数体内 ");

6. printf("a=%d,b=%d\n",a,b);

7. }

8. int main()

9. {

10. int a=5,b=6;

11. change(a,b); //复制 a、b的值12. printf("在函数体外,main函数中 ");

13. printf("a=%d,b=%d\n",a,b); //保持原来的值14. return 0;

15. }

运行结果为:在函数体内 a=15,b=12

在函数体外,main函数中 a=5,b=6

100

Page 109: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5.1.4 函数的定义与声明的区别和使用函数的定义是指一个函数功能的确立,包括指定函数返回值的类型、函数名、形参及其

类型和函数体等。它是一个完整的独立的函数单位。函数的声明只是对已经定义好的函数的说明,它包括函数返回值的类型、函数名和形

式及其类型,但不包括函数体。函数声明的作用是告诉系统,在本函数中将要用到的函数是什么,以便在主调函数中作相应的处理。函数声明中也可以不必指出形参中的变量名,但是必须要指出每个形式参数的数据类型。

如果子函数定义在主调函数之后并且子函数返回值不为整型,必须在主调函数对此子函数进行声明,否则可不声明当函数的返回值类型是 int 时,在调用函数的前、后、内定义是一样的,其它类型的函

数当在调用函数后定义时,先要在调用函数内声明,如:【程序清单 5.4】1. #include<stdio.h>

2. int main()

3. {

4. double m=10.6,n=-20.8;

5. double max(double a,double b); // 此声明不可少,否则出错6. printf("%lf,%lf的最大值=%lf\n",m,n,max(m,n)); // max(m,n)调用函数7. printf("-5,-8的最大值=%lf\n",max(-5,-8)); // max(-5,-8)的实参是-5、-8

8. return 0;

9. }

10. double max(double a,double b) // 用户自定义的函数11. {

12. return a>b?a:b;

13. }

运行结果为:10.600000,-20.800000的最大值=10.600000

-5,-8的最大值=-5.000000

5.2 全局变量与局部变量变量可以在函数的内部定义,也可以在函数的外部定义,还可以在函数的复合语句内

101

Page 110: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

定义。在函数内部定义的变量,只能在这个函数内部使用;在函数的复合语句内定义的变量,

只能在这个复合语句内部有效。这样的变量是局部变量。在函数外部定义的变量,是外部变量,也称全局变量。例如在main()之前定义的变

量就是外部变量,它可以在各函数之间调用,其目的是增加函数间的联系渠道。一种简单的作用域判断方法是,变量在其声明的{}内有效。如果一个变量有多个声明,

则取包含该变量的{}中的最近的一个{}中的声明。请观察【程序清单 5.5】中 a、b、c的值及作用域。【程序清单 5.5】1. #include <stdio.h>

2. int c=100; // 全局变量,在其它地方不可再重新声明3. void change(int a,int b)

4. {

5. a = a+10; b = b*2;

6. printf("在函数体内 ");

7. printf("a=%d,b=%d\n",a,b); // a = a+10; b = b*2;

8. }

9. int main()

10. {

11. int a=5,b=6,i;

12. change(a,b);

13. printf("在函数体外,main函数中 ");

14. printf("a=%d,b=%d\n",a,b); // int a=5,b=6

15. if( 1+2>2)

16. {

17. int a=8,b=10;

18. printf("在 if语句内 ");

19. printf("a=%d,b=%d\n",a,b); //取最近的声明20. } // int a=8,b=10;

21. printf("a=%d,b=%d\n",a,b); // 现在 a,b指谁?22. return 0;

23. } // int a=5,b=6,i;

运行结果为:在函数体内 a=15,b=12在函数体外,main函数中 a=5,b=6在 if语句内 a=8,b=10a=5,b=6

【例 5.2】输入正方体的长宽高 l,w,h。求体积及三个面 x*y,x*z,y*z的面积。102

Page 111: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

【程序清单 5.6】1. #include <stdio.h>

2. int s1,s2,s3;//全局变量3. int vs( int a,int b,int c)

4. {

5. int v;

6. v = a*b*c;

7. s1 = a*b; // s1是全局变量,直接使用8. s2 = b*c;

9. s3 = a*c;

10. return v;

11. }

12. int main()

13. {

14. int v,l,w,h; // main()中的局部变量15. printf("input length,width and height\n");

16. scanf("%d%d%d",&l,&w,&h);

17. v = vs(l,w,h);

18. printf("\nv=%d,s1=%d,s2=%d,s3=%d\n",v,s1,s2,s3);

19. return 0;

20. }

运行过程为:input length,width and height

2 3 4↙v=24,s1=6,s2=12,s3=8

程序说明:(1)在函数 vs( int a,int b,int c){}中,s1、s2、s3是全局变量,可以在程序的其它函数中

直接使用,赋值前保留原来的值,赋值后的值可以被后继的代码使用,在第 18行中被输出。(2)在 VS()中 v是局部变量,其值通过 return语句作为函数值返回。在 main(){}函

数中的 v是 main()函数的局部变量与 vs()中的 v不同,第 17行通过赋值语句调用函数vs(),v为 vs()的值。(3)在第 14行定义的变量 l、w、h是main()中的局部变量,不可以直接被 vs()函数使

用,必须通过传参把值传给函数 vs()内的变量 a、b、c。

5.3 存储类型C的每个变量和函数都有两种属性:类型和存储类型。存储类型分为 4种:自动

103

Page 112: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(auto)、外部(extern)、寄存器(register)和静态(static)。这 4种存储类型的声明及作用见表 5.1。

表 5.1 变量与函数的存储类型存储类型 声明方式 作用auto 代码块内,auto int a,b; 声明的变量只能在作用域内发挥作用,默认情

况下为 auto,一般不写。extern 函数的外部,extern int a,b; 外部变量对于它之后所有的函数都是有效的,

在退出代码块或函数之后,外部变量仍然存在。

register 但 一 般 用 在 局 部 模 块内,register int a,b;

为了提高速度,直接把变量存储在高速的寄存器中。

static 代码块外,static int a,b; 允许所声明的变量在重新进入代码块时能够保持原来的值。

注意:(1)外部变量不能使用 auto或 register 存储类型;(2)register 存储类型只能用于少量的常用的变量,因为编译器只能使用数量有限的

寄存器;(3)static与 extern可以一起使用。我们将【程序清单 5.6】的变量用存储类型声明一下,成为【程序清单 5.7】。【程序清单 5.7】1. #include <stdio.h>

2. static int s1,s2,s3;

3. int vs( int a,int b,int c)

4. {

5. extern int s1,s2,s3; //在外部已经声明6. register int v; //寄存器变量7. v = a*b*c;

8. s1 = a*b; //s1是静态变量9. s2 = b*c;

10. s3 = a*c;

11. return v;

12. }

13. int main()

14. {

15. auto int v,l,w,h; //main()中的局部变量16. printf("input length,width and height\n");

17. scanf("%d%d%d",&l,&w,&h);

18. v = vs(l,w,h);

104

Page 113: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

19. printf("\nv=%d,s1=%d,s2=%d,s3=%d\n",v,s1,s2,s3);

20. return 0;

21. }

目前,我们只要了解存储类型就可以,重要的是弄清变量的作用域。

5.4 函数的嵌套调用 一个函数可以调用另一个函数,只要被调用的函数在之前定义,或在更大的范围中定

义就可以。【例 5.3】计算 1+(1+2)+(1+2+3)+……+(1+2+……+n)的值 。分析:这是一个计算数列的和,数列的第 n项为:1+2+……+n。定义一个函数 int item(int n)

求第 n项,即计算 1+2+……+n;定义一个函数 int sum(int n) 求前 n项的和;在 sum()函数中调用 item()函数。在主函数中输入项数 n的值,再调用 sum()函数即可。函数间的嵌套调用如图 5.2 所示。

图 5.2 函数的嵌套调用【程序清单 5.8】1. #include <stdio.h>

2. int item(int n) //求第 n项的函数3. {

4. return (1+n)*n/2;

5. }

6. int sum(int n) //求和函数7. {

8. int i,s=0;

9. for(i=1;i<=n;i++)

10. {

11. s = s+item(i); //调用通项105

Page 114: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

12. }

13. return s;

14. }

15. int main()

16. {

17. int n;

18. printf("请输入项数 n\n");

19. scanf("%d",&n);

20. printf("%d项的和是:%d\n",n,sum(n));

21. return 0;

22. }

求 6项和的输入过程及结果:请输入项数 n

6↙6项的和是:56

5.5 函数的递归调用【例 5.4】求 n!(smu1007)

分析:

在求 n!的函数 f(n)=n!中,可以看成 ,也就是 f(n)调用了 f(n-1)。类似这样直接或间接地调用该函数本身,就是函数的递归调用。求 f(3)的过程如图 5.3 所示。第 1 次存 3及 f(2)的入口地址到栈中;第 2 次存 2及 f(1)的

入口地址到栈中;找到 f(1)=1 时,再把栈中的数逐一取出计算,依次算得 f(2)=2* f(1)=2;f(3)=3* f(2)=6。

106

Page 115: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 5.3 f(3)的递归调用【程序清单 5.9】1. #include<stdio.h>

2. int factorial(int n) //用户自定义的递归函数3. {

4. if(n <= 0)

5. return(-1); // 递归出口6. if(n == 1)

7. return 1; // 递归出口8. else

9. return n*factorial(n - 1); //递归调用10. }

11. int main()

12. {

13. int num=10,fa;

14. fa = factorial(num);

15. printf("%d!=%d\n",num,fa); //调用函数16. return 0;

17. }

运行结果为:

10!=3628800

注意:n太大时会溢出,请大家尝试。递归的思想是将待求解问题分解成相类似的更小规模的子问题,通过递归关系不断找

到更小问题的解,直到在某一规模上,问题的解已知。本例题的解看作输入变量 n的函数 f (n),通过寻找递归关系:

f(n) = n* f (n-1) (5.1)

将求 f (n)的问题转变成求 f (n-1)的问题,不断递归调用公式(5.1),递归的终止是 f

(1)=1。这样一个思想也可以推广到多个输入变量 x,y,z等,只要递归朝着出口的方向递

107

Page 116: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

归就可以了。递归函数的设计方法是先写递归的出口,如程序中的第 4~7行,不是出口时就按更小

规模的递归函数进行计算,如程序中的第 8~9行。思考:请用递归法求两数的最大公约数。

5.6 案例及分析【例 5.5】梯级电价(smu1244)

Description

为了节能减排,发改委准备推行居民电价梯级收费制度。试行方案如下:每月用电在 100千瓦时(含)内的按照每千瓦时 0.45 元收取;超过 100千瓦时,但在 200千瓦时(含)内的超过部分加收 1分/千瓦时。超过 200千瓦时的,超过部分加收 2分/千瓦时。请输入你家的月度用电数,计算你家的电费(单位为元,结果保留 2位小数)并输出。

Input

输入是每月用电数。Ouput

输出每月电费。Sample Input

100

110

200

300

Sample Output

45.00

49.60

91.00

138.00

分析:每个用户都要独立算一次电费,用函数的方式可以让程序更有条理。设一个用户的用电量为 n,则计算电费的函数为:

【程序清单 5.10】1. #include<stdio.h>

108

Page 117: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2. double use(double n){

3. if(n<=100)

4. return 0.45*n;

5. else if(n<=200)

6. return 45+(n-100)*0.46;

7. else

8. return 91+(n-200)*0.47;

9. }

10. int main(){

11. double n;

12.

13. while(scanf("%lf",&n)!=EOF){

14. printf("%.2lf\n",use(n));

15. }

16. return 0;

17. }

运行过程为:30↙13.50120↙54.20200↙91.00250↙114.50

【例 5.6】求一正整数各位数字的和。 (smu1023)

分析:设这个正整数是 n,各位数字的和是一整数,把求各位数字的和设计成一个整数类型

的函数 sum(n)。Sum(n)可以看成是 n 的个位数加上 sum(n/10),n 的个位数为 n%10,也就是

sum(n)=n%10+sum(n/10),对 sum(n/10)用同样的方法,n/10后每次少一位,直到为 0.这是一个递归的过程,如图 5.4 所示。

109

Page 118: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 5.4 求 132各位数字和的递归图【程序清单 5.11】1. #include<stdio.h>

2. int sum(int n) //递归求和3. {

4. if(n==0) return 0;

5. else

6. {

7. return n%10+sum(n/10); //n的个位数加上 n/10的各位数字和8. }

9. }

10. int main()

11. {

12. int n;

13. while(scanf("%d",&n)!=EOF)

14. {

15. printf("%d的各倍数字和是%d\n",n,sum(n));

16. }

17. return 0;

18. }

运行的过程为:8↙8的各倍数字和是 8

33↙33的各倍数字和是 6

1678↙1678的各倍数字和是 22

【例 5.7】Fibonacci数列是 1,1,2,3,5,…。用递归函数求 Fibonacci数列的前 n项和。(smu1017)

分析:Fibonacci数列的规则是每一项是前两项的和,如果通项是 an,则有 a1=a2=1,an=an-

110

Page 119: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1+an-2。【程序清单 5.12】1. #include<stdio.h>

2. int fun(int n)

3. {

4. int a;

5. if (n==1||n==2)//递归的出口6. a = 1;

7. else

8. a = fun(n-1)+fun(n-2);//递归调用9. return a;

10. }

11.

12. int main()

13.

14. {

15. int n;

16. while(scanf("%d",&n)!=EOF)

17. {

18. printf("前%d项和是:%d\n",n,fun(n));

19. }

20. return 0;

21. }

运行的过程为:4↙前 4项和是:3

9↙前 9项和是:34

30↙前 30项和是:832040

【例 5.8】求曲线 y=sin(x)在[0,2π]的近似长度。分析:将[0,2π]进行 n等分,当 n 足够大时每一等分的曲线看成是一条线段,累加这些线段的

长度就是 y=sin(x)在[0,2π]的近似长度。如图 5.5 所示。

111

Page 120: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 5.5 y=sin(x)

曲线 y=sin(x)第 i、 i+1 个等分点所成线段的两端点是:( i/2π,sin(i/2π))、((i+1)/

2π,sin((i+1)/2π))。【程序清单 5.13】1. #include<stdio.h>

2. #include<math.h>

3. #define N 200 // 分成N 段4. double D=2*3.1415926/N; // 每一段的长度5.

6. double dis(double x1,double x2)

7. {

8. return sqrt((x1-x2)*(x1-x2)+(sin(x1)-sin(x2))*(sin(x1)-sin(x2)));

9. }

10.

11. double len()

12. {

13. double ll=0,x1,x2;

14. int i;

15. for(i=0;i<N;i++)

16. {

17. x1 = i*D;

18. x2 = (i+1)*D;

19. ll += dis(x1,x2);

20. }

21. return ll;

22. }

23. int main()

24. {

25. printf("y=sin(x)在[0,2π]的近似长度:%lf\n",len());

26. return 0;

112

Page 121: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

27. }

取N=200 运行的结果为:y=sin(x)在[0,2π]的近似长度:7.640297

取N=2000 运行的结果为:y=sin(x)在[0,2π]的近似长度:7.640394

为了保留小数点两位时,只要 100等分就可以得到理想值。

5.7 进阶【任务 5.1】Hanoi塔问题。(smu1224)

Description

相传古代有一个梵塔,塔内有 3 个座A、B、C,开始时 A座上有 64 个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这 64 个盘子从 A座移到 C座,但规定每次只允许移动一个盘,且在移动过程中在 3 个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座。要求编程序输出移动盘子的步骤。

Input

输入有若干种情况,每种情况一行,用一个正整数表示要移动的盘子数。n<20。Ouput

对每一种情况先输出一行:“The step to move n dishes:”。然后输出移动的过程。每个案例空一行Sample Input2

3

Sample OutputThe step to move 2 dishes: A->B A->C B->C

The step to move 3 dishes: A->C A->B C->B A->C B->A B->C A->C

分析:只有 1 个盘子时,直接移动就可;有 2 个盘子时,把上机一个盘子放入 B,底层的一

个盘子移动到 C,再将 B的盘子移到 C;有 3 个盘子时,借助 C把上面的两个盘子移到B,然后将 A的盘子移到 C,再将 B的盘子借助 A移到 C,……,这是一个递归的过程,我们只需分析移动 1 只盘子和 k(=3)只盘子时的情况就可以写出递归函数。如图 5.6 所示。

113

Page 122: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 5.6 Hanoi塔的移动【程序清单 5.14】1. #include <stdio.h>

2. void move(char x,char y)//移动的函数3. {

4. printf("%c->%c\n",x,y);

5. }

6.

7. void hanoi(int n,char one ,char two,char three) // 递归调用8. {

9. //void move (char x, char y);

10. if(n==1)

11. move(one,three);

12. else

13. {

14. hanoi(n-1,one,three,two);

15. move(one,three);

16. hanoi(n-1,two,one,three);

17. }

18. }

19. int main()

20. {

21. int m;

22. //freopen("input.in","r",stdin);

23. //freopen("output.out","w",stdout);

24. while(scanf("%d",&m)!=EOF)

25. {

26. printf("The step to move %d dishes:\n",m);

27. hanoi(m,'A','B','C');

114

Page 123: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

28. printf("\n");

29. }

30. return 0;

31. }

【任务 5.2】二分法求根(smu1153)

Description

用二分法求方程的根:2x^3-4x^2+3x-6=0

Input

输入有若干行,每行三个 float型的数 a,b,ε,表示要找的区间(a,b)及精确度 ε。Ouput

如果在(a,b)内找不到根就输出"Can't find it.".否则输出"x=x0",x0为所找的根。Sample Input

-10 10 0.00001 -10 0 0.00001 2 10 0.0001

Sample Output

x=2.00 Can't find it. x=2.00

分析:一般地,对于函数 f(x),如果存在实数 c,当 x=c 时,f(c)=0,那么把 x=c叫做函数 f(x)的零

点(根)。 解方程即要求 f(x)的所有零点。

假定 f(x)在区间(x,y)上连续。

先找到 a、b,使 f(a),f(b)异号,(如果 f(a)=0或 f(b)=0 说明已找到)说明在区间(a,b)内一定有零点,然后求 f[(a+b)/2],

现在假设 f(a)<0,f(b)>0,a<b

①如果 f[(a+b)/2]=0,该点就是零点;

② 如果 f[(a+b)/2]<0,则在区间((a+b)/2,b)内有零点,(a+b)/2=>a,从①开始继续使用中点函数值判断。

③ 如果 f[(a+b)/2]>0,则在区间(a,(a+b)/2)内有零点,(a+b)/2<=b,从①开始继续使用中点函数值判断。

这样就可以不断接近零点。

通过每次把 f(x)的零点所在小区间收缩一半的方法,使区间的两个端点逐步迫近函数的零点,以求得零点的近似值,这种方法叫做二分法。

从以上可以看出,每次运算后,区间长度减少一半,是线形收敛。另外,二分法不能计算复根和重根。在计算的过程中,如果判断 f(x0)的绝对值小于某一指定的值 ε(如 ε=0.00001),就可以说

x0是此方程的根。如图 5.7 所示。115

an, 14年7月17日,
此图是新加的
Page 124: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 5.7 二分法求根【程序清单 5.15】1. #include<stdio.h>

2. #include<math.h>

3. float fun(float x)

4. {

5. float f;

6. f = x*(x*(2*x-4)+3)-6;

7. return f;

8. }

9. int main()

10. {

11. float a,b,e;

12. float fa,fb,fc;

13. float c;

14. while(scanf("%f%f%f",&a,&b,&e)!=EOF)

15. {

16. fa=fun(a);

17. fb=fun(b);

18. if(fabs(fa)<e)

19. {

20. printf("x=%.2f\n",a);continue;

116

Page 125: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

21. }

22. if(fabs(fb)<e)

23. {

24. printf("x=%.2f\n",b);continue;

25. }

26. if(fa*fb>0)

27. {

28. printf("Can't find it.\n");continue;

29. }

30.

31. if(fa*fb<0)

32. {

33. while(1)

34. {

35. c = (a+b)/2;

36. fc = fun(c);

37. if(fabs(fc)<e)

38. {

39. printf("x=%.2f\n",c);break;

40. }

41. else

42. {

43. if(fa*fc<0)

44. {

45. b = c; fb = fun(b);

46. }

47. else

48. {

49. a = c; fa = fun(a);

50. }

51. }

52. }

53. }

54. }

55. return 0;56. }

117

Page 126: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

二分法是一个递归的过程,每次都可以看成是在某一区间[a,b]上找解。假设递归函数为:

binaryfunction(float a,float b );

请读者自己完成。

习题1.平面上有三 个点,通过调用 IsTriangle() 判 断这三 个点是否能构成三角形。

(smu1126)2.设 function(n)=n!请你编程通过调用 function()这个函数,求 1!+2!...n!。

function函数定义如下:int function(int n)

 int  i,f=1;

  for(i=1; i<=n; i++)

 f=f*i;

 return f;

 }

3.整数划分(smu1082)将 正 整 数 n 表 示 成 一 系 列 正 整 数 之 和 , 即 : n=n1+n2+...+nk , 其 中

n1>=n2>=...>=nk>=1,k>=1。

正整数 n的不同划分个数称为 n的划分数。如 6有 11种不同的划分: 5+1

4+2,4+1+1; 3+3,3+2+1,3+1+1+1; 2+2+2,2+2+1+1,2+1+1+1+1; 1+1+1+1+1+1. 对于这种问题,你可以找到下列的规律:

f(n,m)   = 1 ;     (n=m=1)

  f(n,m)=f(n,n)  ;    (n<m)

  f(n,m)=1+f(n,m-1)   ;      (n=m!=1)

118

Page 127: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

 f(n,m)=f(n,m-1)+f(n-m,m)  ; (n>m>=1)

n是指被划分的数 ,m 是指划分中出现的最大数。如 f(6,2)=4,具体划分是:2+2+2,2+2+1+1,2+1+1+1+1,1+1+1+1+1+1。 请你编程求 n的划分数。

4.复数除法定义:满足(c+di)(x+yi)=(a+bi)的复数 x+yi(x,y R)∈ 叫复数 a+bi除以复数c+di的商,给你 a+bi和 c+di 请计算 x+yi。(smu1083)

5.复数相加的公式是 (a+bi)+(c+di)=(a+c)+(b+d)i. 给出两个复数,请计算它们的和。(smu1084)

6.求 x(x+1)(x+2)e^(x+1)    在区间(a,b) 上的定积分。(smu1111)7. 给出年、月、日,计算该日是该年的第几天。要求计算天数 day定义为函数 int

SumDay(int month, int day);判断润年定义为函数 int leap (int year); (1116) 8.给出一些小于 1 大于 0的简单小数,要求你将它们转换成分数,结果必须是最简的。

(1121)9.输入十进制数 n(0<=n<=10000),请输出它对应的 k(2<=k<=36)进制数。

10,11…分别用A, B … 代替。(smu1130)10.(1131)有一个糊涂人,写了 n封信和 n 个信封,到了邮寄的时候,把所有的信

都装错了信封。设Dn为装错信封可能的种类数,可以用下面的递归公式:

编程求Dn,n由键盘输入。

11.正整数中的各位非零数字的乘积称为该数的数字乘积 .如 1620的数字乘积为1*6*2=12,12的数字乘积为 1*2=2。正整数的数字乘积根为反复取该整数的数字乘积,直到最后的数字乘积为一位数字,这个一位数字就叫该正整数的数字乘积根。例如 1620的数字乘积根为 2。编程求不超过 6位数字的正整数的数字乘积根。(smu1133)

12.小张前天找了份工作,他想给自己算算 n 个月后的工资会是多少,规定它第一个月的工资是m,从第二个月开始每个月都在上个月的基础上增长 5%,现在要算出他 n 个月的时候能领多少工资。 (smu1140)

13.用递归方法求 n 阶勒让德多项式的值,递归公式为:(smu1142)

119

Page 128: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

14.在一个很正式的社交场合里,每一个后来的人进场都要同前面已经在场的人握手。编程求有 n 个人陆续到场,总共握手几次。例如有 10 个人,第一人进来不用握手,第二个人进来与第一个握手 1 次,第三个人与前面的两人握手 2 次,共握手 3 次,……,第 10 个人进来与前面到场的人握手 9 次,共 45 次。(smu1334)

15. n 个数中取m 个数的组合记为 C(n,m),有如下性质:C(n,m)= C(n,n-m)= C(n-1,m-1)+C(n-1,m)

请用递归方法求 c(n,m)。

16.求数列 an: 1、2、1、-1、-2、-1、1、…、an-1- an-2的第 n项,n 从 1开始。(smu1197)17.有一个棋盘,在第一个格子里放 1粒米,在第 2 个格子中放第一个格子中两倍的

米,以此类推,计算 n 个格子中米粒的总和。(smu1304)18.有编号分别为 0,1,2,3,4 的五本书,准备分给 A, B, C, D, E 五个人,每个人

阅读兴趣用一个二维数组加以描述:(smu1267)

希望你写一个程序,输出所有分书方案,让人人皆大欢喜。假定 5 个人对 5 本书的阅读兴趣如下表:

5.2 5 人读 5本书的阅读兴趣表0 1 2 3 4

A 0 0 1 1 0

B 1 1 0 0 1

C 0 1 1 0 1

D 0 0 0 1 0

E 0 1 0 0 1

19. 一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱 L,面积只容得下一只青蛙落脚,同样右岸也有一石柱 R,面积也只容得下一只青蛙落脚。有一队青蛙从尺寸上一个比一个小。我们将青蛙从小到大,用 1,2,…,n编号。规定初始时这队青蛙只能

120

Page 129: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

趴在左岸的石头 L上,按编号一个落一个,小的落在大的上面。不允许大的在小的上面。在小溪中有 S 个石柱,有 y片荷叶,规定溪中的柱子上允许一只青蛙落脚,如有多只同样要求按编号一个落一个,大的在下,小的在上,而且必须编号相邻。对于荷叶只允许一只青蛙落脚,不允许多只在其上。对于右岸的石柱 R,与左岸的石柱 L一样允许多个青蛙落脚,但须一个落一个,小的在上,大的在下,且编号相邻。当青蛙从左岸的 L上跳走后就不允许再跳回来;同样,从左岸 L上跳至右岸 R,或从溪中荷叶或溪中石柱跳至右岸 R上的青蛙也不允许再离开。问在已知溪中有 S根石柱和 y片荷叶的情况下,最多能跳过多少只青蛙?(smu1268)

20.对于一个正整数,请你求出各位数字的积。(smu1281)21.给你一串只由“(”和“)”组成的字符串。判断它们能否配对,如果能配对请算出它

们最多的嵌套次数是多少。(smu1291)22.一种特殊的病毒,当某个文件感染了这种病毒后,两天后,这个文件每天都会把

病毒感染给 2 个未中病毒的文件。假设第一天有一个文件被这种病毒感染了,那么第 n天总共有多少文件受到该病毒感染呢?

如输入:1

2

3

4

5

输出:1

1

3

5

11

23.给出一个字符串和一个要找的字母,编程统计在一个字符串中该字母出现几次。例如输入:

abcde a3

aaaaaa aa

#

输出:0

3

24.求A^B的最后三位数表示的整数。说明:A^B的含义是“A的 B 次方” ,1<=A,B<=10000

121

Page 130: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

如,输入:2 3

12 6

6789 10000

0 0

输出:8

984

1

25.给定一个方程 2x^3-4x^2+3x-6=0,请用牛顿迭代法编程求迭代 n 次的根。(smu1151)

26.有一个数列是 1,2+3,4+5+6,7+8+9+10,11+12+13+14+15,...。请编程求第 n项的值。(smu1490)

27.把抛物线 y=a(x-x1)(x-x2)的顶点( (x1+x2)/2,a((x1+x2)/2-x1)( (x1+x2)/2-x2) )及与 x

轴的交点(x1,0)(x2,0)围成的三角形绕 x轴旋转一周将得到一个旋转体(两个圆锥的组合体)。请编程求出这旋转体的体积。(smu1343)

28.将 y=sin(x) 0<=x<=3.1415926,绕 x轴旋转一周就可以得到一个类似球状的旋转体。请编程求这个旋转体的体积。(smu1336) 提示:用微分的思想将旋转体分成若干个(请 200等分以上)小的部分,每个部分近似看成一个圆柱体,将每个小圆柱体的体积相加,就是该旋转体的体积。π取 3.1415926。

29.求抛物线 y=a(x-x1)(x-x2)与 x轴在(x1<=x<=x2)围成的面积。(smu1354)输入三个 double型的数 a,x1,x2,输出 y的值。例如,输入 2 -1.2 2,输出 10.92。

122

Page 131: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 6章 批量数据处理--数组

导学对大规模的数据处理;一定要用到数组。掌握数组有 2 个要点,能用循环语句控制数组;

能灵活处理和使用数组的下标。学完数组知识后,可以尝试排序、处理字符、统计二维表等程序设计。Debug是调试工具,也是学习数组的好帮手。

6.1 一维数组为 了 表 达 一 组 有 序 的 数 据 集 合 , 比 如 10 个 人 的 C 语 言 成 绩 :

{90,91,92,99,80,77,87,89,60,100},需要定义同一类型的 10 个变量。引用下标法,把这 10 个成绩分别存在 a[0]、a[1]、a[2]、…、a[9]中,这就是一维数组的形式。

6.1.1 一维数组的定义一维数组定义的一般格式为:类型符 数组名[常量表达式];还可以同时对变量进行初始化:类型符 数组名[常量表达式]={初始值表};10 个人的 C语言考试成绩是整数类型,可能定义成:int a[10];表明有 a[0]、a[1]、a[2]、

…、a[9]这 10 个变量。如果给定了分数值,数组定义可以写成:int a[10]={90,91,92,99,80,77,87,89,60,100};

说明:(1)类型符是 C中有的或是已经定义的数据类型,如 int、double、char等。

123

Page 132: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(2)数据名的命名规则和变量名相同,遵循标识符命名规则。(3)在“[]”内的常量表达式表明该数组的长度,即数组中元素的个数。(4)常量表达式中可以包括常量和符号常量,但不能使用变量。(5)数组的下标从 0开始使用,下标的最大值为数组中元素的个数减 1。使用时,下

标不可以超过这个范围,否则会产生数组越界的错误。(6)常量表达式的值可以为空,长度由后面的数据个数决定,如: int a[]={2,3};这时

数组的长度是 2。(7)数组的遍历一般用循环语句实现,循环变量的初值为数组的首元素下标,循环次

数是数组的长度。如【程序清单 6.1】所示。【程序清单 6.1】1. #include <stdio.h>

2. int main()

3. {

4. int a[10]={90,91,92,99,80,77,87,89,60,100};

5. int i;

6. for(i=0;i<10;i++)

7. {

8. printf("a[%d]=%d\n",i,a[i]);

9. }

10. return 0;

11. }

运行的结果为:a[0]=90

a[1]=91

a[2]=92

a[3]=99

a[4]=80

a[5]=77

a[6]=87

a[7]=89

a[8]=60

a[9]=100

注:程序中的第 4行可以改成:int a[10];

使用时再赋值:a[0]=90,a[1]=91,a[2]=92,a[3]=99,a[4]=80,a[5]=77,a[6]=87,a[7]=89,a[8]=60,a[9]=100;

124

Page 133: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

6.1.2 一维数组的引用一维数组元素的表示形式为:数组名[下标]

每一个数组元素都相当于一个变量,因此,可以被赋值,也可以参与运算。【例 6.1】把通项为 an=3n+1(n=0,1,2,…)的数列依次放入数组 a[]中。然后分别求

出下标为奇数项的和 s1及下标为偶数项的和 s2。(smu1568)分析:首先定义一个长度为 101的数组,使得每种情况 n 都有足够的空间。我们将要写两个函

数,一个用于计算和存储 an的值;另一个用于计算 s1,s2。为了便于函数间的使用,将这3种变量设为全局变量。奇数项的和就是 a[1]+a[3]+…;偶数项的和就是 a[0]+a[2]+…,也就是:在循环语句中,步长为 2。

【程序清单 6.2】1. #include <stdio.h>

2. #define N 101

3. int a[N],s1,s2;

4. void born(int n)

5. {

6. int i;

7. for(i=0;i<=n;i++)

8. a[i] = 3*n+1;

9. }

10. void sum(int n)

11. {

12. int i;

13. s1 = 0;

14. s2 = 0;

15. for(i=0;i<=n;i=i+2) // 循环步长为 2

16. {

17. s2 += a[i]; // 偶数项的和从 0开始18. s1 += a[i+1]; // 奇数项的和从 1开始19. }

20. }

21. int main()

125

Page 134: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

22. {

23. int n=6; // 假设 n=6,请你改为通过键盘输入 n

24. born(n);

25. sum(n);

26. printf("s1=%d\ts2=%d\n",s1,s2);

27. return 0;

28. }

运行结果为:s1=30 s2=40这个过程可以通过 debug的功能查看。把断点设在第 23行,然后一步步观察,当

born()函数执行后,我们查看变量 a[],情况如图 6.1 所示。

图 6.1 数组 a[]中的值当执行到 sum()函数中的 for循环中,i=0 时的第 17行的情况如图 6.2 所示:

图 6.2 执行 sum()内的一个时刻【例 6.2】给定一个有 n 个元素(1<n<100)的一维数组 a[n],我们要对数组之间的元素

进行 n-1 次的操作。(smu1521)126

Page 135: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 1 次,a[i+1]-a[i]a[i],i=1,…,n-1;第 2 次,a[i+1]-a[i]a[i],i=1,…,n-2;……

第 n-1 次,a[i+1]-a[i]a[i],i=1;最终得到一个值 a[0]。例如对于:1 3 6 0 2

第 1 次操作后为:2 3 -6 2

第 2 次操作后为:1 -9 8

第 3 次操作后为:-10 17

第 4 次操作后为:27

请你编程求之。要求:输入要求:输入的数据有若干个案例,每个案例一行。每行的第一个数是 n,表示后面

有 n 个整数。输出要求:每个案例输出一行,先输出“Case id:”,再输出答案,id是案例的序号,

从 1开始。分析:由于 n的最大规模不超过 100,可以定义一个一维数组 a[100]来存放输入的数。操作用

两重循环控制,一重控制整列操作的次数,有 n-1 次;一重循环控制每次进行的前后对减的次数及顺序,从 0到 n-i 次循环。

【程序清单 6.3】1. #include<stdio.h>

2. void in(int n,int a[]) // 输入数据3. {

4. int i;

5. for(i=0;i<n;i++)

127

Page 136: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

6. scanf("%d",&a[i]);

7. }

8. int work(int n,int a[]) // 计算9. {

10. int i,j;

11. for(i=1;i<n;i++) //对数组之间的元素进行 n-1 次操作12. for(j=0;j<n-i;j++) //第 i 次的操作13. {

14. a[j] = a[j+1]-a[j];

15. }

16. return a[0]; // 返回最后算出的答案17. }

18.

19. int main()

20. {

21. int i,j,a[100],n,ca=1;

22. while(scanf("%d",&n)!=EOF)

23. {

24. in(n,a);

25. printf("Case %d:%d\n",ca++,work(n,a));

26. }

27. return 0;

28. }

运行过程为:3 1 2 3↙Case 1:0

4 -1 5 9 -4↙Case 2:-15

8 55 60 78 32 -9 0 4 6↙Case 3:140

在main()、in()和work()中,n是不一样的变量,使用时要进行值传递;a是数组变量,表示内存中的地址,对 a的元素操作就是对地址内的数据进行操作,因此在 24、25行中对 a

是传地址,其值会发生改变。

6.2 二维数组在程序设计中,常常需要存储一个矩阵形式的数据,并且希望只要给定行号和列号,

就能立即访问到矩阵中的元素。在数学中是通过使用行号和列号来控制的。如表 6.1 所示。表 6.1学生成绩表及对应的变量

128

Page 137: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

语文/0列 数学/1列 英语/2列 综合/3列张三//0行 85//c[0][0] 92//c[0][1] 87//c[0][2] 69//c[0][3]

王五//1行 88//c[1][0] 86//c[1][1] 95//c[1][2] 87//c[1][3]

李四//2行 78//c[2][0] 86//c[2][1] 98//c[2][2] 87//c[2][3]

6.2.1 二维数组的定义二维数组定义的一般格式为:类型符 数组名[常量表达式] [常量表达式];还可以同时对变量进行初始化,格式为:类型符 数组名[常量表达式] [常量表达式]={初始值表};表 6.1的数据就可以定义为:int c[3][4]={{85,92,87,69},{88,86,95,87},{78,86,98,87}};

说明:(1)类型符是 C中有的或是已经定义的数据类型,如 int、double、char等。(2)数据名的命名规则与变量名相同,遵循标识符命名规则。(3)在“[]”内的常量表达式表明长度,一般第 1 个常量表达式值表示行的个数,第 2

个常量表达式值表示列的个数,也可以相反。(4)常量表达式中可以包括常量和符号常量,但不能包括变量。(5)行下标和列下标都是从 0开始的。各自下标的最大值为长度减 1,否则会产生数

组越界。(6)数组的初始化可以在定义时进行,即给数组中的元素赋初值。如【程序清单 6.4】

的第 4行所示。(7)二维数组的遍历一般使用双重循环实现。先对行进行循环,在循环体内,再对列

的元素进行循环。表 6.1的输出如【程序清单 6.4】所示。【程序清单 6.4】1. #include <stdio.h>

2. int main()

3. {

4. int i,j,c[3][4]={{85,92,87,69},{88,86,95,87},{78,86,98,87}};

5. for(i=0;i<3;i++) // 行循环6. {

7. for(j=0;j<4;j++) // 列循环129

Page 138: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

8. printf("c[%d][%d]=%d ",i,j,c[i][j]);

9. printf("\n"); // 每行后输出一个换行10. }

11. return 0;

12. }

运行结果为:c[0][0]=85 c[0][1]=92 c[0][2]=87 c[0][3]=69

c[1][0]=88 c[1][1]=86 c[1][2]=95 c[1][3]=87

c[2][0]=78 c[2][1]=86 c[2][2]=98 c[2][3]=87

6.2.1 二维数组的引用二维数组中的元素表示形式为:数组名[下标][下标]

每一个数组元素都相当于一个变量,因此,可以被赋值,也可以参与运算。【例 6.3】对表 6.2的数据求各个学生的总分

表 6.2学生成绩表语文/0列 数学/1列 英语/2列 综合/3列 总分

张三/0行 85/c[0][0] 92/c[0][1] 87/c[0][2] 69/c[0][3]

王五/1行 88/c[1][0] 86/c[1][1] 95/c[1][2] 87/c[1][3]

李四/2行 78/c[2][0] 86/c[2][1] 98/c[2][2] 87/c[2][3]

分析:我们可以增加一列来存放总分。这样,二维数组的规模就是 c[3][5]。【程序清单 6.5】1. #include <stdio.h>

2. #define ROW 3

3. #define COLUMN 5//多定义一列存放总分4. int main()

5. {

6. int i,j,c[ROW][COLUMN]={{85,92,87,69},{88,86,95,87},{78,86,98,87}};

7. for(i=0;i<ROW;i++) // 行循环8. {

9. c[i][COLUMN-1] = 0; // 总分放在 c[][COLUMN-1]中,初始化为 0

10. for(j=0;j<COLUMN-1;j++) // 列循环求和11. c[i][COLUMN-1] += c[i][j] ;

12. }

13. for(i=0;i<ROW;i++)//行循环14. {

130

Page 139: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

15. for(j=0;j<COLUMN;j++) // 列循环16. printf("c[%d][%d]=%d ",i,j,c[i][j]);

17. printf("\n"); // 每行后输出一个换行18. }

19. return 0;

20. }

运行结果为:c[0][0]=85 c[0][1]=92 c[0][2]=87 c[0][3]=69 c[0][4]=333

c[1][0]=88 c[1][1]=86 c[1][2]=95 c[1][3]=87 c[1][4]=356

c[2][0]=78 c[2][1]=86 c[2][2]=98 c[2][3]=87 c[2][4]=349

6.3 字符数组在程序设计中,常常要对字符串进行处理。字符串的处理基于字符处理,字符数组就

是字符串,因此,要处理字符问题就要先掌握字符数组。

6.3.1 字符数组的定义定义字符数组的格式为:char 字符数组名[最大字符个数+1]=”字符串”;

或不说明数组元素个数,系统会根据初值的情况来补上数组的长度,格式化为:char 字符数组名[]=”字符串”;

例如:

char s[8]=”Chinese”;

或:

char s[]=”Chinese”;

还可以先定义,待使用时再赋值。例如:char s[8];其内存对应的结构如图 6.3 所示:

s C h i n e s e \0

  0 1 2 3 4 5 6 7

131

Page 140: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 6.3 字符串 s

字符串数组的后面一定要存储一位’\0’表示结束,如果字符数组的长度比实际字符的长度长很多,则在内存中后面的位全补’\0’。

字符数组不能直接赋值,但字符数组的元素还可以逐个赋值,如【程序清单 6.6】所示。【程序清单 6.6】1. #include <stdio.h>

2. int main()

3. {

4. char s[6];

5. s[0] = '1';

6. s[1] = 'a';

7. s[2] = ‘b’;

8. s[3] = '#';

9. s[4] = '!';

10. s[5] = '\0';

11. printf("%s\n",s);(可以整体操作数组)12. return 0;

13. }

运行结果为:1ab#!

6.3.2 字符数组的使用【例 6.4】从键盘输入一个字符串,长度不超过 20,再将字符串中的数字部分按顺序输

出。分析:将输入的字符串存入字符数组中,然后逐个检查各个字符,是数字就输出。 【程序清单 6.7】1. #include <stdio.h>

2. int main()

3. {

4. char s[21];

5. int i;

6. scanf("%s",s);//输入一个字符串,7. i = 0; //i用于字符串的下标8. while(s[i]!='\0')//

9. {

132

Page 141: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

10. if(s[i]>=48&&s[i]<=57) //判断是否为数字,十进制数 48是 0的ASCII码,十进制数57是 9的ASCII码

11. printf("%c",s[i]); //输出一个数字12. i++;//下一个13. }

14. printf("\n");

15. return 0;

16. }

运行过程为:asd234gg673k0↙2346730

【例 6.5】在一篇文章中除最后一个字符外,只有小写字母、空格和换行符,没有另外的标点、数字和大写字母等。该文章以’#’结尾。请你编程统计字母个数。(smu1028)分析:用一维整数数组 al[26]分别存放 26 个小写字母的个数,用字符数组 s[201]存放

文章。对文章中的各个字符分别判断是否是小写字母,如果是小写字母就将对应的字母个数加 1。不妨设‘a’的个数放入 al[0]中,‘b’的个数放入 al[1]中,…,‘z’的个数放入 al[25]

中,如果当前的字母是 C,对应数组的下标就是 C-‘a’,即 C与‘a’的ASCII码的差。【程序清单 6.8】1. #include<stdio.h>

2. #include<string.h>

3. int main()

4. {

5. char s[201],ch;

6. int al[26],i;

7. gets(s);

8. i = 0;

9. memset(al,0,sizeof(al));

10. while(s[i]!='#')

11. {

12. if(s[i]>='a'&&s[i]<='z')

13. al[s[i]-'a']++;

14. i++;

15. }

16. for(ch='a';ch<='z';ch++)

17. {

18. printf("%c %d\n",ch,al[ch-'a']);

19. }

20. return 0;

21. }

运行结果为:133

Page 142: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

there was an echo on the line and I couldn't hear clearly#↙a 5

b 0

c 3

d 2

e 7

f 0

g 0

h 4

i 1

j 0

k 0

l 4

m 0

n 5

o 3

p 0

q 0

r 3

s 1

t 3

u 1

v 0

w 1

x 0

y 1

z 0

注:memset(al,0,sizeof(al));是将 0拷贝到数组 al中,使得数组 al中的元素全为 0。需要加上头文件 string.h。详细使用请看附录 D

6.3.3 字符串函数C中提供了很多处理字符串的函数,有对字符(串)的各种判断、求字符串长度、大小

写字母转换、字符串拷贝等,详细请看附录 D中的字符函数和字符串函数。使用前要包含头文件 string.h或 ctype.h。

利用库函数,【程序清单 6.7】中的第 10行判断是否为数字可以改写成:if(isdigit(s[i]))。【例 6.6】从键盘上输入 3 个字符串,再按字典序输出它们。(smu1316)

134

Page 143: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

分析:为了简单处理这个问题,写一 csort()函数将两个字符串按字典序排列。再对这 3

个字符串分别两两调用。【程序清单 6.9】1. #include <stdio.h>

2. #include <string.h>

3.

4. void csort(char a[], char b[]) // 数组变量作为参数5. {

6. char temp[20];

7. if(strcmp(a,b)>0)

8. {

9. strcpy(temp,a); // 不可以使用 temp=a

10. strcpy(a,b);

11. strcpy(b,temp);

12. }

13. }

14.

15. int main()

16. {

17. char a[20],b[20],c[20];

18. scanf("%s %s %s",a,b,c);

19. csort(a,b);

20. csort(a,c);

21. csort(b,c);

22. printf("新的顺序是:%s %s %s\n",a,b,c);

23. return 0;

24. }

运行过程为:one 89089 two↙新的顺序是:89089 one two注:(1)在 csort()函数中,用数组名 a、b传参,是地址传参,csort()函数运行后,改变了

a、b地址中的值(详细请看第 7章)。(2)字符串变量之间不可以直接赋值,也就是:将数组 a(字符串)的值传给数组

temp(字符串),不可以使用 temp=a,而要使用字符串复制函数 strcpy(temp,a);并加上头文件 string.h。

135

Page 144: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

6.4 案例及分析【例 6.7】利用一维数组对 n 个数进行冒泡排序。(smu1062)

分析:不妨设 n=5,把 5 个数分别放在 5 个数组 a[0]、…、a[4]中,处理后结果为:a[0]<…

<a[4]。冒泡法的基本思路是:每次将相邻两个数进行比较和交换,使得小的在前,大的在后。

开始分别处理 a[0]与 a[1],a[1]与 a[2],…,a[n-2]与 a[n-1],结果是 a[n-1]最大。接着对 a[0]

到 a[n-2]之间的数进行同样的处理,得到的 a[n-2]是 a[0]到 a[n-2]中的最大数,以此类推,最后处理 a[0]与 a[1]。处理过程的数据变化如表 6.3 所示:

表 6.3 冒泡排序过程次数 a[0]=6 a[1]=7 a[2]=5 a[3]=8 a[4]=4

第 1 次 6 5 7 4 8

第 2 次 5 6 4 7

第 3 次 5 4 6

第 4 次 4 5

n 个数要进行 n-1 次的处理,如果次数 i 从 0开始,第 i 次就要处理从 a[0]到 a[n-i]之间的数。

【程序清单 6.10】1. #include <stdio.h>

2. void sort(int a[],int n)

3. {

4. int i,j,t;

5. for(i=0;i<n-1;i++)

6. for(j=0;j<n-i-1;j++)

7. {

8. if(a[j]>a[j+1])

9. {

10. t = a[j];

11. a[j] = a[j+1];

12. a[j+1] = t;

13. }

14. }

15. }

16. int main()

136

Page 145: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

17. {

18. int i,n=5,a[]={6,7,5,8,4};

19. sort(a,n);

20. for(i=0;i<n;i++)

21. printf("%d ",a[i]);

22. printf("\n");

23. return 0;

24. }

运行结果为:4 5 6 7 8

注:本题还可以用选择排序,也就是:第 1 次找出 n 个数的最大数,对调位置放入 a[n-1]

中(或直接将 a[n-1]与前 n-1 个数比,使 a[n-1]最大);第 2 次将 a[0]~a[n-2]个数的最大数放入 a[n-2]中;……;以此类推,直到这 n 个数按从小到大的顺序排列。请读者尝试。

【例 6.8】要求打出一个米字,米字撇的长度为 n(2<n<=10)。(smu1120)

分析:米字可以看成是一个(2n+1)*(2n+1)的字符阵,第 n+1行、第 n+1列、以及两条对角线看成用‘*’号填空,其它部分用空格填空。程序中的 n不断由键盘输入。

【程序清单 6.11】1. #include <stdio.h>

2. #include <string.h>

3. void set(int n,int a[100][100])

4. {

5. int i,j;

6. for(i=1;i<=n;i++) // 左上的对角线7. a[i][i] = '*';

8. for(i=2*n+1;i>=n+2;i--) // 左下的对角线9. {

10. j=2*n+2-i;

11. a[i][j] = '*';

12. }

13. for(i=1;i<=2*n+1;i++) // 第 n+1行放‘*’14. a[n+1][i] = '*';

15. for(i=1;i<=2*n+1;i++) // 第 n+1列放‘*’16. a[i][n+1] = '*';

17. for(i=2*n+1;i>=n+2;i--) // 右上的对角线18. {

19. j=2*n+2-i;

20. a[j][i] = '*';

21. }

22. for(i=n+2;i<=2*n+1;i++) // 右下的对角线137

Page 146: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

23. a[i][i] = '*';

24. }

25. void out(int n,int a[100][100])

26. {

27. int i,j;

28. for(i=1;i<=2*n+1;i++)

29. {

30. for(j=1;j<=2*n+1;j++)

31. printf("%c",a[i][j]);

32. printf("\n");

33. }

34. printf("\n");

35. }

36. int main()

37. {

38. int n,j,i;

39. char a[100][100];//

40. while(scanf("%d",&n)!=EOF)

41. {

42. memset(a,' ',sizeof(a)); // 把 a阵列清空43. set(n,a); //填充“*”号44. out(n,a); //输出图形45. }

46. return 0;

47. }

运行过程如图 6.4 所示:

图 6.4程序清单 6.11的运行过程图138

Page 147: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

我们可以在 set()函数中合并一些循环,使代码简化:void set(int n,int a[100][100])

{

int i,j;

for(i=1;i<=2*n+1;i++)

a[i][i]= '*';

for(i=2*n+1;i>=n+2;i--)//

{

j=2*n+2-i;

a[i][j] = '*';

a[j][i] = '*';

}

for(i=1;i<=2*n+1;i++)

{

a[n+1][i] = '*';

a[i][n+1] = '*';

}

}

注:语句memset(a,’ ‘,sizeof(a)); 是对数组赋初值’ ‘,这时要加上头文件 string.h。

【例 6.9】湖泊水深(smu1163)

测量湖泊的水深,湖中各处的水深是不一样的。可以给湖面打上格子,测量每个格子的深度。“0”表示地面,数字 1,2,3,4,5表示水深,单位为m。每一格的大小为 5m×5m。

如下数据所示:0 0 1 2 2 3 0 0 0

0 2 3 5 5 3 2 0 0

0 1 4 3 4 2 2 1 0

0 0 1 1 0 0 1 1 0

0 0 0 0 0 0 0 0 0

Input

假设有若干种案例。每个案例的第一行是两个 int类型的变量 m、n,表示湖面所处的位置有 m×n格,0、0表示结束。接着有m行、n列的数字表示湖面各处水深情况。

Output

请你编程求湖面的面积和湖的平均水深。输出格式是: 每种情况输出一行,先输出“Case id:”,id为序号,然后输出湖面的面积和湖的平均水深。

Sample Input

5 9

0 0 1 2 2 3 0 0 0

0 2 3 5 5 3 2 0 0

0 1 4 3 4 2 2 1 0

0 0 1 1 0 0 1 1 0

139

Page 148: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

0 0 0 0 0 0 0 0 0

0 0

Sample OutputCase 1:525m×m 2.33m

【程序清单 6.12】1. #include <stdio.h>

2. int s;

3. double pd;

4. void input(int m,int n,int hu[100][100]) // 输入5. {

6. int i,j;

7. for(i=1;i<=m;i++)//input

8. for(j=1;j<=n;j++)

9. {

10. scanf("%d",&hu[i][j]);

11. }

12. }

13. void calculate(int m,int n,int hu[100][100]) // 计算14. {

15. int i,j,k=0,d=0;

16. for(i=1;i<=m;i++)

17. for(j=1;j<=n;j++) //计算 k,d

18. {

19. if(hu[i][j]>0)

20. {

21. k++;

22. d += hu[i][j];

23. }

24. }

25. s = 25*k;

26. pd = (double)d/k;

27. }

28. int main()

29. {

30. int m,n,hu[100][100],ca=1;

31. while(scanf("%d%d",&m,&n)!=EOF)

32. {

33.

34. if(m==0&&n==0) break;

35. input(m,n,hu);

36. calculate(m,n,hu);

37. printf("Case %d:%dm×m %.2lfm\n",ca++,s,pd);

38. }

140

Page 149: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

39.

40. return 0;

41. }

6.5 进阶【任务 6.1】求 100以内的素数。(smu1122)

Description

找出 100以内所有的素数。Ouput每行输出 10 个数,每个数占一个 tab位。分析 1:要判断整数 i是素数,就得判断 i不能被 2~i-1之间的所有的整数整除;如果 i能被 k*j

的数整数,就一定能被 j整除,这样就有下列的方法——标记法或筛选法。先把 1~100分别存入 a[1]~a[100]中,先看成素数,做上标记,再判断。如果 i不是素数,

就把 a[i]的值赋为 0。找出第 1 个素数 2,将后面下标为 2的倍数的数组元素全部赋值为 0;再找第 2 个素数

3(不为 0的数),将后面下标为 3的倍数的数组全部赋值为 0;接着找第 3 个素数做同样

的事;……;直到找到下标是 100为止。实际上只要判断到 为止。【程序清单 6.13】1. #include <stdio.h>

2. #include <math.h>

3. int a[101];

4. void prim(int m)

5. {

6. int i,j;

7. for (i=1;i<=m;i++) // 第 i 个数组存放 i

8. a[i]=i;

9. a[1]=0;//1不是素数10. for (i=2;i<=sqrt(m);i++) // 只要判断能否被前 个数整除11. {

12. if(a[i]==0) continue;

13. for (j=i+1;j<=m;j++) // i后面所有被 a[i]整除的数都不是素数14. {

15. if(a[j]!=0&&a[j]%a[i]==0)

141

Page 150: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

16. a[j]=0;

17. }

18. }

19. }

20. int main()

21. {

22. int i,j,n;

23. prim(100); // 找出前 100 个数中的素数24. for (i=2,n=0;i<=100;i++)

25. {

26. if(a[i]!=0)

27. {

28. printf("%d",a[i]);

29. n++;

30. if(n%10==0)//

31. {

32. printf("\n");

33.

34. }

35. else if(n!=0) printf("\t");

36. }

37. }

38. printf("\n");

39. return 0;

40. }

运行结果为:2 3 5 7 11 13 17 19 23 29

31 37 41 43 47 53 59 61 67 71

73 79 83 89 97

注:13~17行可以改成:for (j=i+i;j<=m;j=j+i)

a[j]=0;

也就是素数的倍数都不是素数,这样提高了运算速度。分析 2:直接判断 1到 100的每个数是否为素数,判断时,只要判断不能被自己小的素数整除

就可以,并把找到的素数放在数组 a里。方法是:先找第 1 个素数 2,使 a[1]=2,从 3开始到 100,每个数都判断是否能被前面的素数整除,都不能整除的就是素数,然后加入数组 a

中。142

Page 151: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

【程序清单 6.14】1. #include <stdio.h>

2. #include <math.h>

3. int a[101];

4. int prim(int m)

5. {

6. int i,j,k=1;

7. a[k++]=2;

8. for (i=3;i<100;i++)

9. {

10. for (j=1;j<k;j++)

11. {

12. if(i%a[j]==0) break;

13. }

14. if(j>=k) a[k++]=i;

15. }

16. return k-1;

17. }

18. int main()

19. {

20. int i,k,n;

21. k = prim(100);

22. for (i=1,n=0;i<=k;i++)

23. {

24. printf("%d",a[i]);

25. n++;

26. if(n%10==0)//

27. {

28. printf("\n");

29.

30. }

31. else

32. printf("\t");

33. }

34. printf("\n");

35. return 0;

36. }

运行结果不变。这时 a数组中存入的全是素数。【任务 6.2】数字三角形(smp1042)

Description

图 6.5中的左图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,143

Page 152: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。右图是找到了一条最佳路径。你的任务就是求出最佳路径上的数字之和。 注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。

图 6.5 数字三角形及最佳路径Input

输入有多组测试数据,输入以 EOF为结束,对于每一组测试数据,输入的第一行是一个整数 N (1 < N

<= 100),给出三角形的行数。下面的N行给出数字三角形。数字三角形上的数的范围都在 0和 100之间。Ouput

对于每一组测试数据输出一行,先输出 Triangle #i:,i 从 1开始,然后输出最大和的值。Sample Input

5

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

Sample Output

Triangle #1: 30

输入的数据存放在数组 d[][]中,从上到下依次是:d[1][1]

d[2][1] d[2][2]

d[3][1] d[3][2] d[3][3]

……

分析 1: 用递归的思想,每个数字左右两个数字三角形看成是小一级的问题。用 p(int

l,int r,int n)表示从 d[l][r]开始向下 n行数字三角形中的最大和,则p(int l,int r,int n)= max{d[l][r]+p(l+1,i,n-1),d[l][r]+p(l+1,i,n-1)}。//下左与下右两个数字三

角形中的和最大值。【程序清单 6.15】1. //用递归

144

Page 153: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2. #include<stdio.h>

3. int d[102][102];

4. int p(int l,int r,int n)

5. {

6. int i,max=0,s;

7. if(n==1) return d[l][r];

8. for(i=r;i<=r+1;i++)

9. {

10. s = d[l][r]+p(l+1,i,n-1);

11. if(max<s)

12. max = s;

13. }

14. return max;

15. }

16. void main()

17. {

18. int i,j,k=1,n;

19. while(scanf("%d",&n)!=EOF)

20. {

21. for(i=1;i<=n;i++)

22. for(j=1;j<=i;j++)

23. scanf("%d",&d[i][j]);

24. printf("Triangle #%d: %d\n",k++,p(1,1,n));

25. }

26. }

分析 2: 从底层开始,每一个数字都用最下层 2 个数中的最大者加上,这样到最上一个数得到的和就是最大和。也就是把 d[i][j]替换成 d[i][j]+max{d[i+1][j],d[i+1][j+1]}。

【程序清单 6.16】1. //先算子问题2. #include<stdio.h>

3. int maxl(int a,int b) // 求最大值4. {

5. int t;

6. if(b>a)

7. t=b;

8. else

9. t=a;

10. return t;

11. }

12. int main()

13. {

14. int k,i,j,n,d[105][105],t=1;

145

Page 154: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

15. while(scanf("%d",&n)!=EOF)

16. {

17. for(i=1;i<=n;i++)

18. for(j=1;j<=i;j++)

19. scanf("%d",&d[i][j]);

20. for(i=n-1;i>=1;i--)

21. for(j=1;j<=i+1;j++)

22. {

23. k = maxl(d[i+1][j],d[i+1][j+1]);

24. d[i][j]=k+d[i][j];

25. }

26. printf("Triangle #%d: %d\n",t++,d[1][1]);

27. }

28. return 0;

29. }

程序设计时,一般把主要的功能都写成函数,在 main()函数中直接调用即可。程序清单6.16中的第 20~25行可以写成函数:

int max_sum(int n,int d[105][105])

{

int k,i,j;

for(i=n-1;i>=1;i--)

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

{

k = maxl(d[i+1][j],d[i+1][j+1]);

d[i][j]=k+d[i][j];

}

return d[1][1];

}

在main()中的代码,请读者自己尝试完成。【任务 6.3】最大黑区域(smp1221)

Description

二值图像是由黑白两种像素组成的矩形点阵,图像识别的一个操作是求出图像中最大黑区域的面积。请设计一个程序完成二值图像的这个操作。黑区域由黑像素组成,一个黑区域中的每个像素至少与该区域中的另一个像素相邻,规定一个像素仅与其上、下、左、右的像素相邻。两个不同的黑区域没有相邻的像素。一个黑区域的面积是其所包含的像素的个数。

Input

输入由多个测试例组成。每个测试样例的第一行含两个整数 n和m, (1 <=n,m<=100), 分别表示二值图像的行数与列数,后面紧跟着 n行,每行含 m 个整数 0或 1,其中第 i行表示图像的第 i行的m 个像素,0表示白像素,1表示黑像素。同一行的相邻两个整数之间用一个空格隔开,两个测试例之间用一个空行隔开,最后一个测试例之后隔一个空行,再接的一行含有两个整数 0,标志输入的结束。

146

Page 155: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Output

每个测试例对应一行输出,含一个整数,表示相应的图像中最大黑区域的面积。Sample Input5 6

0 1 1 0 0 1

1 1 0 1 0 1

0 1 0 0 1 0

0 0 0 1 1 1

1 0 1 1 1 0

0 0

Sample Output

7

注:引自福州大学OJ 1082 。分析:从当前的值为 1的位置开始,按右左上下四个方向递归寻找,每找到一个位置

就做上记号,以免重复寻找。v[i][j]为第(i,j)的位置是否被访问,值为 0表示没有被访问,为 1表示被访问;f(i,j)表示(i,j)所在的最大黑区域;max是全局变量,表示最大黑区域中 1的个数。从上到下,从左到右搜索,如果(i,j)的值为 1 而且没有被访问到,就将黑区域数加 1,并从上、下、左、右继续搜索。这样一趟搜索得到的值是一块黑区域的值,再比较各个黑区域的值,就得出最大黑区域的值。

【程序清单 6.17】1. #include<stdio.h>

2. #include<string.h>

3. int v[100][100],a[101][101],max,n,m; //v访问标志4. void f(int i,int j) // 一块黑区域的值5. {

6. if(v[i][j]==0&&i>=0&&i<n&&j>=0&&j<m&&a[i][j]==1)

7. {

8. v[i][j]=1;

9. max++;

10. //从四个方向递归调用11. f(i+1,j); //下12. f(i-1,j); //上13. f(i,j-1); //左14. f(i,j+1); //右15. }

16. }

17. int main()

18. {

19. int i,j,ans;

20. while(scanf("%d %d",&n,&m))

147

Page 156: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

21. {

22. if(n+m==0) break;

23. ans=0;

24. for(i=0;i<n;i++)

25. for(j=0;j<m;j++)

26. scanf("%d",&a[i][j]);

27. memset(v,0,sizeof(v));

28. for(i=0;i<n;i++)

29. for(j=0;j<m;j++)

30. {

31. if(a[i][j]==1)

32. {

33. max=0;

34. f(i,j);

35. if(max>ans)

36. ans=max;

37. }

38. }

39. printf("%d\n",ans);

40. }

41. return 0;

42. }

148

Page 157: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题1.输入一个小于 32位的正整数,请加空格输出各位数。(smu1306)2.将一系列字符串按字典序输出。(smu1316)3.给定一段文章,请输出每个字母出现的次数(不分大小写)。(smu1599)

4.某一食堂包子很好吃,每开卖出很多,现在给出周一到周日每天卖出的包子数,请你编程判断是那一天卖出最多。如输入:100、120、123、98、98、102、101,输出是 3。

5.给定一串数字组成的字符串(最长可达 200),请统计 0~9各数字出现的次数。(与smu1028相似)

6.有 N 个人频繁进入商场,保安从录像中记录了他们进入商场的信息,请编程统计几号进入商场次数最多。如输入:

10

1 3 4 4 2 6 6 6 9 5

输出 6

7.给你一串的数,请 找出被 12 整除的数,注意 所给的数可能是 1~200 位。(smu1532)

如,输入:12

23

546576845634552523554665776574765653333

输出:Yes

No

No

8.编程求两个可乘矩阵A、B的乘积。(smu1057)

9.求行列式的值。10.阳阳很喜欢 88 两字符,他要在一串字符中寻找,请编程统计 88出现的次数。数字

可以重复使用。例如在 8and88and888中,88出现的次数是 3.

11.两个同样维数的矩阵可以相加,也就是把对应的同行同列的元素相加即可。请编程149

Page 158: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

计算。(smu1065)

12.图像在计算机内是以矩阵的方式存贮,要把图像逆时针旋转 90°就相当于把矩阵逆时针旋转 90°。请把所给的矩阵逆时针旋转 90°后输出。(smu1080)

比如输入的矩阵: ,输出的矩阵就是:

13.给你一个 n×n的矩阵,请求出它对角线上元素的和。(smu1074)

14.选择题得分(smu1072)有一种考试,只考选择题,共 10题,每题 10分。每次只能选“ABCD”中的一个。请编程对每一个人

的答案判分。如:

AABBDCACCD

BABBDCACCD

ABBBDCABBD

AABCCCACAD

AABBDCACCD

AABBDCACCD

第一行是正确答案,其余各行是每个考生的答题,考生的序号从 1开始。输出的结果就是:1:90

2:70

3:70

4:100

5:100

15.寻找魔方阵(smu1075)由 n*n 个数字所组成的 n 阶方阵,具有各对角线,各横列与纵行的数字和都相等的性

质,称为魔方阵。而这个相等的和称为魔术数字。若填入的数字是从 1到 n*n,称此种魔方阵为 n 阶正规魔方阵。如:下列是一个 3*3的魔方阵。 8  1  6

3  5  7

4  9  2

现在给你一些矩阵,请判断他们是否是魔方阵.

16.在数组中的某一元素,如果它在该行上最大,在该列上最小,这个元素就是鞍点。也可能没有鞍点。请在所给的数组中找出鞍点。(smu1076)

17.有 n 个数已从小到大排好队,第 n+1 个数要插进来。请指出它要插入的位置,然后再把这 n+1 个数从小到大输出。(smu1077)

18.工兵被派到一个矩阵区域去扫雷,有扫雷的地方标上扫雷的数量,没扫的地方标150

Page 159: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

上-1,请编程帮工兵数一数,扫了多少雷。扫雷区是一个 m*n的区域。(smu1087)

19.为了对一篇文章进行统计,要求你帮忙统计每行有多少个字符,每行以回车键作为结束标志。 (smu1480)

20.每一行是一个英文的句子。请你找出最长的单词,如果有多个一样多,则按序输出。

(smu1093)

21.有 n 个整数按由大到小顺序存放在一个数组中,输入一个数,要求用折半查找法找出该数是数组中第几个元素的值。如果该数不在数组中,则输出“无此数”。假设数组的下标是从 1开始。 (smu1096)

22.(1097)任意输入 n 个数,输出其中最大数和最小数,并输出它们在序列中的位置。

23.N 个数中有两个数是相同的,请编程找出。24.有一个 m*n的矩阵,求所有元素的最大值。 (smu1104)

25.(smu1115)专业选修课的班上有 20 名学生,号数是 1、2、…、20。一个学期以来老师布置了好多次作业,给出每次提交的号数,请统计每位学生提交的次数,最后列出全交的学生名单。

26.票数谁最多(smu1129)学生会主席选举开始了,有N 个人报名参加选举,学生会共有M 个人参加投票,每人只能投一票。他

们想让你帮他们找出票数最高的参选人。有多组测试数据,每组测试数据第一行给出两个数字 N,M; 接下来N 行 每行有一个字符串 name 表示参选人的姓名,name长度小于 20; 接下来M行,每行有一个字符串 name 表示 姓名为 name的参选者所获得的票数+1; 1<N<10,1<M<100。输出 票数最高者的姓名,及其票数。例如:输入:3 5

Li

Jack

Sun

Jack

Jack

Jack

Sun

Sun

输出:Jack 3

27. N盏灯排成一排,从 1到N按顺序依次编号。有N 个人也从 1到N依次编号。第一151

Page 160: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

个人(1 号)将灯全部关闭。第二个人(2 号)将凡是 2和 2的倍数的灯打开。第三个人(3

号)将凡是 3和 3的倍数的灯做相反的处理。(开就闭,闭的就打开)。以后的人也都如此处理。请问第N 个人操作之后,哪几盏灯是点亮的? (smu1132)

28.单数变成复数(smu1134)单数变成复数请编一个程序,可以将英语规则名词由单数变成复数。已知规则如下:

(a)以辅音字母 y 结尾,将 y 改成 i,再加 es。(b)以 s,x,ch,sh 结尾,则加 es;(c)以元音 o 结尾,则加 es;(d)其他情况直接加 s。

输入有若干行,每行一个英语规则名词。输出该名词的复数形式。例如:输入:brother

school

bus

fox

watch

dish

country

hero

veto

radio

输出:brothers

schools

buses

foxes

watches

dishes

countries

heroes

vetoes

radios

29.给定一串数字组成的字符串(最长可达 200),请你统计 0~9各数字出现的次数。(smu1137)如:11220651,输出 0:1 1:3 2:2 3:0 4:0 5:1 6:1 7:0 8:0 9:0.

30. 判断代码雷同(smu1150)OJ平台上大家都比较诚实、认真。然而有个别同学直接复制他人的代码,或只改变空格个数(scanf和

printf里的空格不算)。请编程判断所给的代码是否雷同。先输入一个正整数 T表示有 T种情况要检测。每种情况的两段代码头尾都有一行“##########”标记。 雷同的输出“Same”,否则输出“Not sure”。

152

Page 161: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

例如,输入:

1

##########

#include <stdio.h>

int main()

{

   int a;

   scanf("%d",&a);

   printf("%c",a);

   return 0;

}

##########

##########

#include <stdio.h>

int main(  )

{

int    a;

       scanf("%d",       &a);

      

     printf("%c", a);

       return 0;

}

输出:Same

31.编写一程序,将两个字符串连接起来,不要用 strcat。(smu1156)32.编写一程序,将两个字符串 s1和 s2 比较,若 s1>s2,输出一个正数;若 s1=s2,

输出 0;若 s1<s2,输出一个负数。不要用 strcpy函数。两个字符串用 gets函数读入。输出的正数或负数的绝对值应是比较的两个字符串相应字符的ASCII码差值。例如“A”〈“B”,输出-1。(smu1157)

33.编写一个程序,将字符数组 s2中的全部字符复制到字符数组 s1中。不用 strcpy函数。(smu1158)

34.有一篇英文,请编程统计有多少单词数。提示英文的标点符号是紧跟在单词后不算单词的个数。 (smu1159)

35.有一个班级的名单,序号从 1开始,任意说出一个号数,说出对应的名字。36.请编程统计成绩,要求按学生总成绩从高到低排序输出。(smu1198)

原成绩如表 6.4 所示:表 6.4 原成绩表

153

Page 162: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

math C graph

90 92 87

78 90 80

87 76 90

统计后的成绩如表 6.5 所示:(成绩按每个同学的总分从高到低依次排列)表 6.5 排序后的成绩表

num math C graph total

1 90 92 87 289

3 87 76 90 253

2 78 90 80 248

average 85.0 86.0 85.7 256.7

37.对字符的处理有取字符、插入、删除。 (不用系统函数)编程实现这个操作。(smu1164)

38.把一个点(x,y)向右平移 a 个单位、向上平移 b 个单位可以进行下列的矩阵运算:(smu1173)

经过变换后的点就是(x+a,y+b)。被乘的矩阵就叫做变换矩阵,形式如下:

把一个图形进行平移、旋转、放缩等的变换就是把图形中的每一点都乘以相应的变换矩阵。本题给你原来的点和变换矩阵,请编程求出变换后的点。输 入 有 若 干 种 案 例 , 每 个 案 例 一 行 , 每 行 有 11 个 数 :

x、y、a11、a12、a13、a21、a22、a23、a31、a32、a33,分别表示点(x,y)和变换矩阵中的 9 个元素。Sample Input

2 1 1 0 0 0 1 0 3 4 1

2 1 3 0 0 0 2 0 0 0 1

Sample Output

Case 1:(5,5)

Case 2:(6,2)

154

Page 163: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

39.在一个 3×3的矩阵中,元素是无序的,现在要让他们按指定的位置排列大小。如下所示:(smu1174)排序前的数据:

3 5 9

8 1 4

7 6 2

排序后的数据:8 4 7

1 9 3

5 2 6

如果 a1>=a2>=a3>=a4>=a5>=a6>=a7>=a8>=a9 则排序后的位置为:

a2 a6 a3

a9 a1 a7

a5 a8 a4

40.有一个柜子有m×n 个抽屉,里面放了物品,给出第几行、第几列,请编程取出相应的物品。例如表 6.6就是一个案例:(smu1177)

表 6.6 物品位置表  1 2 3 4 5

1 book pen pin-pong shoes ball

2 hand-bag notebook cup mobilephone wallet

3 clothes appale dictionary telephone camera

4 telescope computer tea laptop flower

当输入 2,5 时,输出”wallet“

41.扫雷(smu1188)扫雷是Windows自带的游戏,如图 6.7 所示。游戏的目标是尽快找到雷区中的所有地雷,而不许踩到

地雷。双击某一方块,如果方块上的是地雷,将输掉游戏。如果方块上出现数字,则表示在其周围的八个方块中共有多少颗地雷。

155

Page 164: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

 

图 6.7 扫雷界面图你的任务是在已知地雷出现位置的情况下,计算各个方块中的数据。如:

*...

 ....            “*”表示有地雷 .*..            “.”表示无地雷 ....

经过处理应得到 *100

 2210

1*10 

1110

42.假设 x是一个正整数,它的值不超过 65535(即 1<x<=65535),请编写一个程序,将 x分解为若干个素数的乘积。(smu1189)

43.求两个矩阵的积。矩阵A和 B可乘的条件是矩阵A的列数等于矩阵 B的行数。若A

是一个 p×q的矩阵,B是一个 q×r的矩阵,则其乘积 C=AB是一个 p×r的矩阵,如图 6.8 所示。其标准计算公式为:

156

Page 165: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 6.8 矩阵相乘输入两个矩阵,请你计算它们的积。(smu1057)(smp1103)44.复制与粘贴

人们总喜欢复制与粘贴,你的任务是按要求选出要复制的字符(串),然后粘贴到指定的地方。(smu1193)输入有若干种案例,每种案例四行。第一行是被复制的字符串,第二行是输入两个整数 i,j表示要复

制从第 i 个到第 j 个的字符。序号从 0开始。第三行是要粘贴的字符,第四行是一个正整数 k表示要在此位置之前插入复制过来的字符。例如,输入:How are you.

4 7

You welcome.

4

输出:You are welcome.

45.为了举办六一活动,有 m*n位小朋友排成阵列进行彩排,手举字母牌(A到 Z共26 个字母)进行排练。请你统计这 26 个字母各有多少个。 (smu1199)

46.对给定的字符串(长度不超过 100),请在字符”o”的后面加上”(don’t became

0)”。 (smu1101)47.一年一度的田径运动会即将开幕,让我们来简单模拟一项铅球比赛。假设有 n 个选

手(编号为 1、2…),每个选手都有 3 次投掷机会,每次投掷出的距离就是选手本次投掷的成绩(我们规定如果选手犯规,那么此次选手的得分为 0,如果不犯规那么选手的得分要大于 0)。在选手三次投掷完成后,选手在这三次中的最高成绩将是选手这次比赛的最终成绩。如表 6.7 所示:(smu1218)

表 6.7 铅球成绩表  第一次 第二次 第三次 成绩1 号选手 8.8 7.8 0 8.8

157

Page 166: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2 号选手 9.2 0 0 9.2

3 号选手 7.6 9.6 8.6 9.6

由表 6.11可以清晰的得知:1 号选手成绩为:8.80

2 号选手成绩为:9.20

3 号选手成绩为:9.60

第 1 次没人犯规第 2 次有 1 人犯规第 3 次有 2 人犯规请你编程实现这个过程。48.给你一个二维数组,该数组里面存储了 M*N(0<M,N<100)个正整数,请编程分

别求出该数组中奇、偶整数的个数。(smu1221)

49.zigzag数组(smu1272)输入一个正整数 n,求一个 n*n矩阵内含 1~n2,共 n2 个数。规定矩阵沿 45 度线递增,形

成一个 zigzag数组(JPEG编码里取像素数据的排列顺序),请编程实现。 注:在 JPEG 图形算法中首先对图像进行分块处理,一般分成互不重叠且大小一致的块,量化的结果保留了低频部分的系数,去掉了高频部分的系数,量化后的系数按 zigzag扫描重新组织,然后进行哈夫曼编码。zigzag数组是一个“之”字形排列的数组。例如:

0 1 5 6 14 15 27 28

2 4 7 13 16 26 29 42

3 8 12 17 25 30 41 43

9 11 18 24 31 40 44 53

10 19 23 32 39 45 52 54

20 22 33 38 46 51 55 60

21 34 37 47 50 56 59 61

35 36 48 49 57 58 62 63

50. 3之韵,形如 3的字可以用 3来组成,其规模由一个正数N来表达。(smu1534)N=0 时,就是 3;

N=1 时是:158

Page 167: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

333 3333 3333N=2 时是:33333 3 333333 3 333333N=3 时是:3333333 3 3 33333333 3 3 33333333请编程输出指定N的图案。51.密码(smu1535)

如果密码被盗,后果会很严重。现在发现安全的密码至少应该满足下面两个条件:

(1).密码长度大于等于 8,且不要超过 16。(2).密码中的字符应该来自下面“字符类别”中四组中的至少三组。这四个字符类别分别为:1.大写字母:A,B,C...Z;

2.小写字母:a,b,c...z;

3.数字:0,1,2...9;

4.特殊符号:~,!,@,#,$,%,^;

给你一个密码,你的任务就是判断它是不是一个安全的密码。如输入:3

a1b2c3d4

Linle@ACM

^~^@^@!%

输出:NO

YES

159

Page 168: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

NO

52.找座位(smu1536)这周六校自律会将在大礼堂举办 20周年晚会,Cdq一行人准备去看演出,但他们想坐一排一起看,

所以他们要找连在一起的座位。假设礼堂里的座位为一个 n行m列的矩阵,而有些座位事先已经有安排人去坐了,这些位置就不能去

坐了。

输入有多组数据,每组数据第一行给出 2 个正整数 n和m,接下来给出 n行m列的字符,字符“E”代表空座位,字符“P”代表该座位已经有人坐,不会出现其他字符。最后一行给出一个正整数 k,表示 Cdq

一行人有多少个。0<n,m,k<20

对于每组输入数据输出一行,若能找到连着的一排座位让他们坐下,则输出“YES”,否则输出“NO”。

样例输入5 4

EPEE

EPPE

EPPE

PEEE

PPPP

3

5 5

EPEEP

EPPEP

EPPEP

PEEEP

PPEEP

4

样例输出YES

NO

53.孪生素数(smu1638)孪生素数是两个素数相差为 2的,比如 3和 5,5和 7 都是孪生素数。编程求 n以内的孪生素数有几对;

输入本题有多组输入数据,你必须处理到 EOF为止,每组数据只有一个 n(n<10000000),代表求 n以内的

孪生素数(包括 n)。输出每组数据输出一行,为孪生素数有几对。样例输入100

样例输出8

54.图书馆座位安排(smu1537)160

Page 169: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Description

图书馆的管理员决定合理安排一下每个学生的自习位置。规则如下:(1)首先将图书馆自习室划分成 N 个不同的区域。(例如文史区,外语区,数学区,哲学区,理工

区等)(2)每个学生对不同的区域有不同的喜好程度(喜好程度度的范围为 1 — 100 的整数, 喜好程度越

大表示该学生越希望被安排到相应的区域学习)(3)由于每个区域可以容纳的学生数量有限,管理员老师希望找到一个最优的调整方案令到总的喜

好程度最大。

Input

第一行包含两个整数 N , M ,( 1<=N , M<=300 )。分别表示 N 个区域和 M 个学生。

第二行是 N 个整数构成的数列 a ,其中 a[i] 表示第 i 个区域可以容纳的学生数, (1<=a[i]<=M , a[1]+a[2]+..+a[N]=M) 。

紧接着是一个 M*N 的矩阵 P , P ( i , j )表示第 i 个学生对第 j 个区域的喜好度。Output

对于每个测试数据,输出可以达到的最大的喜好程度。Sample Input

3 3

1 1 1

100 50 25

100 50 25

100 50 25

Sample Output

175

55.给定一个整数,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(如:输入-380,输出-83)。(smu1639)

56.求逆序对的数。如 2365中有 65一对。(smu1353)57.键盘问题(smu1538)

Description

Jacky深夜正在写一篇论文,键盘左右 Shift 键突然坏了,没地方换键盘,论文有很多地方要切换大小写,但这难不倒 Jacky,他用 Caps Lock来替代。 现在给 Jacky一段文本,请写一个程序来告诉他,他需要敲击多少下键盘才能打出这段文本。

Input

第一行输入一个数字 n (n<1000),表示共有多少行需要处理的文本。从第 2 到第 n+1 行是这 n 行文本。每行文本由英文字母构成,名字的长度不会超过 100 个字符。已知开始时 键盘是输入小写字母的状态。

Output

这个打字员敲击键盘的次数。Sample Input

5

BeiJingDaXueDongMen

AAAaaaBBBbbbABAB

161

Page 170: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

AmericanRAILWAY

AaAaAa

DFjfkdaB

Sample Output

31

21

18

12

11

58.(smu1110)方差是各个数据与平均数之差的平方的平均数,即:

其中, 表示样本的平均数,n表示样本的数量,xi(i=1…n)表示个体,而 s2就表示方差。

方差,通俗点讲,就是和中心偏离的程度!用来衡量一批数据的波动大小(即这批数据偏离平均数的大小)。 在样本容量相同的情况下,方差越大,说明数据的波动越大,越不稳定 。 要求:用一维数组表示 n 个样本,计算时要调用下列求平均数的函数。

double Avage(double a[],int n)

{

     double avage = 0;

     int i;

     for (i=0;i<n;i++)

    avage += a[i];

     avage /= n;

     return avage;

}

59.新杨辉三角(杨辉三角 smu1073)

Description

Jacky今年上大一,他的程序设计老师要求他打印杨辉三角形,但他厌倦了直角形式和等腰形式的杨辉三角,希望 Jacky给他打印出对称的杨辉三角,称之为新杨辉三角。如下图所示,左下角为杨辉三角的直角形式,右上角为左下角的倒置形式。如 5行的形式如下:

1 4 6 4 1

1 1 3 3 1

162

Page 171: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1 2 1 2 1

1 3 3 1 1

1 4 6 4 1

该矩阵由两部分组成,如下所示1

1 1

1 2 1

1 3 3 1

1 4 6 4 1(左下半部分)1 4 6 4 1

1 3 3 1

1 2 1

1 1

1(右上半部分)其特点是对于左下半部分,其两个腰上的数都为 1,其它位置上的每一个数是它上一行相邻两个整数

之和。而右上半部分为左下部分的倒置。

Input

第一行为一个整数 n(1<=n<=15),表示要求的新杨辉矩阵的行数Output

如样例中形式,每两个整数之间留一个空格Sample Input

5

Sample Output

1 4 6 4 1

1 1 3 3 1

1 2 1 2 1

1 3 3 1 1

1 4 6 4 1

60.a+b=100(SMP1048)给定一个大约有 2到 100000 个无序的十进制序列,找出两个数的和为 100的数对。61.由 1,2,……,n组成的一个有序数组就是一个 n 级排列,如 2431是一个 4 级排

列。在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序,一个排列中逆序的总数就称为这个排列的逆序数。如 2431中,21,43,41,31是逆序,2431的逆序数就是 4。对于给定的排列,请编程求逆序数。(1353)

62.正读和反读都相同的字符序列称为“回文”,例如“ abba”和“abcba”是回文,“abcde”和“ababab”则不是回文。编写一个程序判断读入一个以“#”为结束符的字符序列是否是“回文”,是还要统计出现的字母个数。(smu1455)

63.(smu1491)给你两个字符串,判断它们所使用的字符和个数是否一致。例如:

163

Page 172: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

输入:Hello Hell

AABBCCD ABCDABC

58 85

输出:Case 1:不一致Case 2:一致Case 3:一致

164

Page 173: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 7章 间接访问--指针

导学指针能让我们灵活使用存储空间。指针的学习有点抽象,请您先理解指针是地址,理

解指针内存空间的分配,再按规则掌握指针的基本定义及使用方法。做到能动态申请指针变量的空间,用后能释放这些空间;能用指针处理各种变量形式(基本变量、函数中传递的参数、数组变量等)。

7.1 指针

7.1.1 变量的地址对于普通变量,我们可以直接对它进行赋值,或直接取出它的值来使用。普通变量的

地址可以使用“&”获得。用Debug工具查看下列程序运行中变量的地址。【程序清单 7.1】1. #include <stdio.h>

2. int main()

3. {

4. int n=10;

5. char ch='a';

6. double x=6.6;

7. return 0;

8. }

在第 7 行插入断点,执行Debug 调试。在Watch中我们可以查看到这些变量的值和变量所在的地址。如图 7.1 所示。

165

Page 174: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 7.1 变量的值和地址在Watch中我们查得:变量 n的值为 10,地址为 0x0012ff7c;变量 ch的值为‘a’,ASCII的值为 97,地址为 0x0012ff78;变量 x的值为 6.5999999999999996,地址为 0x0012ff70;地址的前两个字符“0x”表示 16进制,后面有 8位 16进制的数。1 个 16进制的数对应

4位,也就是说:每个地址都是用 32位来表达。地址是程序运行时,内部分配的空间,不是固定不变的值。

7.1.2 指针变量的定义现在,我们的问题是如何用变量表达地址。能表达地址的变量是指针变量。指针变量定义的一般形式为:数据类型 *指针变量名表;例如:int *p,*x;//定义 2 个整型的指针变量其中*是一种间接运算子(indirection operator),变量 p 将要存放的是一个 int类型变量的

地址,这个地址里放的数值由*p得到。声明后的指针变量并没有实际的空间,也就是没有166

Page 175: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

真实的地址,要通过引用同类型其它变量的地址空间或自己申请空间得到。看【程序清单 7.2】,理解指针变量是地址,区分*、&的含义。【程序清单 7.2】

1. #include <stdio.h>

2. int main()

3. {

4. int a,*p; // 定义了两个整型变量,p是指针变量5. a = 10;

6. p = &a; // p引用了 a的地址7. printf("%d %p %p %d\n",a ,&a, p,*p); // 分别输出,a的值、a的地址、p的地址(与 a同)

p地址中的值。8. return 0;

9. }

运行的结果为:10 0012FF7C 0012FF7C 10

也可以从调试的窗口看到 a的地址就是 p的值。如图 7.2 所示。

图 7.2 【程序清单 7.2】运行中的变量程序说明:(1)在第 4行中,声明 p为指针变量,a为普通变量;(2) 在第 6行中 p引用了 a的地址。注意,刚声明的指针变量是不占任何一个实际空间,

如果用来存放一个具体的值,一定出错;(3) 在第 7行中*p是指针变量 p 所指的地址中的值;&a是取 a的地址。再看【程序清单 7.3】,观察字符变量 a、*aptr的地址、值、地址空间的大小。【程序清单 7.3】1. #include <stdio.h>

2. int main()

3. {

4. char a,*aptr; // 定义两个 char类型的变量,而 aptr是指针变量167

Page 176: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5. a = 'A'; // 设定变量 a的初始值6. aptr = &a; // aptr指向了变量 a的地址7. printf("%c %p %p %c\n",a ,&a, aptr,*aptr);

8. //依次输出 a的数值、a的地址、aptr 存放的地址、aptr地址中的数值。%p指输出指针,其值这16进制数

9. printf("%d (bytes) %d (bytes)\n",sizeof(a), sizeof(aptr));

10. //依次输出字符变量 a、及指针 aptr占用的内存空间的大小。11. return 0; }

运行的结果为:A 0012FF7C 0012FF7C A

1 <bytes>4<bytes>

可以得出变量 a占用的内存空间是 1 个字节,而指针 aptr占用的内存空间是 4 字节。其实无论是什么类型的指针变量,占用的内存空间都是 4 字节,它只依赖编译器的类型。

请读者对其它类型的变量进行尝试。

7.1.3 指针的动态内存分配上一节中的指针变量都是引用同类型普通变量的地址。指针变量可以在程序执行中动

态地向系统获取所需的内存空间,不用时再释放这些空间。对内存的动态分配由系统提供的库函数来完成,主要有malloc、calloc、free、realloc这 4 个函数,使用时,要加上头文件 “stdlib.h”或“malloc.h”。

1.malloc函数void *malloc(unsigned int size);

其作用是在内存的动态存储区中分配一个长度为 size的连续空间。函数的返回值是所分配区域的开头位置。例如:

int *p;p = (int *)malloc(sizeof(int));

分配一个整型空间,p得到这个空间的地址。2. calloc函数void *calloc(unsigned n,unsigned size);

n是申请空间的数量,size是每个空间的大小。阅读【程序清单 7.4】,观察申请到的存储空间中的赋值情况。【程序清单 7.4】

168

Page 177: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include<stdio.h>

2. #include <stdlib.h>

3. int main()

4. {

5. double *p;

6. p = calloc(3,sizeof(double)); // 申请 3 个 double类型的空间,p是首地址7. *p = 2.4;//将 2.4 放入首地址中8. *(p+1) = 5.6;//将 5.6 放入第 2 个地址中9. *(p+2) = 7.8;//将 7.8 放入第 3 个地址中10. printf("%lf %lf %lf\n",*p,*(p+1),*(p+2));

11. free(p);

12. return 0;

13. }

运行结果为:2.400000 5.600000 7.800000

第 5行 p是 double类型的指针变量;第 6行申请了 3 个连续的 double类型的空间;第7~10行,对指针变量赋值;第 10行输出它们的值。第 8、9行中 p+1、p+2是指针与整数相加,其结果是还是指针, p+1指的地址是

p+1*sizeof(double),p+2指的地址是 p+2*sizeof(double),1 个 double类型的变量占 8

个字节。如图 7.3 所示。

图 7.3 p、p+1、p+2的地址3.free函数void free(void *p);

如:free(p); //释放已经申请的指针变量空间。指针变量空间一旦申请就永远占用。因此,不用的指针变量空间一定要加以释放。4.realloc函数void *realloc(void *p,unsigned int size);

如果已经通过 malloc函数或 calloc函数获得了动态空间,想改变其大小,可以用 recalloc

169

Page 178: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

函数重新分配。如:realloc(p,30);

将 p指向的动态空间的大小改变为 30 字节。

7.1.4 指针的应用【例 7.1】求 n 个整数的和,这 n 个数要求放在申请的动态内存空间内。【程序清单 7.5】1. #include <stdio.h>

2. #include <stdlib.h>

3. int main(void)

4. {

5. int *total; // 定义一指针变量 total 存放输入的数6. int i, n, sum=0; // n为输入整数的个数,变量 sum储存总和结果7. printf("输入要求和的整数个数: "); // 程序提示字符串8. scanf("%d",&n); //读取输入参数并存至变量 n

9. total = (int*)malloc(sizeof(int)*n); // 配置给指针变量 total有 n 个 int数据型态的内存空间,也就是 4n(bytes)大小的内存。

10. for(i=0;i<n;i++)

11. {

12. printf("第 %d 个数值:",i+1); // 输入第 i 个数值的提示字符串13. scanf("%d",(total+i)); // 读取输入值,依序存至指针变量 total中14. sum += *(total+i); // 依序将使用者输入加总到变量 sum

15. }

16. printf("总和等于 %d\n",sum); // 显示程序计算之加总结果17. free(total); // 释放已配置的内存空间18. return 0;

19. }

运行过程为:输入要求和的整数个数: 5

第 1 个数值:60第 2 个数值:70第 3 个数值:80第 4 个数值:60第 5 个数值:90总和等于 360在第 9行申请了 n 个 sizeof(int)大小的空间,在第 10~15行循环使用这 n 个空间。n=5 时

total的空间布局如图 7.4 所示。170

Page 179: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 7.4 指针变量的内存空间指针在一维数组的最常见的应用就是利用指针表示字符串,见【程序清单 7.5】。【程序清单 7.6】1. #include <stdio.h>

2. #include <stdlib.h> // 为了指针申请空间3. #include <string.h> // 为了字符串的使用4. int main(void)

5. {

6. char *str1="This is string1…"; // 定义指针变量 str1,并设定其初始字符串内容7. char *str2=(char *)malloc(sizeof(char)*(strlen(str1)+1)); //定义指针变量 str2,并配置其内存大小

等同于 str1的初始字符串内容大小8. printf("str1的内容: %s\n",str1); // 显示字符串 str1的内容9. printf("str2的内容: %s\n",str2); // 显示字符串 str2的内容10. strcpy(str2,str1);//字符串复制11. printf("利用字符串复制指令后:\n");

12. printf("str1的内容: %s\n",str1); // 显示复制后字符串 str1的内容13. printf("str2的内容: %s\n",str2); // 显示复制后字符串 str2的内容14. return 0;

15. }

运行结果是:str1的内容: This is string1…str2的内容: 屯屯屯屯屯屯屯屯屯 葺葺葺葺葺 ?利用字符串复制指令后:str1的内容: This is string1…str2的内容: This is string1…程序说明:

(1)第 9行与第 13行分别输出 str2 赋值前和赋值后的内容,str2在复制前是乱码;(2)第 10行中,strcpy(str2,str1)函数实现两地址中内容的复制。注意:数组变量在定义的同时就必须指定一特定大小容量,而指针变量的动态配置是

在在申请空间时才决定变量内存大小,读者在实际操作时去仔细体会。

171

Page 180: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

7.2 指针与数组间的关系数组在内存中表示由编译器配置的一段连续空间,数组名就是数组的首地址。由于指

针申请的也是一段连续空间,因此数组的应用一般都能够利用指针达成。【程序清单 7.7】中显示如何利用指针变量来定义一维数组及二维数组,其中 aptr及 bptr皆为指针变量,并分别指向一维数组 a及二维数组 b的首地址,尽管数组变量与指针变量的不同,程序也能利用指针变量找到数组特定地址,获得特定的数值。

【程序清单 7.7】1. #include <stdio.h>

2. int main()

3. {

4. int *aptr,a[4]={3,6,9,9}; //定义指针变量 aptr及一维数组变量 a,并设定 a的初始值5. int *bptr, b[3][3] = {{1, 1, 1},{2, 2, 2},{3, 3, 3}}; //定义指针变量 bptr及二维数组变量 b,并设

定 b的初始值6. int i,j;

7. aptr = &a[0]; // 设定 aptr指向一维数组 a的首地址8. bptr = &b[0][0]; // 设定 bptr指向二维数组 b的首地址9.

10. for (i=0;i<4;i++)

11. printf ("%d ",*(aptr+i)); // 显示 aptr的地址中的数值12. printf("\n\n");

13. for (i=0;i<3;i++)

14. {

15. for(j=0;j<3;j++)

16. printf ("%d ",*(bptr+i*3+j)); // 显示 bptr的地址中的数值17. printf("\n");

18. }

19. return 0;

20. }

运行的结果为:

3 6 9 9

1 1 12 2 23 3 3程序说明:(1) 第 11行通过指针变量 aptr访问一维数组 a[];(2) 第 16行通过指针变量 bptr访问二维数组 b[][],由于数组 b 每行有 3 个量,前 i

172

Page 181: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

行就有 i*3 个空间,到第 i行的第 j列的地址就是 bptr+i*3+j。事实上可以把数组名当指针用。【程序清单 7.7】可以改成:【程序清单 7.8】1. #include <stdio.h>

2. int main()

3. {

4. int a[4]={3,6,9,9};//定义指针变量 aptr及一维数组变量 a,并设定 a的初始值5. int b[3][3] = {{1, 1, 1},{2, 2, 2},{3, 3, 3}}; // 定义指针变量 bptr及二维数组变量 b,并设定 b

的初始值6. int i,j;

7. for (i=0;i<4;i++)

8. printf ("%d ",*(a+i)); // 第 i 个元素的地址是 a+i

9. printf("\n\n");

10. for (i=0;i<3;i++)

11. {

12. for(j=0;j<3;j++)

13. printf ("%d ",*(b[i]+j)); // b[i]是第 i行的首地址,第 i行,第 j列的地址就是 b[i]+j)

14. printf("\n");

15. }

16. return 0;

17. }

程序第 8行中的*(a+i),通过首地址 a加上 i来访问数组 a中的所有元素。程序第 13行中的*(b[i]+j)),通过数组每行的首地址 b[i]加上 j来访问数组 b中的所有元

素。数组 a的首地址是 a;数组 b 三行的首地址分别是:b[0]、b[1]、b[2]。如图 7.5 所示:

图 7.5 数组的地址空间对于三维以上的数组,定义与使用方法类似,请读者自己尝试。

173

Page 182: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

7.3 指针变量作为函数参数指针变量与一般变量一样可以当作函数中的参数进行传递,但两种形式的变量在储存

数据及函数间传递的效果大不相同。 因此,参数传递的方式大致可分为:传值(Call By

Value)及传址(Call By Address)传递。传值也就是把函数外部实参的值传给函数中的形参,其数值会储存在不同的内存地址中;而指针变量以储存的数据为地址,在参数传递的过程中,传递参数的变量会以地址作为传递的对象,其形式是在一般变量前加上地址运算符&,这时形参和实参是在同一地址中,也就是说函数内指针变量的值发生改变,函数外对应的变量值也一样改变。【程序清单 7.9】中以交换函数范例来说明一般变量与指针变量作为函数参数传递的差异。

【程序清单 7.9】1. #include <stdio.h>

2. void swap1(int,int); // 将两个一般变量交换的函数3. void swap2(int*,int*); // 将两个指针变量交换的函数4. int main(void)

5. {

6. int a=10,b=20; // 先设定两个变量 a及 b的初始值7. printf("主程序main()中...\n"); // 显示主程序中两个变量的信息8. printf("交换前 a=%d,b=%d\n",a,b); // 显示交换前的变量值9. printf("变量 a 的地址为 %p\n",&a); // 显示变量 a 存放的地址10. printf("变量 b 的地址为 %p\n",&b); // 显示变量 b 存放的地址11. swap1(a,b); //通过传值调用函数12. printf("交换后 a=%d,b=%d\n",a,b); // 显示交换后的变量值13. printf("变量 a 的地址为 %p\n",&a); // 显示变量 a 存放的地址14. printf("变量 b 的地址为 %p\n",&b); // 显示变量 b 存放的地址15. a=10,b=20; // 重新设定两个变量 a及 b的数值16. printf("主程序main()中...\n"); // 显示主程序中两个变量的信息17. printf("交换前 a=%d,b=%d\n",a,b); // 显示交换前的变量值18. printf("变量 a 的地址为 %p\n",&a); // 显示变量 a 存放的地址19. printf("变量 b 的地址为 %p\n",&b); // 显示变量 b 存放的地址20. swap2(&a,&b); //通过传址调用函数21. printf("交换后 a=%d,b=%d\n",a,b); // 显示交换后的变量值22. printf("变量 a 的地址为 %p\n",&a); // 显示变量 a 存放的地址23. printf("变量 b 的地址为 %p\n",&b); // 显示变量 b 存放的地址24. return 0;

25. }

26. void swap1(int a,int b)//形参是一般变量174

Page 183: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

27. {

28. int temp;

29. temp = a;

30. a = b;

31. b = temp;

32. printf("子函数 swap1()中...\n"); // 显示子函数 swap1中变量的信息33. printf("交换中 a=%d,b=%d\n",a,b); // 显示交换时的变量值34. printf("变量 a 的地址为 %p\n",&a); // 显示交换时 a的地址35. printf("变量 b 的地址为 %p\n",&b); // 显示交换时 b的地址36. }

37. void swap2(int *a,int *b) // 形参是指针变量38. {

39. int temp;

40. temp = *a;

41. *a = *b;

42. *b = temp;

43. printf("子函数 swap2()中...\n"); // 显示子函数 swap2中变量的信息44. printf("交换中 a=%d,b=%d\n",*a,*b); // 显示交换时的变量值45. printf("指针 a 所指的地址为 %p\n",a); // 显示交换时 a的地址46. printf("指针 b 所指的地址为 %p\n",b); // 显示交换时 b的地址47. }

运行的结果为:主程序main()中...

交换前 a=10,b=20

变量 a 的地址为 0012FF7C

变量 b 的地址为 0012FF78

子函数 swap1()中...

交换中 a=20,b=10

变量 a 的地址为 0012FF24

变量 b 的地址为 0012FF28

交换后 a=10,b=20

变量 a 的地址为 0012FF7C

变量 b 的地址为 0012FF78

主程序main()中...

交换前 a=10,b=20

变量 a 的地址为 0012FF7C

变量 b 的地址为 0012FF78

子函数 swap2()中...

交换中 a=20,b=10

指针 a 所指的地址为 0012FF7C

指针 b 所指的地址为 0012FF78

交换后 a=20,b=10

变量 a 的地址为 0012FF7C

175

Page 184: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

变量 b 的地址为 0012FF78

【程序清单 7.9】中利用简单的交换函数说明了一般变量及指针变量在函数间传递的变量数值及存放地址的差异:在子函数 swap1()中使用了传值方式的传递,在传递期间主函数与子函数中变量所存放的地址不同。而子函数 swap2()则使用了传址方式的传递,即利用指针变量进行传递参数,从执行结果中就可以看出:变量在传递前后,在主函数或子函数中的地址都无变化。

如果希望函数要改变传参变量的值,就要将传参变量设为指针类型。如果要函数返回多个变量值,而又不想用传参,就要将这些变量设为全局变量。

7.4 函数值为指针类型每个非 void类型的函数都要确定返回值的类型,一个函数的返回值的类型也可以是指

针。它的一般形式为:类型名 *函数名(参数表列);这时,函数内的返回值必须是地址,调用时在函数名前加上*即可。【例 7.2】从键盘输入若干个字符串,然后统计数字的个数。【程序清单 7.10】1. #include <stdio.h>

2. #include <string.h>

3. #include <ctype.h>

4. int *num(char a[]) // 统计字符串 a中数字的个数5. {

6. int i,n=0,len = strlen(a);

7. for (i=0;i<len;i++)

8. if(isdigit(a[i])) n++;

9. return &n; // 返回 n的地址10. }

11. int main()

12. {

13. char a[20];

14. int n;

15. while(scanf("%s",a)!=EOF)

16. {

17. n = *num(a); // 调用返回值是指针类型的函数18. printf("%d\n",n);

176

Page 185: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

19. }

20. return 0;

21. }

运行结果为:12345↙5

Hello↙0

a1a2a3a4↙4

7.5 指针数组指针数组是指数组变量作为指针的形式,也就是定义的数组中每一个元素都可视为一

个指针。例如:

int *ptr[5];

表示定义了一个具有 5 个整数型态大小的数组变量 ptr,且这五个变量皆属于指针变量。【例 7.3】请输入若干个字符串,以 q 结束,然后按字典序输出它们。分析:我们将利用冒泡排序法 (bubble sorting) 将输入的字符串以字典序排序,其中常数

LENGTH定义为二维字符串数组的数目及大小,另外定义的指针数组变量 sptr作为临时交换的空间。

【程序清单 7.11】1. #include <stdio.h>

2. #include <string.h>

3. #define LENGTH 50

4. int main(void)

5. {

6. int i,j,k;

7. char s[LENGTH][ LENGTH]; // 定义二维数组 s来储存输入字符串8. char *sptr[LENGTH]; // 定义一指针数组,变量 sptr作为排序中的处理媒介9. char *p; / 定义指针变量 p作为排序中交换的暂存变量10. printf("输入欲排序的字符串, 结束时输入 \"q\" \n"); // 提示字符串11. for (i=0;i< LENGTH;i++)

12. {

13. printf("%d:",i+1); // 输入第 i 个字符串的提示字符串

177

Page 186: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

14. gets(s[i]); //由键盘读取输入的字符串,并依序存至数组 s中15. if (strcmp(s[i],"q")==0) // 确认使用者是否输入完毕16. break;

17. sptr[i] = s[i]; // 将数组转存为指针18. }

19. for (j=0; j<i-1; j++) // 冒泡排序法之实现20. for (k=j+1; k<i; k++)

21. if (strcmp(sptr[j],sptr[k]) >0)

22. {

23. p = sptr[k];

24. sptr[k] = sptr[j];

25. sptr[j] = p;

26. }

27. for (j=0; j<i; j++) //最后输出排序后的结果28. printf("%d: %s\n",j+1, sptr[j]);

29. return 0;

30. }

运行过程为:输入欲排序的字符串, 结束时输入 "q"

1:hello↙2:who↙3:12345↙4:1a2a3a↙5:vvvv↙6:q↙1: 12345

2: 1a2a3a

3: hello

4: vvvv

5: who

程序中用 char *p定义了指针变量 p,用于存储一个字符串。在第 21~26行中就是用这个空间来交换 sptr[k]与 sptr[j]的值。对指针变量可以直接用赋值语句传递地址的值,而对于一个字符串拷贝到另一个字符

串,必须使用 strcpy()函数。

7.6 双重指针指针储存的内容为变量的地址,而指针变量本身也有自己的地址,因此双重指针的定

义即为一个被定义为指向另一个指针的指针变量。就双重指针储存的内容:第一重指针储178

Page 187: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

存变量的地址,第二重指针则指向了存放变量地址的地址。在【程序清单 7.12】中,用双重指针替代二维数组的使用。

【程序清单 7.12】1. #include <stdio.h>

2. int main()

3. {

4. int a[3][4] = {{1,1,1,1},{2,2,2,2},{3,3,3,3}};

5. int **p=a; // 定义双重指针 p,并引用了二维数组的首地址6. int i,j;

7. for(i=0;i<3;i++)

8. {

9. for(j=0;j<4;j++)

10. printf("%d ",*((p+i*4)+j)); // 用指针 p访问数组11. printf("\n");

12. }

13. return 0;

14. }

运行结果为:1 1 1 12 2 2 23 3 3 3第 5行 int **p=a 执行后,p是数组 a的首地址,p+0、p+4、p+4*2分别是数组 a 三行的首

地址相当于 a[0]、a[1]、a[2]。如图 7.6 所示。

图 7.6 双重指针与二维数组 注意:p必须指在 a数组的空间中才有意义,否则程序会出错。也就是第 10 行中((p+i*4)+j))计算后的地址要在二维数组 a的地址中。双重指针在 C语言中的使用方式有以下两项说明:(1)双重指针的定义和初始值设定方式双重指针的定义方式为:数据类型 **指针变量; 其中**即为双重指针所使用的双重取

址运算子,代表储存的地址内之数值,而指针变量则指向了存放变量地址的地址。如【程序清单 7.12】中的双重指针变量 p 所示。(2)双重指针的动态内存配置

179

Page 188: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

如同单重指针变量,双重指针的使用一般在实际应用中也需要动态内存配置。【程序清单 7.13】中的 ptr1、ptr2是在程序执行时引用同类型普通变量的地址空间。

【程序清单 7.13】1. #include <stdio.h>

2. int main(void)

3. {

4. int a=5, i, j; // 定义程序中会使用到的变量5. int *ptr1, **ptr2; // 定义指针变量 ptr1和双重指针变量 ptr2

6. char temp[10], **ptr; // 定义字符串变量 temp和双重指针变量 ptr来存放字符串7. char str1[]="ABC"; // 定义字符串 str1,并设定初始值为ABC

8. char str2[]="IJK"; // 定义字符串 str2,并设定初始值为 IJK

9. char str3[]="XYZ"; // 定义字符串 str3,并设定初始值为XYZ

10. ptr1 = &a; // 将变量 a的地址指派给指针变量 ptr1

11. ptr2 = &ptr1; // 将指针变量 ptr1的地址指派给双重指针变量 ptr2

12. printf("*ptr1 = %d ptr1 = %p\n",*ptr1,ptr1); // 显示指针变量 ptr1的数值及地址13. printf("**ptr2= %d *ptr2 = %p ptr2 = %p\n", **ptr2,*ptr2,ptr2); // 显示双重指针变量 ptr2的数值,

第一重及第二重指针的地址。14. ptr=temp; // 将暂存指针指派给双重指针变量 ptr

15. *(ptr+0) = str1; // 设定 ptr第一个存放的地址指向指针变量 str1的地址16. *(ptr+1) = str2; // 设定 ptr第二个存放的地址指向指针变量 str2的地址17. *(ptr+2) = str3; // 设定 ptr第三个存放的地址指向指针变量 str3的地址18. printf("\n ptr 的地址 = %p\n", ptr); // 显示双重指针 ptr的地址19. for (i=0;i<3;i++) // 利用循环依序显示 ptr第 1~3 个存放地址所指向的地址及内容20. {

21. printf("\n *(ptr+%d) 所存的地址 = %p\n",i,*(ptr+i));

22. printf("*(ptr+%d) 指向字符串 %s\n",i,*(ptr+i));

23. for (j=0; *(*(ptr+i)+j) != '\0';j++)

24. printf("*(*(ptr+%d)+%d)=%c \n",i,j,*(*(ptr+i)+j));

25. }

26. return 0;

27. }

运行结果为:*ptr1 = 5 ptr1 = 0012FF7C

**ptr2= 5 *ptr2 = 0012FF7C ptr2 = 0012FF70

ptr 的地址 = 0012FF60

*(ptr+0) 所存的地址 = 0012FF58

*(ptr+0) 指向字符串 ABC

*(*(ptr+0)+0)=A

*(*(ptr+0)+1)=B

*(*(ptr+0)+2)=C

180

Page 189: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

*(ptr+1) 所存的地址 = 0012FF54

*(ptr+1) 指向字符串 IJK

*(*(ptr+1)+0)=I

*(*(ptr+1)+1)=J

*(*(ptr+1)+2)=K

*(ptr+2) 所存的地址 = 0012FF50

*(ptr+2) 指向字符串 XYZ

*(*(ptr+2)+0)=X

*(*(ptr+2)+1)=Y

*(*(ptr+2)+2)=Z

程序说明:(1)第 10行 ptr1=&a是让 ptr1指向变量 a的地址;(2)第 11行 ptr2=&ptr1后,ptr2是 ptr1的地址,也就是 a地址的地址;(3)对于第 6行 char temp[10]后 temp是一维数组的首地址,而在第 14行 ptr=temp后,

ptr与 temp 都是一维数组的首地址。在 15~17中,*(ptr+0)、*(ptr+1)、*(ptr+2)就可以分别代表字符数组的首地址 str1、str2、str3。在【程序清单 7.14】中,双重指针 str是通过malloc()函数申请得到使用空间。【程序清单 7.14】1. #include <stdio.h>

2. #include <stdlib.h>

3. #include <string.h>

4. #define TOTAL 50 // 预先定义需输入字符串总数的最大值5. #define LENGTH 20 // 预先定义每个输入字符串的最大长度6. int main(void)

7. {

8. int i,j;

9. char **str=(char **)malloc(TOTAL * sizeof(char*)); // 动态配置双重指针变量 str的内存空间(先配置其列空间,也就是预输入字符串总数)

10. for(i=0;i<TOTAL;i++) // 利用循环动态配置每一字符串所需输入的最大长度内存空间11. *(str+i) = (char *)malloc(LENGTH * sizeof(char)); // 为每一个字符串申请空间12. printf("输入每一个字符串内容:(输入 end 代表结束)\n"); // 提示输入字符串13. for(i=0;i<TOTAL;i++)

14. {

15. scanf("%s",*(str+i)); // 从键盘依序读取每一个预输入的字符串16. if(strcmp(*(str+i),"end")==0) // 若在输入第 i+1 个字符串时(在预定义输入字符串总数最大值

TOTAL之内)即输入 end来结束输入,则跳出循环停止输入程序17. break;

18. }

181

Page 190: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

19. printf("\n输出为:\n"); // 输出提示字符串20. for(j=0;j<i;j++)

21. printf("%d %s\n",j+1,*(str+j)); // 依序输出使用者输入的字符串内容22. free(str); // 释放已取得的双重指针变量 str内存空间23. return 0;

24. }

运行过程为:输入每一个字符串内容:(输入 end 代表结束)hello↙welcome↙2013↙acm↙1a2b3c↙end↙

输出为:

1 hello

2 welcome

3 2013

4 acm

5 1a2b3c

在程序中的第 9行,双重指针 str申请动态空间。注意申请的空间使用后要通过 free()进行空间释放,见第 22行。

7.7案例及分析【例 7.4】两个大数相加。(smp1006)分析:当两数的范围超过-231~(231-1)时,计算机无法相加。我们可以申请两个足够的空间

p 、q来保存这两个大数,再对这两个大数从低位到高位按位相加,并把结果存入最长的那个数字串中。相加时可能最高位要进行进位,因此在两数的后面补 0增加一位。66+9999的过程如图 7.7 所示:

182

Page 191: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 7.7 按位相加过程示意图说明:把左边灰色区域的格子内的数字相加,填入右边灰色区域的格子内。【程序清单 7.15】1. #include <stdio.h>

2. #include <stdlib.h>

3. #include <string.h>

4. #define MAX 202

5. char *add(char *p,char *q)

6. {

7. int len_p,len_q,t,i,j;

8. len_p = strlen(p);

9. len_q = strlen(q);

10. *(p+len_p)='0'; *(p+len_p+1)='\0'; // 多补一位 0保证相加进位时位数足够11. *(q+len_q)='0'; *(q+len_q+1)='\0';

12. if(len_p<=len_q)

13. {

14. for(i=len_p,j=len_q;i>0;i--,j--)

15. {

16. t = *(p+i-1)+*(q+j-1)+*(q+j)-'0'-'0'-'0'; // p、q同位及原进位的相加17. *(q+j) = t%10+'0'; // 放和的个位18. *(q+j-1) = (t-t%10)/10+'0'; // 放进位19. }

20. while(j>0)//处理 q 比 p多出的位21. {

22. t = *(q+j-1)+*(q+j)-'0'-'0';

23. *(q+j) = t%10+'0';

183

Page 192: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

24. *(q+j-1) = (t-t%10)/10+'0';

25. j--;

26. }

27. return q;

28. }

29. else

30. {

31. for(i=len_q,j=len_p;i>0;i--,j--)

32. {

33. t = *(p+j-1)+*(q+i-1)+*(p+j)-'0'-'0'-'0';

34. *(p+j) = t%10+'0';

35. *(p+j-1) = (t-t%10)/10+'0';

36. }

37. while(j>0)

38. {

39. t = *(p+j-1)+*(p+j)-'0'-'0';

40. *(p+j) = t%10+'0';

41. *(p+j-1) = (t-t%10)/10+'0';

42. j--;

43. }

44. return p;

45. }

46. }

47.

48. int main()

49. {

50. char *p,*q,*r;

51. int i,k;

52. p = (char *)calloc(MAX,sizeof(char));

53. q = (char *)calloc(MAX,sizeof(char));

54. r = (char *)calloc(MAX,sizeof(char));

55. while(scanf("%s%s",p,q)!=EOF)

56. {

57. r = add(p,q);

58. if(*(r)=='0')

59. k=1;

60. else

61. k=0;

62. for(i=k;i<strlen(r);i++) //跳过首字符为 0的字符63. printf("%c",*(r+i));

64. printf("\n");

65. }

66. }

运行过程为:184

Page 193: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

222222222222222222222212345678 22222222211111111111111↙222222244444444433333323456789

333333333333333456677888888888888 12345678901234567890123456789↙333345679012234691245779012345677

注:第 58~64行利用 r是指针的特点,可以改成:if(*(r)=='0')

printf("%s\n",r+1); //从第 2 个字符开始输出else

printf("%s\n",r); //从头开始输出

7.8 进阶指针的使用虽然在开始学习中接触的机会比较少,但是在实际业界的应用中,指针的

使用却是相当普遍。指针不仅有前面的使用,还有函数指针的使用。如果在程序中定义了一个函数,在编译时,编译系统会为函数代码分配一段存储空间,

这段空间的入口地址就是函数指针。也就是说函数名就是函数的入口地址。可以定义一个指向函数的指针变量,用来存放某一函数的起始地址。如对于函数 int f(int,char);

可以这样定义一个函数指针 p:

int (*p)(int x,char c);//只在函数名处改成指针变量,而函数要传的参数要保留使用时将参数传入就可得到函数的值。如果 x=5,c=’m’,则(*p)(5,’M’)就是函数值。【任务 7.1】王小二切饼(用函数指针完成)(smp1134)

Description

王小二自夸刀工不错,有人放一张大的煎饼在砧板上,问他:“饼不许离开砧板,切 100刀最多能分成多少块?”如图 7.4 所示:

图 7.8 王小二切饼示意图你的任务是编程解决切 n刀时,饼至多能被分成多少块。

Input

185

Page 194: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

每行一个案例,输入一个正整数 n表示要切的刀数。

对应输出饼被切成的最大块数。

Sample Input

Ouput

1

3

4

Sample Output

2

7

11

分析:

切一刀是分成两块;切第 2刀就与前面的一条直线相交,多出 2 块来;切第 3刀与前面的 2条直线相交,就可以将前面的 3 块分开,这样就多 3 块,由此下去,可以得出规律:切第 n刀就会多出 n 块。用 fun(n)表示切 n刀得到的块数,则:

【程序清单 7.16】1. #include<stdio.h>

2. int fun(int n){

3. if(n==0) return 1;

4. else return fun(n-1)+n;

5. }

6. int main(){

7. int n,f,(*p)(int x); // 定义函数指针8. while(scanf("%d",&n)!=EOF){

9. p=fun;

10. f=(*p)(n); // 通过函数指针调用函数值11. printf("%d\n",f);

12. }

13. return 0;

14. }

运行过程为:1↙22↙43↙7

186

Page 195: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5↙16100↙5051

187

Page 196: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题1.有 n 个学生,每个学生有m科成绩。要求在用户输入学生序号以后,能输出该学生

的全部成绩。用指针函数实现。(smu1190)2.有 n 个学生,每个学生有m科成绩。要求查找并输出有不及格课程的学生的成绩。

用指针函数实现。(smu1191)3.用指针传参方法编程:如果 n为圆心角的度数,R为圆的半径,给定 n,R计算扇形

的面积。PI取 3.1415926。(smu1303)4.将数组中的 n 个元素按相反顺序存放。(smu1318)5.给你一个 m×n的矩阵,矩阵的元素是整数,请你统计出有多少个数是 6的倍数。

(1332)6.输入一学生楼中每个宿舍中爱打篮球、羽毛球的人数,请你编程分别统计:这幢楼

爱打篮球、羽毛球的人数。这些楼中的宿舍数据按方阵排列(smu1338)7.一个 m*n(平方公里)的地方,每一平方(1*1)的地方测得一个平均海拨高度,

找出山峰头有几个,即比周围八个点高的点有几个,m*n平方公里以外的区域认为海拔高度为 0。(smu1346)

8.一个 n*n 的矩阵,如果主对角线以下的元 素全为 0,就是上三角阵。如

就是上三角阵,请你编程判断所给的矩阵是否是上三角形矩阵。(smu1348)

9.请你用递归方法编程求N 个数的最大数。(smu1349)递归思路:求 N 个数的最大数,可以看成是前 N-1 个数的最大值与第 N 个数,这两个

数的最大值。也就是如果用 Fmax(N)表示 N 个数的最大数,则有Fmax(N)= max{Fmax(N-1),第N 个数},Fmax(2)=max{第一个数,第 2 个数}。10.有一个班有 n 个学生,各学 5门课,请你统计他们的平均分,并按平均分从高到

低进行排名。(smu1350)输入如表 7.1。

表 7.1 统计前的学生成绩表188

Page 197: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

89 90 99 87.5 89

100 100 100 100 100

62 50.5 67 59 52.5

输出如表 7.2:表 7.2 统计后的学生成绩表

2 100 100 100 100 100 100.0

1 89 90 99 87.5 89 90.9

3 62 50.5 67 59 52.5 58.2

11.现在常用的硬币有 1 角、5角、1 元。要找 K角钱,至少需要多少枚硬币,请编程求出结果。(smu1355)

12.用位运算和循环表达 0~63的二进制数(smu1359).。输出的结果为:

000000000001000010000011000100……11111011111113.有任意多个包,每个包的容量都为 1,现在有 n件物品,每件物品的重量都小于

1。请编程统计,至少要用多少个包才可以把这些物品装下。例如,给定 5件物品,重量分别是 0.2、0.8、0.3、0.5、0.4,至少要用 3 个包才可以装下。(smp1303)

14.(smu1382)一个整数在计算机里是表示成一串二进制位的,根据机器的不同占的字节数也有所不同。请编写一个函数move(value,n)将整数 value 左移或右移|n|位。当 n>0

时右移,当 n<0 时左移。如:

对于 value = 8;n = 2;move(value,n)就是将 8 右移 2位,得到 2.即:00000000 00001000(8)右移 2

位:00000000 00000010(2).

对于 value = 8;n = -2;move(value,n)就是将 8 左移 2位,得到 32.即:00000000 00001000(8)左移2位:00000000 00100000(32).

15. Ackerman函数的定义如下:(smu1448)

189

Page 198: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

请你分别用递归和非递归两种方法实现。

16.某公司想用电报传输公司文件,但又担心被人窃听,盗走公司商业秘密。于是该公司决定将要传输的文件进行加密。其加密规则如下:(smu1467)若文件中的字符是数字 0~9,则不予加密,保持原样不变;若是字符 A~Z,则用其后的一个字符代替,即:A用 B代替,B用 C代替,……,Z 则用A代替。a用 b代替,b用 c代替,……,z用 a代替。现在给你公司文件的原文,请你编程将该文件按以上加密算法进行加密并输出。

17.请输出如下所示的图形:(smu1468)***** ***  *

18.自然对数的底 e是一个无理数。一般谈及 e,使用数值 2.718。通常使用下面的公式求 e的近似值:

e=1+1/1!+1/2!+1/3!+……。即:

请编程求 e的近似值。 (smu1469)19.由数轴上的两点间的一切实数所组成的集合叫做区间,其中,这两个点叫做区间

端点。不含端点的区间叫做开区间,含有两个端点的区间叫做闭区间。而两个区间端点之差的绝对值称为这个区间的长度。(smu1472) 现在给定一组区间的两个端点值 a和 b,要求出这些区间中长度最大的区间,输出这个区间。输出格式为: 长度最大的区间是[区间的左端点 a,区间的右端点 b]。

20.中国体育彩票福建省 36 选 7(以下简称福建省 36 选 7)由国家体育总局体育彩票190

Page 199: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

管理中心发行和组织销售,福建省体育彩票管理中心在所辖区域内销售。福建省 36 选 7是指从 01-36共 36 个号码中选取 7 个号码进行投注,一组 7 个号码的组合称为一注。请你统计最近 n期开奖号码中每个号码出现的次数。(smu1473)当输入为:10

11 26 17 19 20 29 25

17 11 35 36 05 12 31

19 05 03 30 13 24 33

35 25 05 07 03 24 30

18 13 20 17 34 01 27

05 22 16 10 24 08 23

02 09 03 36 34 16 04

01 17 33 29 04 15 26

36 02 09 12 34 05 04

29 26 15 06 16 07 17

输出:2,2,3,3,5,1,2,1,2,1,2,2,2,0,2,3,5,1,2,2,0,1,1,3,2,3,1,0,3,2,1,0,2,3,2,3

21.在M*N的矩阵中,每个元素都是整数。请你编程统计能被 3整除的数的个数,并把这些数都用 3替代。 (smu1475)

22.三角形可以分成锐角三角形(三个角都是锐角)、直角三角形(有一个角是直角)、钝角三角形(有一个角是钝角)。给你空间三角形的三个顶点坐标,请编程判断三角形的形状。 (smu1476)

23.规定只有出现大小写字母的是单词,给出若干个字符串,请编程统计单词的数量。注意,句后的标点符号已去掉。(smu1480)

24.打印形如‘7’的图形。输入不同的 n,输出图形的比例大小不同。例如:当 n=3 时输出的图形为:(smu1481)

**** * **25.给出一个 m*n的矩阵,请编程统计正数和负数的个数,并把正数输出为‘+’,负

数输出为‘-’。 (smu1484)26.给出一串数,约 4~100 个。请找出第二大和倒数第二大的数,按从小到大输出。

(smu1485)27.子网掩码

191

Page 200: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

子网掩码是用来判断任意两台计算机的 IP地址是否属于同一子网络的根据。最为简单的理解就是两台计算机各自的 IP地址与子网掩码进行 AND 运算后,如果得出的结果是相同的,则说明这两台计算机是处于同一个子网络上的,可以进行直接的通讯。就这么简单。

请看以下示例:运算演示之一:aa

I P 地址  192.168.0.1

子网掩码  255.255.255.0

AND 运算转化为二进制进行运算:

I P 地址 11010000.10101000.00000000.00000001

子网掩码 11111111.11111111.11111111.00000000

AND 运算     11010000.10101000.00000000.00000000

转化为十进制后为:      192.168.0.0

运算演示之二:

I P 地址  192.168.0.254

子网掩码  255.255.255.0

AND 运算转化为二进制进行运算:

I P 地址 11010000.10101000.00000000.11111110

子网掩码 11111111.11111111.11111111.00000000

AND 运算     11010000.10101000.00000000.00000000

转化为十进制后为:      192.168.0.0

运算演示之三:

I P 地址  192.168.0.4

子网掩码  255.255.255.0

AND 运算转化为二进制进行运算:

I P 地址 11010000.10101000.00000000.00000100

子网掩码 11111111.11111111.11111111.00000000

AND 运算     11010000.10101000.00000000.00000000

转化为十进制后为:      192.168.0.0

通过以上对三组计算机 IP地址与子网掩码的 AND 运算后,可以看到它运算结果是一样的。均为192.168.0.0

  所以计算机就会把这三台计算机视为是同一子网络。

输入第一行是本机 IP地址第二行是子网掩码第三行整数N,表示后面有N 个 IP地址

192

Page 201: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 1 个 IP地址......

第N 个 IP地址输出计算并输出N 个 IP地址是否与本机在同一子网内。对于在同一子网的输出"INNER"

对于在不同子网的输出“OUTER”

样例输入192.168.0.1

255.255.255.0

3

192.168.0.2

192.168.0.254

192.168.1.2

样例输出INNER

INNER

OUTER

193

Page 202: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 8章 数据的组织与处理--结构体、共用体、

枚举与链表

导学本章要求是将多种类型的数据封装成结构体;处理较复杂的数据结构问题;初步掌握

链表的建立,链表结点的插入与删除;掌握 enum语句,能用枚举法解决一些实际问题;能综合调试程序。

8.1用 typedef声明的的类型名typedef指定新的类型名来代替已有的类型名,一般格式为:typedef 原类型名 新类型名;例如:typedef int Integer;//指定 Integer为类型名,作用与 int相同typedef __int64 Long;// 指定 Long为类型名,作用与__int64相同typedef通常被用于以下三个目的:(1)为了隐藏特定类型的实现,强调使用类型的目的。(2)简化复杂的类型定义,使其更容易题解。(3)允许一种类型用于多个目的,同时使得每次使用该该类型的目的明确。下列的代码给出了 typedef的具体使用方法。【程序清单 8.1】1. //int 变量的用法

194

Page 203: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

2. #include <stdio.h>

3. typedef int Integer; // 重新指定整型的名字为 Integer

4. int main()

5. {

6. Integer x; // 用自己指定的名字 Integer来定义整型变量7. scanf(“%d”,&x); // 整型变量的输入8. printf(“%d\n”,x); // 整型变量的输出9. return 0;

10. }

8.2 结构体与共用体在实际问题中,常常要把多个数据合在一起当作一个数据处理。例如,处理平面上的

点集问题时,一个点的坐标 p(x,y)是一个数据。为了解决这个问题,C语言中给出了另一种构造数据类型——“结构体”。可以定义一个名为 Point的结构体,将 2 个坐标合在一起,构成点的信息:Struct Point{

int x; //点的横坐标int y; //点的纵坐标

};

有时,一组数据往往具有不同的数据类型。例如, 在学生登记表中含有以下几种数据类型:(1)姓名应为字符串型;(2)学号可为整型或字符型;

(3)年龄应为整型;(4)性别应为字符型;(5)成绩可为整型或实型。

显然不能用一个简单数据类型的数组来存放这一组数据。 而是希望把一个学生的信息当作一个数据处理。为了解决这个问题,可以定义一个名为 student的结构体,将这几项信息包容在一起,

构成学生的个人信息:struct Student

195

Page 204: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

{char name[20]; // 姓名int id; // 学号int age; // 年龄char sex; // 性别float score; // 成绩

};再用这个结构来定义可存放 N 个学生信息的数组变量 stu[],即 struct Student stu[N];

8.2.1 结构的定义结构体类型的定义方式较多,一般有如下几种定义方式。1.先声明结构体类型,再定义该类型的变量结构体声明格式为:struct 结构体名{类型名 1 成员名 1;类型名 2 成员名 2;…类型名 n 成员名 n;

};这里,struct是结构体类型的标志。结构体名 student是编程者自己命名的,与一般变量

的命名规则一样。大括号所括起来的 n 个语句是结构体中 n 个成员的定义。注意:结构体定义之后一定要跟一个“;”号。

结构体变量定义的格式为:struct 结构体名 变量名 1,变量名 2,…,变量名 m;例如,点的结构体声明为:struct Point{

int x; //点的横坐标int y; //点的纵坐标

};定义两个点 p1、p2为:struct Point p1,p2;

2.在声明类型的同时定义变量196

Page 205: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

其格式为:struct 结构体名{类型名 1 成员名 1;类型名 2 成员名 2;…类型名 n 成员名 n;

};变量名 1,变量名 2,…,变量名 m;例如,声明点的结构同时定义两个点为:struct Point{

int x; //点的横坐标int y; //点的纵坐标

}p1,p2;

3.不指定类型名而直接定义结构类型的变量struct {类型名 1 成员名 1;类型名 2 成员名 2;…类型名 n 成员名 n;

}变量名 1,变量名 2,…,变量名 m;例如,点的结构体变量 p1,p2的定义:struct {

int x; //点的横坐标int y; //点的纵坐标

}p1,p2;

4.使用 typedef定义其格式为:typedef struct <结构名>{类型名 1 成员名 1;类型名 2 成员名 2;…类型名 n 成员名 n;

}类型名;例如,点的结构体的定义:先声明结构的类型:typedef struct {

197

Page 206: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

int x; //点的横坐标int y; //点的纵坐标

}Point;再用 point定义点的变量。如:Point p1,p2;

8.2.2 结构类型变量的使用结构是一种“构造”而成的数据类型,其定义出来的变量与前面所学的变量类似,使

用时要初始化和引用。可以在定义的时候进行初始化。如:struct Student{

char name[20]; // 姓名int id; // 学号int age; // 年龄char sex; // 性别float score; // 成绩

}stu={“张山”,1001,20,m,99};或是:struct Student{

char name[20]; // 姓名int id; // 学号int age; // 年龄char sex; // 性别float score; // 成绩

};struct Student stu={“张山”,1001,20,m,99};也可以在使用前对各个成员变量赋值。结构体中的成员值的引用方式为:结构体变量名.成员名例 如 上 面 一 个 结 构 变 量 stu 里 的 成 员 变 量 在 引 用 时 分 别 写 成 :

stu.name,stu.id,stu.age,stu.sex,stu.score。【例 8.1】输入若干个点,请你编程分别求出这个点关于 x轴、y轴的对称点。分析:(1)把(x,y)看成一个数据,数据结构定义成:struct Point //定义点的结构 Point{

198

Page 207: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

int x,y; // 点的横、纵坐标};(2)(x,y)关于 x轴的对称点为(-x,y),关于 y轴的对称点为(x,-y)。【程序清单 8.2】1. #include <stdio.h>

2. struct Point //定义点的结构 point

3. {

4. int x,y; // 点的横、纵坐标5. };

6. int main() // 主函数7. {

8. struct Point p,px,py; // 定义点 p,px,py

9. while(scanf("%d %d",&p.x,&p.y)==2) //输入点 p的坐标值10. {

11. px.x = p.x; px.y = -p.y; // 计算关于 x轴的对称点,放在 px中12. py.x = -p.x; py.y = p.y; // 计算关于 y轴的对称点,放在 py中13. printf("(%d,%d)关于 x轴的对称点是(%d,%d)\n",p.x,p.y,px.x,px.y); // 输出14. printf("(%d,%d)关于 y轴的对称点是(%d,%d)\n",p.x,p.y,py.x,py.y); // 输出15. }

16. return 0;

17. }

运行过程为:4 5↙〈4,5〉关于 x轴的对称点是〈4,-5〉〈4,5〉关于 y轴的对称点是〈-4,5〉-3 -6↙〈-3,-6〉关于 x轴的对称点是〈-3,6〉〈-3,-6〉关于 y轴的对称点是〈3,-6〉本题小结:使用结构体的步骤:(1) 先定义结构体类型,见第 2~5行。(2) 使用类型定义结构体变量,见第 8行。(3) 结构变量的使用规则是:结构体变量名.成员变量名,见第 9~15行。对于更复杂的结构体变量的使用方法也是一样。一起看【程序清单 8.3】,如何使用结构

体变量处理学生信息。【程序清单 8.3】1. #include <stdio.h>

2. struct Student //定义结构 student

3. {

4. char name[20]; // 姓名199

Page 208: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

5. int id; // 学号6. int age; // 年龄7. char sex; // 性别8. float score; // 成绩9. };

10. int main() // 主函数11. {

12. struct Student stu1; // 定义 stu1为 student类型13. printf("请输入一个学生的姓名、学号、年龄、性别、成绩,数据间用空格隔开\n");

14. scanf("%s %d %d %c %f",stu1.name,&stu1.id,&stu1.age,&stu1.sex,&stu1.score); //输入个人信息

15. printf("输入的学生信息是:\n");

16. printf("姓名:%s 学号:%d 年龄:%d 性别:%c 成绩%f\

n",stu1.name,stu1.id,stu1.age,stu1.sex,stu1.score); //输出个个信息17. return 0;

18. }

运行过程为:请输入一个学生的姓名、学号、年龄、性别、成绩,数据间用空格隔开LiXing 1001 20 m 598↙输入的学生信息是:

姓名:LiXing 学号:1001 年龄:20 性别:m 成绩 598.000000

程序说明:(1)程序中第 2~9行定义一个名为 Student的结构体类型变量,Student理解为一种数

据类型,就像 int是整数的数据类型,student是自己定义的类型,它有 5 个成员变量。(2)程序中第 12行是定义 stu1为 student类型,在 C语言中前面的 struct不可少,而

在 C++中是可以省去。(3)在第 14、16行中变量的使用规则是:结构体变量名.成员变量名。如图 8.1 所示:

图 8.1 结构体 Student的变量 stu1

(4)与普通变量一样,结构体类型的变量也可以在定义时进行初始化。如:struct Student{

char name[20]; // 姓名200

stu1.namestu1.idstu1.agestu1.sexstu1.score

变量stu1

Page 209: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

int id; // 学号int age; // 年龄char sex; // 性别float score; // 成绩

}stu1={“WanWu”,2013001,20,’m’,598.5};

也可以是:

struct Student stu1={“WanWu”,2013001,20,’m’,598.5};

8.2.3 结构数组若干个学生的信息就要使用若干个结构变量,我们可以使用结构体类型的数组,即数

组元素是同一类型的结构体变量。【例 8.2】在 student.txt文件中,保存了若干个学生的信息。请你编程统计男、女生的人数

及这些学生的平均成绩。student.txt文件的内容如下:10

张三 2013001 20 m 600

李四 2013002 19 f 601.5

王五 2013003 20 f 599

李东东 2013004 21 m 602

施奇 2013005 19 m 598

张弓 2013006 20 m 600

赵四 2013007 19 f 601.5

陈南南 2013008 20 f 599

昊可用 2013009 21 m 602

雷厉 2013010 20 m 599

其中,第 1 个数 10表示后面的学生数是 10。每个学生的信息由姓名、学号、年龄、性别、成绩组成。分析:显然,学生的各项信息是一个整体,应定义为结构体数据类型 student;由于有多个学

生信息需要存储,因而需定义结构数组 st[100]。如【程序清单 8.4】中的第 3~10行所示。程序中分别完成读入数据、统计、输出。【程序清单 8.4】1. #include <stdio.h>

2. #include <malloc.h>

3. struct Student//学生信息的数据类型201

Page 210: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

4. {

5. char name[20]; // 姓名6. int id; // 学号7. int age; // 年龄8. char sex; // 性别9. float score; // 成绩10. }st[100];//结构数组11.

12. void work(int n,int *m_num,float *p_score)// 统计男、女生的人数及平均成绩13. {

14. int i;

15. for(i=1;i<=n;i++)

16. {

17. if(st[i].sex=='m') (*m_num)++;

18. *p_score += st[i].score;

19. }

20. *p_score /= n;

21. }

22.

23. int main()

24. {

25. int i,n,*m_num;

26. float *p_score;

27. freopen("student.txt","r",stdin); // 从文件中读入数据28. m_num = (int *)malloc(sizeof(int)); // 用于函数传参29. p_score = (float *)malloc(sizeof(float)); // 用于函数传参30. *m_num = 0;

31. *p_score = 0;

32. scanf("%d",&n);

33. for(i=1;i<=n;i++)//输入34. {

35. scanf("%s %d %d %c %f",st[i].name,&st[i].id,&st[i].age,&st[i].sex,&st[i].score);

36. }

37. work(n,m_num,p_score); // 用指针变量传参,可以带回计算结果38. printf("共有男生%d 人,女生%d 人\n",*m_num,n-*m_num);

39. printf("平均成绩是:%.2f\n",*p_score);

40. return 0;

41. }

运行结果为:共有男生 6 人,女生 4 人平均成绩是:600.20

注:(1)*m_num用于存放男生数、*p_score用于存放平均成绩,为了能在函数中保持运

202

Page 211: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

行结果值,用指针变量。(2)在第 10行中同时定义了 100 个 Student类型的结构数组,也可以在使用前定义:

struct Student st[100];

(3)另外,可采用 typedef来定义结构体类型的结构体名。第 3~10行可以写成:typedef struct//{

char name[20]; // 姓名int id; // 学号int age; // 年龄char sex; // 性别float score; // 成绩

}Student;student st[100];//用结构体名 student定义结构变量 st[100]。用 typedef来定义结构体类型的结构体名的格式具体如下所示:typedef struct {类型名 1 成员名 1;类型名 2 成员名 2;…类型名 n 成员名 n;

}结构体名;

这时,就可以使用时用结构体名定义结构变量。(4)对于 char name[20];定义的变量 name的值,如果不在 scanf()中直接输入,就要使

用字符函数 strcpy()处理。

8.2.4 共用体在程序设计中,有时需要使几种不同类型的变量存放到同一段内存单元中。也就是使

用覆盖技术,让几个变量互相覆盖。这种让几个不同的变量共同占用一段内存的结构,在 C

语言中,被称作“共用体”类型结构,简称共用体或联合体。共用体类型定义的格式为:union 共用体名{成员表列

}变量表列;

203

Page 212: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

例如,声明了一个 union data类型,将 x、y定义为 union data变量如下:union data{

int i;char ch[10];

}x,y;或写成:union data{

int i;char ch[10];

};union data x,y; 请对【程序清单 8.5】进行 debug 操作并观察 x.i与 x.ch的地址,这时 i与 ch的地址相同。

如图 8.2 所示。【程序清单 8.5】1. #include <stdio.h>

2. #include <string.h>

3. union data

4. {

5. int i;

6. char ch[10];

7. }x;

8. int main()

9. {

10. x.i = 10; // 对成员变量 i 赋值11. printf("%d\n",x.i); // 输出 10

12. strcpy(x.ch,"hello"); // x.ch的值为“hello”13. printf("%d\n",x.i); // 空间被 x.ch占用,x.i的原值消失14. printf("%s\n",x.ch); // 输出“hello”15. return 0;

16. }

运行结果为:10

1819043176

hello

204

Page 213: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 8.2 观察 x.i与 x.ch的地址将【程序清单 8.5】加以变化。对 x 两个成员变量先后赋值,观察结果,又将 x 两个成员

变量的类型进行更改,如改成数组等,再观察,可以得出如下结论:(1)共用体变量的地址和它的各成员的地址都是同一地址,但是每一瞬间只有一个成

员起作用,其他的成员不起作用,即不是同时都存在和起作用。(2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新成员后,原有

成员就失去作用。如第 10行给 x.i 赋值为 10,后又在第 12行将 x.ch 赋值为”hello”,则 x.i的值变为”hello”。(3)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。(4)共用体类型可以出现在结构体类型的定义中,也可以定义共用体数组。反之,结

构体也可以出现在共用体类型的定义中,数组也可以作为共用体的成员。

8.3 指针与结构体前面已经了解了结构体的定义和使用。结构体这种数据也是存储到内存单元中,因此

205

Page 214: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

它也有地址,也可以用指针来访问。【程序清单 8.3】可以改写成【程序清单 8.6】。【程序清单 8.6】1. #include <stdio.h>

2. #include <malloc.h>//为了使用指针变量3. struct student

4. {

5. char name[20]; // 姓名6. int id; // 学号7. int age; // 年龄8. char sex; // 性别9. float score; // 成绩10. };

11. int main()

12. {

13. struct student *st; //结构体指针14. st = (struct student*)malloc(sizeof(struct student)); //申请空间15. printf("请输入一个学生的姓名、学号、年龄、性别、成绩,数据间用空格隔开\n");

16. scanf("%s %d %d %c %f",st->name,&st->id,&st->age,&st->sex,&st->score);

17. printf("输入的学生信息是:\n");

18. printf("姓名:%s 学号:%d 年龄:%d 性别:%c 成绩%f\n",st->name,st->id,st->age,st->sex,st-

>score);

19. return 0;

20. }

从中看出:结构体指针变量与普通指针变量的使用一样,先定义,再申请空间或引用空间。而利用结构体指针变量访问成员变量时要用“->”号。如图 8.2 所示:

图 8.3 结构体 student的指针变量 st

结构体内的成员变量可以是结构体变量、指针变量、或者是本结构体的变量及指针变量。请阅读【程序清单 8.7】。

【程序清单 8.7】1. #include <stdio.h>

2. #include <stdlib.h> //为方便使用指针3. #include <math.h>

206

St->nameSt->idSt->ageSt->sexSt->score

变量*st

Page 215: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

4. struct point //点的结构5. {

6. int x,y;

7. };

8. struct p_dis

9. {

10. struct point *p1,*p2; // 两个点11. double d; // 存放两点间的距离12. };

13.

14. int main()

15. {

16. struct p_dis pd;

17. pd.p1 = (struct point *)malloc(sizeof(struct point));

18. pd.p2 = (struct point *)malloc(sizeof(struct point));

19. pd.p1->x = 1; pd.p1->y = 2;

20. pd.p2->x = 4; pd.p2->y = 6;

21. pd.d = sqrt((pd.p1->x-pd.p2->x)*(pd.p1->x-pd.p2->x)+(pd.p1->y-pd.p2->y)*(pd.p1->y-pd.p2-

>y));

22. printf("(1,4)与(2,6)之间的距离是:%.2lf\n",pd.d);

23. return 0;

24. }

运行的结果是:(1,4)与(2,6)之间的距离是:5.00

结构体内的指针与普通变量的指针一样,也是要先申请地址空间或引用其它变量的地址空间才可以使用。

8.4返回值是结构体指针的函数返回值是结构体指针的函数使用较为普遍,下面用【程序清单 8.8】来解释它的用法。【程序清单 8.8】1. #include <stdio.h>

2. #include <malloc.h>

3. struct student // 定义结构 student

4. {

5. char name[20]; // 姓名6. int id; // 学号7. int age; // 年龄8. char sex; // 性别

207

Page 216: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

9. float score; // 成绩10. };

11. int main() // 主函数12. {

13. struct student *in(); // 输出函数声明14. void out (struct student *stu); // 输出函数声明15. struct student stu1; // 定义 stu1为 student类型,用于存放函数 in()的返回值16. stu1 = *(in()); // 调用 in()函数,将值传给 stu1

17. out(&stu1); //调用 out()函数用于输出,传入的是变量 stu1的地址18. return 0;

19. }

20. struct student *in() // 定义 in()函数,函数值为结构体指针类型21. {

22. struct student *stu; // 定义 stu为 student类型23. stu = (struct student *)malloc(sizeof(struct student));

24. printf("请输入一个学生的姓名、学号、年龄、性别、成绩,数据间用空格隔开\n");

25. scanf("%s %d %d %c %f",stu->name,&stu->id,&stu->age,&stu->sex,&stu->score); //输入个人信息

26. return stu;

27. }

28. void out (struct student *stu)

29. {

30. printf("输入的学生信息是:\n");

31. printf("姓名:%s 学号:%d 年龄:%d 性别:%c 成绩%f\n",stu->name,stu->id,stu->age,stu-

>sex,stu->score); //输出个人信息32. }

运行过程为:请输入一个学生的姓名、学号、年龄、性别、成绩,数据间用空格隔开zhang 1001 20 m 699↙输入的学生信息是:

姓名:zhang 学号:1001 年龄:20 性别:m 成绩 699.000000

程序说明:(1)程序的功能是输入一位学生的信息,再将这个信息输出。(2)第 3~10行把学生信息定义成一个结构体。(3)第 20~27行定义一个结构体指针类型(struct student *)的函数 in(),其中第

22、23行定义一个 struct student *类型的变量,并申请了空间,用于存放函数的返回值;第26行返回的 stu的类型就是函数值的类型(struct student *)。(4)第 28~32行定义一个输出信息的函数 out(),传入的参数是结构体指针变量。

208

Page 217: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

8.5 链表数组使用时要开辟连续的固定的存储空间,然而在实际使用时,空间的大小往往不好

确定,常常要开辟相当大的空间。为了开辟实际使用的空间,我们可以使用链表处理数据。链表属于动态数据结构,它就像一个接着一个的链条,它是由结构体内定义一个指向下一个结构体变量的指针来实现的。这种结构非常灵活,每个结点的存储空间可以在使用时生成,结点间的存储空间也不需要连续。链表又有分单链表、单循环链表、双链表、双循环链表。下面只讨论单链表。

8.5.1单链表的结构单链表中的一个结点的数据结构可以定义为:sturct node_name{数据项DATA;sturct node_name *next;

}node_name是你为结点取的名字,与变量名的规则一样,数据项 DATA可以包含若干

个数据类型。sturct node_name *next是定义一个与结构体类型一致的指针变量,用于用于存储下一结点的地址,从而,多个结点连在一起就构成链表,如图 8.4 所示。

图 8.4 单链表

8.5.2单链表的建立与输出【例 8.3】新生报到开始了,需要登记的信息是:姓名、性别、来的地方、已安排的学号。

请你编程将新生的信息输入电脑,然后按原顺序输出。(smu1178)信息如下(input.in):20130862150 m zhang fuzou

209

Page 218: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

20130862178 f li shanghai

20130862154 m wu sanming

20130862155 f wang zhejian

20130862170 f chen zhangzhou

新生的结构定义为:struct student{     __int64 num;     char sex;     char name[10];     char come_from[20];    struct student *next;};分析:建立链表步骤是:(1)先建立(定义)链表的头指针 head;(2)申请一个新结点的空间,并让头指针指向该结点(首结点);(3)输入结点数据域的各数据项;(4)反复在尾结点后加入新结点;

(5)判断是否要结束输入数据,若是,释放该结点并退出循环;(6)置新结点(尾结点)的指针域为空。(7)返回头指针 head。注:对于头结点 head,可以存储数据,也可以空着不使用。在建立链表时,可以根据

具体情况而定。输出链表:新建一个结点指针 p指向头指针,通过 p指针逐一指向每一个结点,即通过 p指针输

出数据后,再用语句 p=p->next 将 p移动到下一个结点。【程序清单 8.9】1. #include<stdio.h>

2. #include<stdlib.h>

210

Page 219: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

3. struct student

4. {

5. __int64 num;

6. char sex;

7. char name[10];

8. char come_from[20];

9. struct student *next;

10. };

11. struct student *creat()

12. {

13. struct student *head,*p,*q;

14. q = head = NULL; //建立头结点15. p=(struct student *)malloc(sizeof(struct student)); // 为新的结点开辟空间16. while(scanf("%I64d %c %s %s",&p->num,&p->sex,p->name,p->come_from)==4)

17. {

18. if(head==NULL) // 链表中没有数据项时,产生的结点作为头结点19. {

20. head = p;

21. q = p;

22. }

23. else//用 q指针完成加入新结点工作24. {

25. q->next = p;

26. q = q->next;

27. }

28. p = (struct student *)malloc(sizeof(struct student)); // 为下一个新结点申请空间29. }

30. free(p); // 将最后一个多申请的空间删除31. q->next = NULL; // 让链表的尾指针为空32. return head;

33. }

34. void out(struct student *head)

35. {

36. struct student *p;

37. p = head;

38. while(p!=NULL)

39. {

40. printf("%I64d %c %s %s\n",p->num,p->sex,p->name,p->come_from);

41. p = p->next;

42. }

43. }

44.

45. void main()

46. {

211

Page 220: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

47. struct student *head;

48. head=creat();

49. out(head);

50. }

程序说明:( 1)主函数中 head=creat();是调用 creat()函数,并获得链表的头指针,

out(head);是调用函数 out(),并输出头指针为 head的链表。(2)从 15~29行是增加一个结点,每链接一个结点就要判断是否是要放在头结点,

新结点作为头结点还是接在老结点的后面代码是不一样的。如果头结点不用,也就是带头结点的链表,情况会简单些。请大家自己尝试。(3)数据放在 input.in 的文件中,第 40 行使得程序从文件 input.in 中取数据。运行的过程为:20130862150 m zhang fuzou↙20130862178 f li shanghai↙20130862154 m wu sanming↙20130862155 f wang zhejian↙20130862170 f chen zhangzhou↙^Z↙20130862150 m zhang fuzou

20130862178 f li shanghai

20130862154 m wu sanming

20130862155 f wang zhejian

20130862170 f chen zhangzhou

8.5.3单链表结点的插入

我们将【例 8.3】的输出改为:按学号的大小顺序输出。(smu1180)可以理解成

每次都将新结点插入到前一个结点的学号比自己小,后一个结点的学号比自己大的

位置。链表的插入步骤是:(1) 申请空间 p,把要插入的数据存入结点 p;(2) 找到要插入的位置 q,也就是要在 q的后面插入;

212

Page 221: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(3) 把 p插入 q的后面。如图 8.5 所示:

图 8.5 链表 p 结点的插入这个操作需要 2 个指针变量 p、q来实现,p指针负责申请空间和输入数据,q指针负责

移动使得 p要插入到 q的后面。【程序清单 8.10】1. #include <stdio.h>

2. #include <malloc.h>

3. struct student

4. {

5. __int64 num;

6. char sex;

7. char name[10];

8. char come_from[20];

9. struct student *next;

10. };

11. struct student *creat() // 产生空链表12. {

13. struct student *head;

14. head = (struct student*)malloc(sizeof(struct student));

15. head->next = NULL;

16. return head;

17. }

18. struct student*insert(struct student*head,struct student *p) // 插入,头指针不用19. {

20. struct student *q;

21. q = head;

22. while(q->next!=NULL&&q->next->num<p->num)

23. {

24. q = q->next;

25. }

26. p->next = q->next;

27. q->next = p;

28. return head;

213

Page 222: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

29. }

30.

31. void out(struct student *head) // 从头指针的下一个结点开始输出32. {

33. struct student *p;

34. p=head->next;

35. while(p!=NULL)

36. {

37. printf("%I64d %c %s %s\n",p->num,p->sex,p->name,p->come_from);

38. p=p->next; // 指针下移39. }

40. }

41. void work(struct student *head)

42. {

43. struct student *p;

44. p = (struct student*)malloc(sizeof(struct student));

45. while(scanf("%I64d %c %s %s",&p->num,&p->sex,p->name,p->come_from)==4)

46. {

47. head = insert(head,p); // 调用插入函数48. p = (struct student*)malloc(sizeof(struct student));

49. }

50. free(p);

51. }

52. int main()

53. {

54. struct student *head;

55. head = creat(); // 创建空链表

56. work(head); // 读入学生信息,并插入到指定的位置57. out(head); // 输出58. return 0;

59. }

运行过程为:20130862150 m zhang fuzou↙20130862178 f li shanghai↙20130862154 m wu sanming↙20130862155 f wang zhejian↙20130862170 f chen zhangzhou↙^Z↙20130862150 m zhang fuzou

20130862178 f li shanghai

20130862154 m wu sanming

20130862155 f wang zhejian

20130862170 f chen zhangzhou

214

Page 223: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

8.5.4单链表结点的删除

将【例 8.3】的输出改成:按原顺序输出女生信息(smu1179)。也就是要删除男生信息,这就是链表中结点的删除问题。删除一个结点的步骤是:(1)找到要删结点的位置 p,前面的一个结点是 q;(2)让 q 结点直接指向 p的下一个结点。此时,p 结点就无法在此链表中找到;(3)释放 p空间。如图 8.6 所示:

图 8.6 链表 p 结点的删除【程序清单 8.11】1. #include<stdio.h>

2. #include<stdlib.h>

3. struct student

4. {

5. __int64 num;

6. char sex;

7. char name[10];

8. char come_from[20];

9. struct student *next;

10. };

11. struct student *creat()

12. {

13. struct student *head,*p,*q;

14. q = head = NULL;

15. p = (struct student *)malloc(sizeof(struct student));

16. while(scanf("%I64d %c %s %s",&p->num,&p->sex,p->name,p->come_from)==4)

17. {

215

Page 224: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

18. if(head==NULL)

19. {

20. head = p;

21. q = p;

22. }

23. else

24. {

25. q->next = p;

26. q = q->next;

27. }

28. p = (struct student *)malloc(sizeof(struct student));

29. }

30. q->next = NULL;

31. return head;

32. }

33. void out(struct student *head)

34. {

35. struct student *p;

36. p = head;

37. while(p!=NULL)

38. {

39. printf("%I64d %c %s %s\n",p->num,p->sex,p->name,p->come_from);

40. p = p->next;

41. }

42. }

43. struct student *del(struct student *head) // 删除男生信息44. {

45. struct student *p,*q;

46. p = q = head;

47. while(p)

48. {

49. if(p->sex=='m') // 找到要删除的结点50. {

51. if(p==head) // 头结点情况52. {

53. head = head->next;

54. free(p);

55. p = q = head;

56. }

57. else //非头结点情况58. {

59. q->next = p->next;

60. free(p);

61. p = q->next;

216

Page 225: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

62. }

63. }

64. else //移动 p、q 结点65. {

66. q = p;

67. p = p->next;

68. }

69. }

70. return head;

71. }

72.

73. void main()

74. {

75. struct student *head;

76. head = creat();

77. out(del(head));

78. }

运行过程为:20130862150 m zhang fuzou↙20130862178 f li shanghai↙20130862154 m wu sanming↙20130862155 f wang zhejian↙20130862170 f chen zhangzhou↙^Z↙20130862178 f li shanghai

20130862155 f wang zhejian

20130862170 f chen zhangzhou

8.6 枚举数据类型有时需要为某些属性定义一组可选 择的值。例如,一个星期的 7 天:

mon、tue、wed、thu、fri、sat、sun,想用 1、2、3、4、5、6、0表示,也就是要使得mon=1;tue=2、wed=3、thu=4、fri=5、sat=6、sun=0。这个问题可以通过声明一个枚举类型来实现。即:

enum Weekday{ sun,mon,tue,wed,thu,fri,sat };声明枚举类型的一般形式为:enum [枚举名]{枚举成员列表};

217

Page 226: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

说明:(1)其中枚举名与变量名类似,由用户自己定义;(2)枚举成员是常量,不能给它们赋值,但可以作为整型数使用;(3)默认第 1 个枚举成员的值为 0,后面的每个枚举成员赋的值比前面大 1,也可以

在声明时加以改变,例如,把声明改成 enum Weekday {sun,mon,tue=6,wed,thu,fri,sat};

则 sun,mon,tue,wed,thu,fri,sat的值分别为:0、1、6、7、8、9、10。(4)枚举元素可以用来判断比较,如 if(sun<wed)…。枚举变量的定义格式为:enum [枚举名] 变量列表;枚举变量可以取枚举成员列表中的值。

【程序清单 8.12】1. #include<stdio.h>

2. int main()

3. {

4. enum Weekday {sun,mon,tue,wed,thu,fri,sat}; //声明枚举变量5. char wname[7][5] = {{"sun"},{"mon"},{"tue"},{"wed"},{"thu"},{"fri"},{"sat"}};

6. enum Weekday wk; // 定义枚举变量7. for(wk = sun;wk<=sat;wk++) // 用枚举变量 wk遍历 sun到 sat

8. {

9. printf("%s= %d, ",wname[wk],wk); //

10. }

11. printf("\n");

12. return 0;

13. }

输出结果为:sun= 0, mon= 1, tue= 2, wed= 3, thu= 4, fri= 5, sat= 6,

【例 8.4】安排值日(smu1166)Description

一个学生宿舍住着 4位学生,名字叫 studenter1、studenter2、studenter3、studenter4,每周要有 3位学生完成宿舍的值日,分别做周 1到周 3、周 4到周 5、周 6到周日。请你编程排一值日表,排出所有可能。

Output

按字典序输出各种可能。分析:这是从四个学生选择三位,把所有的结果按字典序排出的问题。可以用三重循环对选

出的三位学生进行枚举。为了便于把四位学生对应数据 1、2、3、4来表示,我们使用枚举类型。enum Stu{ studenter1,studenter2,studenter3,studenter4};

218

Page 227: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

这里,Stu 是枚举名,studenter1,studenter2,studenter3,studenter4是枚举常量。相当于studenter1=0、studenter2=1、studenter3=2、studenter4=3。当 使 用 enum Stu k; 定 义 枚 举 变 量 时 , 相 当 于 k 可 以 取

studenter1 、studenter2、studenter3、studenter4 的值。【程序清单 8.13】

1. #include <stdio.h>

2. int main()

3. {

4. enum Stu{studenter1,studenter2,studenter3,studenter4};

5. enum Stu i,j,k;

6. char name[4][15]={"studenter1","studenter2","studenter3","studenter4"};

7. for(i=studenter1;i<=studenter4;i++) // 周 1到周 3 值日的学生8. for(j=studenter1;j<=studenter4;j++) // 周 4到周 5 值日的学生9. if(i!=j)

10. {

11. for(k=studenter1;k<=studenter4;k++) // 周 6到周日值日的学生12. {

13. if(k!=i&&k!=j)

14. printf("周 1到周 3:%s\t周 4到周 5:%s\t周 6到周日:%s\

n",name[i],name[j],name[k]); //输出一种情况15. }

16. }

17. }

运行结果为:周 1到周 3:studenter1 周 4到周 5:studenter2 周 6到周日:studenter3

周 1到周 3:studenter1 周 4到周 5:studenter2 周 6到周日:studenter4

周 1到周 3:studenter1 周 4到周 5:studenter3 周 6到周日:studenter2

周 1到周 3:studenter1 周 4到周 5:studenter3 周 6到周日:studenter4

周 1到周 3:studenter1 周 4到周 5:studenter4 周 6到周日:studenter2

周 1到周 3:studenter1 周 4到周 5:studenter4 周 6到周日:studenter3

周 1到周 3:studenter2 周 4到周 5:studenter1 周 6到周日:studenter3

周 1到周 3:studenter2 周 4到周 5:studenter1 周 6到周日:studenter4

周 1到周 3:studenter2 周 4到周 5:studenter3 周 6到周日:studenter1

周 1到周 3:studenter2 周 4到周 5:studenter3 周 6到周日:studenter4

周 1到周 3:studenter2 周 4到周 5:studenter4 周 6到周日:studenter1

周 1到周 3:studenter2 周 4到周 5:studenter4 周 6到周日:studenter3

周 1到周 3:studenter3 周 4到周 5:studenter1 周 6到周日:studenter2

周 1到周 3:studenter3 周 4到周 5:studenter1 周 6到周日:studenter4

周 1到周 3:studenter3 周 4到周 5:studenter2 周 6到周日:studenter1

周 1到周 3:studenter3 周 4到周 5:studenter2 周 6到周日:studenter4

周 1到周 3:studenter3 周 4到周 5:studenter4 周 6到周日:studenter1

周 1到周 3:studenter3 周 4到周 5:studenter4 周 6到周日:studenter2

周 1到周 3:studenter4 周 4到周 5:studenter1 周 6到周日:studenter2

219

Page 228: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

周 1到周 3:studenter4 周 4到周 5:studenter1 周 6到周日:studenter3

周 1到周 3:studenter4 周 4到周 5:studenter2 周 6到周日:studenter1

周 1到周 3:studenter4 周 4到周 5:studenter2 周 6到周日:studenter3

周 1到周 3:studenter4 周 4到周 5:studenter3 周 6到周日:studenter1

周 1到周 3:studenter4 周 4到周 5:studenter3 周 6到周日:studenter2

8.7 案例及分析【例 8.4】歌咏比赛(smu1114)

Description

某电视台要举行大学生歌咏比赛,请了 10位评委,选手的得分规则是:去掉一个最高分,去掉一个最低分,对剩下的 8 个分数求平均分。要求你编程现场统计,每比赛完一个就亮出得分,最后结束时统计出冠军、亚军和季军。

Input

输入的数据有若干行,每行 10 个分数,依次是各评委对选手的打分。选手的序号从 1开始。不超过 50

名选手。如:Ouput

依次输出各选手的得分,格式是“id:score"。结束后,分三行输出前三名的情况,输出格式是:

gold medalist:id score:score

silver medalist:id score:score

bronze medalist:id score:score 结果保留两位小数(要四舍五入)。如果有重名就并列计算,但只选前三名。Sample Input

9 9 9.5 8.9 9 9.1 9.5 8.8 9 9.4

9.6 9.6 9.6 9.6 9.6 9.6 9.6 9.6 9.6 9

8.6 8.7 8.9 8.7 9 9 8.9 8.9 8 8.6

9.8 9.5 9.6 9.6 9.6 9.6 9.6 9.6 9.6 9.6

8.3 9 9.6 9.2 9 9.1 8.9 8.8 8.9 9

Sample Output

1:9.11

2:9.60

3:8.79

4:9.60

5:8.99

gold medalist:2 score:9.60

gold medalist:4 score:9.60

silver medalist:1 score:9.11

分析:每位歌手的数据项都一致,因此选用结构数组。数组的下标就是选手的号数。选手结点

的数据结构用:220

Page 229: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

struct Singer { int num; // 歌手编号

float score[10]; // 计 10位评委打的分float Last_score; // 选手的最后得分

};得到评委打的分数后,就可以计算该歌手的得分,整个过程在一个函数work()内完成。

【程序清单 8.14】1. #include<stdio.h>

2. struct Singer

3. {

4. int num; // 歌手编号5. float score[10]; // 计 10位评委打的分6. float Last_score; // 选手的最后得分7. }a[50]; // 定义结构数组8. void work()

9. {

10. int i=0,j,k;

11. float max,min,t;

12. struct Singer temp;

13. while(scanf("%f%f%f%f%f%f%f%f%f

%f",&a[i].score[0],&a[i].score[1],&a[i].score[2],&a[i].score[3],&a[i].score[4],&a[i].score[5],&a[i].sco

re[6],&a[i].score[7],&a[i].score[8],&a[i].score[9])!=EOF)

14. {

15. a[i].Last_score=0,max=0,min=10;

16. for(j=0;j<10;j++)

17. {

18. if(a[i].score[j]>max) max=a[i].score[j]; // 找最高分19. if(a[i].score[j]<min) min=a[i].score[j]; // 找最低分20. a[i].Last_score = a[i].Last_score+a[i].score[j]; // 总分21. }

22. a[i].Last_score = (a[i].Last_score-max-min)/8; // 平均分23. printf("%d:%.2f\n",i+1, a[i].Last_score);

24. i++;

25. a[i].num = i;

26. }//while

27. for(k=0;k<i-1;k++)//排序28. for(j=k+1;j<i;j++)

29. {

30. if(a[k].Last_score<a[j].Last_score)

31. {

32. temp = a[k];

33. a[k] = a[j];

221

Page 230: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

34. a[j] = temp;

35. }

36. }

37. for(k=0;k<3;k++) //输出前三名38. {

39. if(k==0)

40. printf("gold medalist:%d score:%.2f\n",a[k].num,a[k].Last_score);

41. if(k==1)

42. {

43. if(a[1].Last_score==a[0].Last_score)

44. printf("gold medalist:%d score:%.2f\n",a[k].num,a[k].Last_score);

45. else

46. printf("silver medalist:%d score:%.2f\n",a[k].num,a[k].Last_score);

47. }

48. if(k==2)

49. {

50. if(a[0].Last_score==a[1].Last_score==a[2].Last_score)

51. printf("gold medalist:%d score:%.2f\n",a[k].num,a[k].Last_score);

52. else

53. {

54. if(a[1].Last_score==a[2].Last_score)

55. printf("silver medalist:%d score:%.2f\n",a[k].num,a[k].Last_score);

56. else

57. printf("bronze medalist:%d score:%.2f\

n",a[k].num,a[k].Last_score);

58. }

59. }

60. }

61.

62. }

63. int main()

64. {

65. work();

66. return 0;

67. }

【例 8.5】判断平面上的三点能否构成三角形(smu1126)Description平面上有三个点,先设计函数 Is_triangle()来判断这三个点是否能构成三角形,再由主函数调用。点

要求使用结构体。Input输入有若干种情况,每种情况一行,每行有三个点:(x1,y1),(x2,y2),(x3,y3)。

输出要求每行输出一种情况,如果能构成三角形输出"ok",否则"sorry"。

222

Page 231: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Sample Input

0 0 1 1 2 2 -1 0 1 0 0 1Sample Outputsorry sorryok分析:设点的数据结构为:struct point{

int x,y;};用这样的结构定义 3 个点 p1、p2、p3,能构成三角形就是三点不共线。三点共线的判断是:

, (1) 也就是:(p1.y-p2.y)*(p1.x-p3.x)==(p1.y-p3.y)*(p1.x-p2.x) (2)注意:等式(1)隐含除法运算,无法判断等式是否成立,等式(2)两边运算的结果是整数,因此要用等式(2)。方法 1:不用指针见【程序清单 8.11】。【程序清单 8.15】1. #include<stdio.h>

2. #include<math.h>

3. struct point

4. {

5. int x,y;

6. };

7. int Is_triangle(struct point p1,struct point p2,struct point p3) // 参数是结构体变量8. {

9. double a1,a2;

10. if((p1.y-p2.y)*(p1.x-p3.x)!=(p1.y-p3.y)*(p1.x-p2.x)) // 判断三点是否共线11. return 1;

12. else return 0;

13. }

14. int main()

15. {

16. int n,i,z;

17. struct point pp1,pp2,pp3;

223

Page 232: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

18. while(scanf("%d%d%d%d%d%d",&pp1.x,&pp1.y,&pp2.x,&pp2.y,&pp3.x,&pp3.y)!=EOF)

19. {

20. z = Is_triangle(pp1,pp2,pp3); //结构体变量传参21. if(z==1)

22. printf("Ok\n");

23. else

24. printf("Sorry\n");

25. }

26. return 0;

27. }

运行过程为:0 0 1 1 2 2 ↙sorry

-1 0 1 0 0↙Ok

函数 Is_triangle(struct point p1,struct point p2,struct point p3)中传进的是三个点的结构体变量。可以看出结构体变量的传参与普通变量的传参是一样。方法 2:如果用指针传参,程序可修改成【程序清单 8.16】。【程序清单 8.16】1. #include<stdio.h>

2. #include<math.h>

3. struct point

4. {

5. int x,y;

6. };

7. int Is_triangle(struct point *p1,struct point *p2,struct point *p3) // 参数定义成结构体指针变量8. {

9. double a1,a2;

10. if((p1->y-p2->y)*(p1->x-p3->x)!=(p1->y-p3->y)*(p1->x-p2->x))

11. return 1;

12. else

13. return 0;

14. }

15. int main()

16. {

17. int n,i,z;

18. struct point pp1,pp2,pp3;

19. while(scanf("%d%d%d%d%d%d",&pp1.x,&pp1.y,&pp2.x,&pp2.y,&pp3.x,&pp3.y)!=EOF)

20. {

21. z = Is_triangle(&pp1,&pp2,&pp3); // 结构体地址传参22. if(z==1)

224

Page 233: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

23. printf("ok\n");

24. else

25. printf("sorry\n");

26. }

27. return 0;

28. }

【例 8.6】猴子选大王(smu1162)Description有 n 只猴子编号是 1,2,…,n(1<n<100),围成一圈,从第 1位顺序开始报号 1,2,3,

…,k。凡报到 k的猴子退出圈子。最后留下的那一位是猴王。请你编程找出第几只猴子是猴王。Input有若干种情况,每种情况一行,每行两个正整数 n、k,表示 n 只猴子,退出的是第 k 个。 Output每种情况输出一行,先输出“Case id:”,再输出留下当大王的猴子的号数。 Sample Input 13 32 2Sample OutputCase 1:13Case 2:1分析:有 n 只猴子围成一圈。让第 1 只指向第 2 只,第 2 只指向第 3 只,…,第 n 只指向第 1

只,这样就形成一个圈;凡报到 k的猴子要退出圈,只要让前面一只猴子指向这只猴子的下一只就行。为了申请指针空间的麻烦,我们用整数变量 next代替指针,其值为下一只猴子的编号,这样也就有了链表的思想。

【程序清单 8.17】1. #include<stdio.h>

2. struct monkey

3. {

4. int number;

5. int next;

6. }link[100];//结构数组7. void set(int n,int k) //将数组之间设置成链式状8. {

9. int i;

10. for(i=1;i<=n;i++)

11. {

12. if(i==n)

13. link[i].next=1;

225

Page 234: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

14. else

15. link[i].next=i+1;

16. link[i].number=i;

17. }

18. }

19. int find(int n, int k)//寻找猴王20. {

21. int i,count=0, h = n;

22. while (count<(n-1))

23. {

24. i=0;

25. while(i!=k) // 寻找报数到 k的猴子26. {

27. h=link[h].next;

28. if(link[h].number!=0)

29. i++;

30. }

31. link[h].number = 0;

32. count++;

33. }

34. for(i=1;i<=n;i++)

35. if(link[i].number!=0)break;

36. return i;

37. }

38. int main()

39. {

40. int n,k,t=1;

41. while(scanf("%d %d",&n,&k)!=EOF)

42. {

43. set(n,k);

44. printf("Case %d:%d\n",t++,find(n,k));

45. }

46. return 0;

47. }

请读者将第 5行的 int next;改成:struct monkey *next;重写这一题的代码。注意:建立链表时,将尾指针指向头指针,形成循环链表。

8.8 进阶【任务 8.1】求两降幂排列多项式的和。

226

Page 235: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

Description

两个一元多项式求和,相当于合并同类项。如 A(x)= 5x^17+8x^10+7x+12,B(X)= -6x^10+15x^7+8x,他们的和是: A(x)+B(x)=5x^17+2x^10+15x^7+15x+12.请你编程求两个一元多项式的和。假设多项式按降幂排列,次数不超过 100。

Input

先输入一个整数 T(0<T<=10),表示要算几对多项式的和,接下来有 2T行,每两行是一对要求和的多项式。每一行的第一个整数 n表示多项式的项数,后面的 2n 个数是对应的系数和指数。

Output

每行输出一对多项式的和,先输出“Case id:”,id是从 1开始的序号,接着按问题描述中的格式输出和的多项式。空项不用输出。

Sample Input

3

4 5 17 8 10 7 1 12 0

3 -6 10 15 7 8 1

1 2 1

1 -2 1

1 -1 1

1 0 0

Sample Output

Case 1: 5x^17+2x^10+15x^7+15x+12

Case 2: 0

Case 3: -x

分析:把每一个项看成一个结点,形成一个多项式的链表。先设计各项的结点数据结构:typedef struct Node{

int zs,xs; struct Node *next;}Node,*Sqlist;typedef是用来声明新类型名,这里声明了Node和*Sqlist,分别代表了结构体类型和结

构体指针类型。可以直接用它们定义变量,不用再加 struct。如【程序清单 8.18】中的第 12行。

【程序清单 8.18】1. #include<stdio.h>

2. #include<malloc.h>

3. #define le sizeof(Node)

4. typedef struct Node //多项式各项的结点结构5. {

6. int zs,xs;

7. struct Node *next;

227

Page 236: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

8. }Node,*Sqlist;

9. struct Node *scan1(int n) //建立多项式 1 链表,返回头指针10. {

11. int i;

12. Sqlist p,phead=NULL,pp;

13. for(i=1;i<=n;i++)

14. {

15. p=(struct Node *)malloc(le);

16. scanf("%d %d",&p->xs,&p->zs);

17. if(phead==NULL)

18. phead=p;

19. else

20. pp->next=p;

21. pp=p;

22. }

23. pp->next=NULL;

24. return phead;

25. }

26. struct Node *scan2(int m) // 建立多项式 2 链表,返回头指针27. {

28. int i;

29. Sqlist q,qhead=NULL,qq;

30. for(i=1;i<=m;i++)

31. {

32. q=(struct Node *)malloc(le);

33. scanf("%d %d",&q->xs,&q->zs);

34. if(qhead==NULL)

35. qhead = q;

36. else

37. qq->next = q;

38. qq = q;

39. }

40. qq->next = NULL;

41. return qhead;

42. }

43. struct Node *add(Sqlist phead,Sqlist qhead) //两多项式求和44. {

45. Sqlist t,tt,r,head,tail,temp;

46. int sum;

47. t = phead, tt = qhead;

48. head = (struct Node *)malloc(le);

49. tail = head;

50. r = tail;

51. while(tt!=NULL&&t!=NULL)

228

Page 237: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

52. {

53. if(t->zs>tt->zs)

54. {

55. tail->next = t;

56. tail = t;

57. t = t->next;

58. }

59. else if(t->zs==tt->zs)

60. {

61. sum=t->xs+tt->xs;

62. if(sum!=0)

63. {

64. t->xs=sum;

65. tail->next=t;

66. tail=t;

67. t=t->next;

68. temp=tt;

69. tt=tt->next;

70. free(temp);

71. }

72. else

73. {

74. t->xs = sum;

75. tail->next = t;

76. tail = t;

77. t = t->next;

78. temp = tt;

79. tt = tt->next;

80. free(temp);

81. }

82. }

83. else

84. {

85. tail->next = tt;

86. tail = tt;

87. tt = tt->next;

88. }

89. }

90. if(tt!=NULL)

91. tail->next=tt;

92. else

93. tail->next=t;

94. return r->next;

95. }

229

Page 238: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

96. void print(Sqlist head) // 输出多项式的和

97. {

98. int k=0;

99. Sqlist tt;

100. tt = head;

101. while(tt!=NULL)

102. {

103. if(tt->xs!=0)

104. {

105. if(k==1&&tt->xs>0)

106. printf("+");

107. if(tt->zs==0)

108. printf("%d",tt->xs);

109. else

110. {

111. if(tt->xs==-1)

112. printf("-");

113. else if(tt->xs!=1)

114. printf("%d",tt->xs);

115. printf("x");

116. }

117. if(tt->zs!=1&&tt->zs!=0)

118. printf("^%d",tt->zs);

119. k = 1;

120. }

121. tt = tt->next;

122. }

123. if(k==0)

124. printf("0");

125. }

126. void main()

127. {

128. int n,n1,n2,k=1;

129. Sqlist phead=NULL,qhead=NULL;

130. Sqlist t,tt,s;

131. while(scanf("%d",&n)!=EOF)

132. {

133. while(n--)

134. {

135. scanf("%d",&n1);

136. t=scan1(n1);

137. scanf("%d",&n2);

138. tt=scan2(n2);

139. s=add(t,tt);

230

Page 239: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

140. printf("Case %d: ",k++);

141. print(s);

142. printf("\n");

143. phead=NULL,qhead=NULL;

144. }

145. }

146. }

运行过程为:3↙4 5 17 8 10 7 1 12 0↙3 -6 10 15 7 8 1↙Case 1: 5x^17+2x^10+15x^7+15x+12

1 2 1↙1 -2 1↙Case 2: 0

1 -1 1↙1 0 0↙Case 3: -x

注:这是一位学生AC的代码,请你仔细阅读,并加以改进。

231

Page 240: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题1.一个班有 n 个学生,5门学科,请统计每人的总分和平均分,然后按号数查询。要

求学生用结构体变量表示,统计用函数。(smu1102)2.直角坐标系中(x,y)关于直线 y=x的对称点是(y,x)。请编程求对称点的坐标。要求点

用结构:(smu1105) struct POINT

{

 int x;

 int y;

};

求对称点用函数。3.平面上有三个点,求这三个点构成的三角形的面积。点用结构体定义:(smu1107)struct POINT

{

 int x;

 int y;

};

面积写成函数,用公式:(三个点逆时针时面积为正)

4.平面上有 n 个格点(x,y坐标都是整数),请编程找出离原点最远的点,如果有多个一样远,都得列出。点用结构(或自己定义):(smu1112)

struct POINT

232

Page 241: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

{

     int x;

     int y;

}pp[51];

把对过程重复使用的部分,如两点的距离定义成函数。5.在数轴上放了 n条线段,每条线段都知道它的起点坐标 a和终点坐标 b。请编程求这

些线段的和。求两坐标间的长度用函数: (smu1113) float lengh(float a,float b)

{

    float len;

    len = a-b;

    if(len<0)  len = -len;

    return len;

}

6.总共有五科成绩,如果一个学生有四科成绩超过(包括=90)90 且不挂科,则是优等生。例如:输入:3

wangwu 83 90 90 90 95

lisi 63 83 90 100 95

liming 90 95 97 98 50

输出:wangwu 83 90 90 90 95

7.在平面上有 N 个点,请找出一个矩形恰好将这些点包容,并且此矩形的边平行坐标轴。4<=N<1000。 (smu1125)

8.平面上有若干个点,每个点有坐标(x,y)和颜色 C。请编程找出给定颜色的点。(smu1352)

9. (smu1145)有若干个老师和学生的数据,学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。可以看出,学生和教师所包含的数据是不同的。现要求把它们放在同一表格中。然后按名字的字典序输出教师与学生的信

233

Page 242: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

息。老师和学生的结构定义如下:struct person

{

 int num;

 char name[10];

 char sex;

 char job;

 union

 {

   int clas;

   char position[10];

 }category;

}per [N];

10.新生报到名单(smu1219)新学期来临,请根据在新生注册时提供的信息,然后根据某一个学号来查找出该学号对应的学生的相

关信息。结构定义如下struct Student

{

       int num;//学号       char name[101];//姓名       int grade;//入学总分       struct Student *next;

};

Sample Input

5

20110201 Lilei 489

20110202 Dale 515

20110203 Edison 526

20110204 Jack 469

20110205 Macy 502

20110204 

Sample Output

你要找到的结果是:20110204 Jack 469

11.先用链表建两个按升幂排列的多项式,再找出同类项。如果有同类项则输出同类项的项数;如果没有则输出“没有找到同类项”。 (smu1292)

12.给出空间中的 n 个点,请你编程找出离原点最远的点和最近的点,最远和最近点都只有一个。(smu1293)

13.有 n 个学生,每个学生有m科成绩。要求在输出每个学生的平均成绩。用指针 函数实现。(smu1323)

234

Page 243: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

14.寻宝人留下的足迹是一串点的坐标。请把这些点建立成横坐标由小到大的链表(如果横坐标同就按纵坐标由小到大排列),并输出。(smu1204)

15.有一色扑克牌 2、3、…、9、10(用 T表示)、J、Q、K、A,随机洗乱后循环分给 3 个人。请编程列出这三个人的牌。(smu1641)设牌的初始顺序是:2、9、J、Q、5、4、3、A、6、7、8、K、T。输出的结果为:甲的牌有 5张,分别是:2 Q 3 7 T

乙的牌有 4张,分别是:9 5 A 8

丙的牌有 4张,分别是:J 4 6 K

16. 口袋中有红、黄、蓝、白、黑 5种颜色的球若干个。每次从口袋中先后取出 3 个球。编程求得到不同颜色但一定含有某一颜色的球的可能取法,并输出结果。球的类型变量 color

是枚举型:enum color{red, yellow, blue, white, black}; (smu1149)17 . 幼 儿 园 的 小 朋 友 每 次 选 出 三 种 颜 色 画 画 。 被 选 的 颜 色 有

{ black,blue,green,grey,orange,purple, red, white, yellow }。请你编程列出小朋友所选出三种颜色(英文单词按字典序从小到大排列)的所有可能。(smu1340)

235

Page 244: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

第 9章 流的输入输出--文件

导学如果读者还有一些时间的话,请学习一下磁盘文件的使用,即将数据保存到文件、从

文件中读取数据、利用输入和输出文件解决交互类型的问题。

9.1 认识文件在前面的章节中,所有的输入输出只涉及到键盘和显示器。但是,对于复杂的程序设

计,仅依赖键盘输入和显示器输出处理数据是完全不够的,比如高校学生的信息管理,可以将这些数据记录在存储介质上,长久保存,这种记录在外部介质上的数据的集合称之为“文件”。

其实,程序开发人员对文件并不陌生,在编写 C语言的简单程序时,就知道在 C编译器中将源程序输入到计算机里去,然后把它们以文件的形式存储到磁盘上,这些文件称之为源程序文件。

C语言中,对于输入、输出的数据都按“数据流”的形式进行处理,也就是说,输出时,系统不添加任何信息,输入时,逐一读入数据,直到遇到 EOF或文件结束标志。C程序中的输入、输出文件,都以数据流的形式存储在介质上。

【例 9.1】小明想将 10000以内的素数保存到文件 c:\prime.txt,请帮忙实现。分析:系统提供了一个文件的类型 FILE,程序员利用文件类型的指针,就可以对文件进行打

开、关闭和读写操作。试读一下【程序清单 9 .1】。【程序清单 9.1】1. #include <stdio.h>

2. #include <stdlib.h>//为了使用 exit(0);

236

Page 245: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

3. #define M 10001 //宏定义 M

4. int p[M]; //全局变量数组 p保存素数数组,值为 1表示下标对应元素为素数,5. //0表示合数6. void prime(int n) //筛选法求素数7. {

8. int i,j;

9. for(i=2;i<n;i++)

10. {

11. p[i] = 1;

12. }

13. for(i=2;i<n;i++)

14. {

15. if(p[i])

16. {

17. for(j=2*i;j<n;j+=i)

18. p[j] = 0;

19. }

20. }

21. }

22. int main()

23. {

24. FILE *fout; //声明文件类型的指针25. int i;

26. void prime(int n);

27. if((fout=fopen("c:\\prime.txt","w"))==NULL) //创建要保存的文件28. {

29. printf("无法创建该文件!\n");

30. exit(0);

31. }

32. prime(M); //待用筛选法处理素数函数33. for(i=2;i<M;i++)

34. {

35. if(p[i])

36. fprintf(fout,"%5d,",i); //把结果保存到文件中37. }

38. printf("请打开 c:\\prime.txt 查看");

39. fclose(fout); //关闭文件40. return 0;

41. }

运行结果为:请打开 c:\prime.txt 查看第 22、25~29、30~36行就是利用文件指针来将素数存入 prime.txt中。第 24行中的 FILE是一种文件类型。在 stdio.h中有这样一段:

237

Page 246: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

#ifndef _FILE_DEFINEDstruct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; };typedef struct _iobuf FILE;#define _FILE_DEFINED#endif

FILE就是这样一种结构类型,结构中变量的意思分别为:struct _iobuf {

char *_ptr;  //文件输入的下一个位置int _cnt;   //当前缓冲区的相对位置char *_base;  //指基础位置(即是文件的其始位置)int _flag;  //文件标志int _file;  //文件的有效性验证int _charbuf;  //检查缓冲区状况,如果无缓冲区则不读取int _bufsiz;  //文件的大小char *_tmpfname;  //临时文件名

};

9.2文件的打开与关闭对文件的操作是通过文件指针进行的,使用前要先定义一个文件类型的指针变量。定

义文件类型指针变量的一般形式为: FILE *指针变量名例如: FILE *f1,*f2;

文件指针在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。定义说明文件指针的一般形式为:FILE *指针变量标识符;

238

Page 247: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

其中 FILE应为大写,它实际上是由系统定义的一个结构,该结构中含有文件名、文件状态和文件当前位置等信息。在编写源程序时不必关心 FILE 结构的细节。指针变量符是指向 FILE 结构的指针变量,通过它可找到存放某个文件信息的结构变量,然后按结构变量提供的信息找到该文件,实施对文件的操作。文件在进行读写操作之前要先打开,使用完毕要关闭。所谓打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作。在C语言中,文件操作都是由库函数来完成的。1.文件打开函数 fopen()

  fopen函数用来打开一个文件,其调用的一般形式为:

文件指针名=fopen(文件名,使用文件方式)

其中,“文件指针名”必须是被说明为 FILE 类型的指针变量,fopen(文件名,使用文件方式) 中的“文件名”是被打开文件的文件名,可以是字符串常量或字符串数组,“使用文件方式”是指文件的类型和操作要求。例如:

FILE *fp;fp=("file1.txt","r");

其意义是在当前文件夹下打开文件 file1.txt, 只允许进行“读”操作,并使 fp指向该文件。又如:FILE *fp2;fp2=("c:\\test1.dat',"rb");

其意义是打开 C驱动器磁盘的根目录下的文件 test1.dat, 这是一个二进制文件,只允许按二进制方式进行读操作。两个反斜线“\\ ”中的第一个表示转义字符,第二个表示根目录。使用文件的方式共有 12种,它们的符号和意义见表 9.1。

表 9.1 文件打开方式文件使用方式 意义“r” 只读打开一个文本文件,只允许读数据“w” 只写打开或建立一个文本文件,只允许写数据“a” 追加打开一个文本文件,并在文件末尾写数据“rb” 只读打开一个二进制文件,只允许读数据“wb” 只写打开或建立一个二进制文件,只允许写数据

239

Page 248: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

“ab” 追加打开一个二进制文件,并在文件末尾写数据“r+” 读写打开一个文本文件,允许读和写“w+” 读写打开或建立一个文本文件,允许读和写“a+” 读写打开一个文本文件,允许读,或在文件末追加数“rb+” 读写打开一个二进制文件,允许读和写“wb+” 读写打开或建立一个二进制文件,允许读和写“ab+” 读写打开一个二进制文件,允许读,或在文件末追加数据对于文件使用方式有以下几点说明:(1)文件使用方式由 r,w,a,t,b,+六个字符拼成,各字符的含义是:r(read): 读w(write): 写a(append): 追加t(text): 文本文件,可省略不写b(banary): 二进制文件+: 读和写(2)凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。(3)用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名

建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。(4) 若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件。但此时该文

件必须是存在的,否则将会出错。(5)在打开一个文件时,如果出错,fopen 将返回一个空指针值 NULL。在程序中可

以用这一信息来判别是否完成打开文件的工作,并作相应的处理。因此常用以下程序段打开文件:

if((fp=fopen("c:\\test1.dat","rb")==NULL){

printf("\n无法打开文件 c:\\test1.dat!");getch();exit(0);

}这段程序的意义是,如果返回的指针为空,表示不能打开 C 盘根目录下的 test1.dat

文件,则给出提示信息“无法打开文件 c:\test1.dat file!”,下一行 getch()的功能是从键盘输入一个字符,但不在屏幕上显示。在这里,该行的作用是等待,只有当用户从键盘敲任一键时,程序才继续执行,因此用户可利用这个等待时间阅读出错提示。敲键后执行

240

Page 249: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

exit(0)退出程序。(6)把一个文本文件读入内存时,要将 ASCII码转换成二进制码,而把文件以文本

方式写入磁盘时,也要把二进制码转换成 ASCII码,因此文本文件的读写要花费较多的转换时间。对二进制文件的读写不存在这种转换。

2.关闭文件 fclose函数当对文件的读(写)操作完成后,必须关闭文件,以避免文件的数据丢失等错误。调用的一般形式是: fclose(文件指针); 例如:fclose(fp);

成功完成关闭文件操作,fclose函数返回值为 0,否则返回非 0。

9.3读写文件的有关函数当成功地打开文件之后,接下来的事情就是去对文件进行输入或输出操作。用 fgetc和

fputc函数可以进行字符的输入和输出 , 用 fgets和 fputs函数可以进行字符串的输入和输出 ,

用 fscanf和 fprintf函数可以对文本文件进行格式输入和输出。1.用 fprintf函数写文件fprintf函数按格式将内存中的数据转换成对应的字符,并以 ASCII代码形式输出到文

本文件中。fprintf函数和 printf函数相似,只是输出的内容将按格式存放在磁盘的文本文件中。函数的调用形式如下:

fprintf(文件指针,格式控制字符串,输出项表)

例如,若文件指针 fp 己指向一个己打开的文本文件,x,y分别为整型变量,则以下语句将把 x和 y 两个整型变量中的整数按%d格式输出到 fp 所指的文件中。

fprtntf(fp,”%d %d”,x,y);

【例 9.2】将以下信息保存到文件 c:\student1.txt。 学号 姓名 性别 年龄 20130703001 张大军 男 19

20130703002 古怀勇 男 18

20130703003 李华萍 女 19

【程序清单 9.2】241

Page 250: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. #include <stdio.h>

2. #include <stdlib.h>//为了使用 exit(0);

3. void main()

4. {

5. FILE *fout;

6. char ch;

7. if((fout=fopen("c:\\student1.txt","w"))==NULL)

8. {

9. printf("无法创建该文件!\n");

10. exit(0);

11. }

12. fprintf(fout,"%s %s %s %s\n","学号","姓名","性别","年龄");

13. fprintf(fout,"%s %s %s %d\n","20130703001","张大军","男",19);

14. fprintf(fout,"%s %s %s %d\n","20130703002","古怀勇","男",18);

15. fprintf(fout,"%s %s %s %d\n","20130703003","李华萍","女",19);

16. fclose(fout);

17. }

本例子执行后,如果没有错误提示,在 C 盘根目录下可以找到 student.txt文件,请打开看内容是否跟题目要求一致。

2.用 fscanf函数读文件

fscanf函数只能从文本文件中按格式输入。fscanf函数和 scanf函数相似,只是输入的对象是磁盘上文本文件中的数据。函数的调用形式如下:

fscanf(文件指什,格式控制字符串,输入项表)

例如,若文件指针 fp 己指向一个己打开的文本文件,a、b分别为整型变量,则以下语句从 fp 所指的文件中读入两个整数放入变量 a和 b中:

fscanf(fp,”%d%d”,&a,&b);

【例 9.3】将例 9.2创建的文件 student1.txt内容显示在屏幕上。【程序清单 9.3】1. #include <stdio.h>

2. #include <stdlib.h>

3. void main()

4. {

5. FILE *fout;

6. char ch;

7. char title[101],sno[20],sname[10],sgender[10];

8. int sage;

9. if((fout=fopen(“c:\\student1.txt”,”r”))==NULL)

242

Page 251: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

10. {

11. printf(“无法读取该文件!\n”);

12. exit(0);

13. }

14. fgets(title,100,fout); //对标题行单独处理,因为有多个空格,用 fgets 比 fscanf

//更合适,fgets函数后面有详细介绍15. printf(“%s”,title);

16. while(fscanf(fout,”%s %s %s %d”,sno,sname,sgender,&sage)!=EOF)

17. {

18. printf(”%s %s %s %d\n”,sno,sname,sgender,sage);

19. }

20. fclose(fout);

21. }

运行结果为:学号 姓名 性别 年龄

20130703001 张大军 男 19

20130703002 古怀勇 男 18

20130703003 李华萍 女 19

3.调用 fputc函数写文件 fputc函数的调用形式如下: fputc(ch,fp);这里 ch是待输出的某个字符,它可以是一个字符常量,也允许是一个字符变量。fp是

文件指针。fputc(ch,fp)的功能是将字符 ch写到文件指针 fp 所指的文件中去。当输出成功,fputc函数返回所输出的字符;如果输出失败,则返回一个 EOF 值。

【例 9.4】将 9.1的内容从键盘输入保存到文件 c:\student2.txt,用#作为输入结束标志。【程序清单 9.4】1. #include <stdio.h>

2. #include <stdlib.h>

3. void main()

4. {

5. FILE *fout;

6. char ch;

7. if((fout=fopen(“c:\\student2.txt”,”w”))==NULL)

8. {

9. printf(“无法创建文件!\n”);

10. exit(0);

11. }

12. ch = getchar();

243

Page 252: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

13. while(ch!=’#’)

14. {

15. fputc(ch,fout);

16. ch = getchar();

17. }

18. fclose(fout);

19. }

4.调用 fgetc函数读文件 fgetc函数的调用形式如下: ch=fgetc(fp);此处 fp是文件指针;函数的功能是从 fp指定的文件中读入一个字符,并把它作为函数

返回值。以上表达式中 fgetc函数把从文件中读入的一个字符赋给变量 ch。【例 9.5】将 student2.txt文件中的内容输出到屏幕。【程序清单 9.5】1. #include <stdio.h>

2. #include <stdlib.h>

3. void main()

4. {

5. FILE *fin;

6. char ch;

7. if((fin=fopen(“c:\\student2.txt”,”r”))==NULL)

8. {

9. printf(“无法打开文件!\n”);

10. exit(0);

11. }

12. ch=fgetc(fin);

13. while(ch!=EOF)

14. {

15. putchar(ch);

16. ch = fgetc(fin);

17. }

18. fclose(fin);

19. }5.用 fgets函数读文件fgets函数用来从文件中读入字符串。调用形式如下:fgets(str,n,fp);fp是文件指针;str是存放字符串的起始地址;n是一个 int类型变量。函数的功能是从

244

Page 253: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

fp 所指文件中读入 n-1 个字符放入 str为起始地址的空间内:如果在未读满 n-1 个字符之时,已经读到一个换行符或一个 EOF〔文件结束标志),则结束本次读操作。因此,确切地说,调用 fgets函数时,最多只能读入 n-1 个字符。读入结束后,系统将自动在最后加’\0’,并以 str作为函数值返回。

6.用 fputs函数写文件fputs函数用来把字符串输出到文件中。调用格式如下:fputs(str,fp);

fp是文件指针;str是待输出的字符串,可以是字符串常量、指向字符串的指针或存放字符串的字符数组名等。输出成功函数值为非 0,否则为 0。

9.4二进制文件二进制文件是按二进制的编码方式来存放文件的。二进制文件直接用记事本打开的话,

其内容可能为乱码,无法读懂。C系统在处理这些文件时,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作“流式文件”。跟二进制文件操作有关的函数主要有 feof()、fread()、fwrite()。(1)文件结束检测函数 feof函数调用格式: feof(文件指针);

功能:判断文件是否处于文件结束位置,如文件结束,则返回值为 1,否则为 0。(2)fread和 fwrite函数fread和 fwrite函数用来读、写二进制文件。它们的调用形式如下: fread( buffer,size,count,fp); fwrite(buffer,size,count,fp);其中,buffer是数据块的指针,对 fread来说,它是一个内存块的首地址,输入的数据

存入这个内存块中;对于 fwrite来说,它是准备输出的数据块的起始地址;size:表示每个数据块的字节数;count:用来指定每读、写一次,输入或输出数据块的个数(每个数据块具有 size 字节);fp:文件指针。

【例 9.6】将以下信息保存到二进制文件 c:\student1.dat,然后重新打开该文件把年龄为 19

245

Page 254: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

岁的学生信息显示在屏幕上。student1.dat文件内的数据:

20130703001 张大军 男 19

20130703002 古怀勇 男 18

20130703003 李华萍 女 19

【程序清单 9.6】1. struct Student

2. {

3. char sno[20];

4. char sname[10];

5. char sgender[10];

6. int sage;

7. };

8. #include <stdio.h>

9. #include <stdlib.h>

10. void main()

11. {

12. FILE *fout,*fin;

13. int i;

14. struct Student stu[3]={"20130703001","张大军","男",19,

15. "20130703002","古怀勇","男",18,

16. "20130703003","李华萍","女",19

17. },stu2;

18. if((fout=fopen("c:\\student1.dat","wb"))==NULL)

19. {

20. printf("无法创建该文件!\n");

21. exit(0);

22. }

23. for(i=0;i<3;i++)

24. {

25. fwrite(&stu[i],sizeof(struct Student),1,fout);

26. }

27. fclose(fout);

28. if((fin=fopen("c:\\student1.dat","rb"))==NULL)

29. {

30. printf("无法读取该文件!\n");

31. exit(0);

32. }

33. while(fread(&stu2,sizeof(struct Student),1,fin))

34. {

35. if(stu2.sage==19)

36. printf("%s %s %s %d\n",stu2.sno,stu2.sname,stu2.sgender,stu2.sage);

37. }

246

Page 255: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

38. fclose(fin);

39. }

运行的结果为:20130703001 张大军 男 19

20130703003 李华萍 女 19

提示:从例 9.5与例 9.1对比可以看出,用二进制文件来处理学生信息比用文本文件方便,可以很好的处理结构体数据,并能避免字符串之间空格个数不一致的麻烦,还可利用关键字进行查找与排序。另外,用记录方式保存信息比用文本方式通常能节省空间。

9.5随机读写文件对文件输入输出方式也称“存取方式”。C语言中,有两种对文件的存取方式:顺序存

取和直接存取。顺序存取文件的特点是:每当“打开”这类文件,进行读或写操作时,总是从文件的

开头开始.从头到尾顺序地读或写;也就是说当顺序存取文件时,要读第 M 个字节时,先要读取前M-1 个字节,而不能一开始就读到第M 个字节;要写第M 个字节时,先要写前M-1 个字节。

直接存取文件又称随机存取文件,其特点是:可以通过调用 c语言的库函数去指定开始读(写)的字节号,然后直接对此位置上的数据进行读(写)操作。前几节介绍的对文件的读写方式都是顺序读写,即读写文件只能从头开始,顺序读写。

但在实际问题中常要求只读写文件中某一指定的部分。为了解决这个问题可移动文件内部的位置指针到需要读写的位置,再进行读写,这种读写称为随机读写。实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。文件定位移动文

件内部位置指针的函数主要有两个,即 rewind 函数和 fseek函数。rewind函数调用形式为:rewind(文件指针);它的功能是把文件内部的位置指针移到文

件首。

fseek函数用来移动文件内部位置指针,其调用形式为:fseek(文件指针,位移量,起始点);

其中:“文件指针”指向被移动的文件。“位移量”表示移动的字节数,要求位移量

247

Page 256: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

是 long型数据,以便在文件长度大于 64KB 时不会出错。当用常量表示位移量时,要求加后缀“L”。“起始点”表示从何处开始计算位移量,规定的起始点有三种:文件首,当前位置和文件尾。其表示方法如表 9.2。

表 9.2 文件指针起始点说明起始点 表示符号 数字表示文件首 SEEK_SET 0

当前位置 SEEK_CUR 1

文件末尾 SEEK_END 2

例如:fseek(fp,100L,0);其意义是把位置指针移到距离文件首部 100 个字节的地方。fseek函数

一般用于二进制文件。在文本文件中由于要进行转换,故往往计算的位置会出现错误。文件的随机读写在移动位置指针之后,即可用前面介绍的任一种读写函数进行读写。由于一般是读写一个数据块,因此常用 fread和 fwrite函数。

9.6案例及分析【例 9.7】将【例 9.6】创建的文件 student1.dat复制到 student2.dat。分析:分别用指针 fin指向 student1.dat,fout指向 student2.dat进行读写操作,用 feof 判断文件

是否到结尾。当文件未到结尾时,fread函数每次读取源文件的一条记录存到结构体变量 stu

中,fwrite函数把该记录存储到目标文件中。【程序清单 9.7】1. struct Student

2. {

3. char sno[20];

4. char sname[10];

5. char sgender[10];

6. int sage;

7. };

8. #include <stdio.h>

9. #include <stdlib.h>

10. void main()

11. {

248

Page 257: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

12. FILE *fout,*fin;

13. struct Student stu;

14. if((fin=fopen("c:\\student1.dat","rb"))==NULL)

15. {

16. printf("无法读取该文件!\n");

17. exit(0);

18. }

19. if((fout=fopen("c:\\student2.dat","wb"))==NULL)

20. {

21. printf("无法创建该文件!\n");

22. exit(0);

23. }

24. while(!feof(fin))

25. {

26. fread(&stu,sizeof(struct Student),1,fin);

27. fwrite(&stu,sizeof(struct Student),1,fout);

28. }

29. fclose(fin);

30. fclose(fout);

31. }

【例 9.8】将 student2.dat的第二条记录删除。分析:将源文件以即读又写方式打开,文件指针指向第三条记录,然后把第三条记录之后的

所有记录写入到第二条记录开始的地方。【程序清单 9.8】1. struct Student

2. {

3. char sno[20];

4. char sname[10];

5. char sgender[10];

6. int sage;

7. };

8. #include <stdio.h>

9. #include <io.h>

10. #include <stdlib.h>

11. void main()

12. {

13. FILE *fin;

14. int i;

15. struct Student stu[100];

16. if((fin=fopen("c:\\student2.dat","r+b"))==NULL)

249

Page 258: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

17. {

18. printf("无法读取该文件!\n");

19. exit(0);

20. }

21. i=0;

22. fseek(fin,sizeof(struct Student)*2,SEEK_SET);//指针定位到第三条记录处23. while(fread(&stu[i],sizeof(struct Student),1,fin))

24. {

25. i++; //统计满足条件记录个数26. }

27. fseek(fin,sizeof(struct Student)*1,SEEK_SET); //指针定位到第二条记录处28. fwrite(stu,sizeof(struct Student),i,fin);//把后 i条记录写入文件29. chsize(fileno(fin),sizeof(struct Student)*(i+1));//改变文件大小,如果没有本语句,

//源文件结尾会有一条重复的垃圾记录30. fclose(fin);

31. }

提示:本例直接在 student2.dat文件操作,由于删除数据后文件变小,为了避免文件末尾产生垃圾记录,要用 chsize函数来修改文件大小,该函数原型在 io.h中。如果想避免这种麻烦,也可以另外定义一个文件 student3.dat,先把满足条件的记录写入 student3.dat,然后把 student3.dat的内容重新复制到 student2.dat。

9.7 进阶本章的进阶主要介绍图像文件的拷贝。典型的 BMP 图像文件由四部分组成:(1)位图头:保存位图文件的总体信息,也就是图像文件的识别信息,应用程序会首

先读取这部分数据以确保打开的文件是位图文件并且没有损坏。(2)位图信息:保存位图图像的详细信息,在屏幕上显示图像将会使用这些信息;它

从文件的第 15 个字节开始。(3)调色板:保存所用颜色的定义,在 RGB模型中,每种颜色都是由不同强度(从

0到最大强度)的红色(R)、绿色(G)和蓝色(B)组成的,也就是说,每种颜色都可以使用红色、绿色和蓝色的值所定义。(4)位图数据,保存实际图像的每一个像素的值;这部分的内容根据 BMP位图使用

的位数不同而不同,在 24位图中直接使用 RGB,而其他的小于 24位的使用调色板中颜色

250

Page 259: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

索引值。位图头占 14 个字节。字节 #0-1 :保存位图文件的标识符,这两个字节的典型数据是 BM。字节 #2-5 :使用一个 dword保存位图文件大小。字节 #6-9 :是保留部分,留做以后的扩展使用,对实际的解码格式没有影响。字节 #10-13: 保存位图数据位置的地址偏移,也就是起始地址。位图信息占 40 个字节。字节 #14-17: 定义用来描述图像区块(BitmapInfoHeader)的大小。它的值是:40 -

Windows 3.2、95、NT、12 - OS/2 1.x、240 - OS/2 2.x。字节 #18-21 :保存位图宽度(以像素个数表示)。字节 #22-25: 保存位图高度(以像素个数表示)。字节 #26-27: 保存所用彩色位面的个数。不经常使用。字节 #28-29: 保存每个像素的位数,它是图像的颜色深度。常用值是 1、4、8(灰阶)

和 24(彩色)。字节 #30-33 :定义所用的压缩算法。允许的值是 0、1、2、3、4、5。0 表示没有压缩(也用

BI_RGB表示),1表示行程长度编码 8位/像素(也用 BI_RLE8表示),2 表示行程长度编码 4位/像素(也用 BI_RLE4表示),3 –Bit field(也用 BI_BITFIELDS表示),4 - JPEG

图像(也用 BI_JPEG表示),5 - PNG 图像(也用 BI_PNG表示)。字节 #34-37 保存图像大小。这是原始(en:raw)位图数据的大小,不要与文件大小混

淆。字节 #38-41 保存图像水平方向分辨率。字节 #42-45 保存图像竖直方向分辨率。字节 #46-49 保存所用颜色数目。字节 #50-53 保存所用重要颜色数目。当每个颜色都重要时这个值与颜色数目相等。

【任务 9.1】图像处理是非常普通和重要的任务。请你编程将一个名为 source.bmp的 BMP

图像文件打开,并储存至文件名为 target.bmp的图像文件中。分析:这是图像文件的读写。操作的顺序是先定义源文件和目标文件的指针,按图像的数据

结构定义相应的变量;通过文件指针打开源文件,读取文件信息;打开目标文件,写入信

251

Page 260: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

息;最后关闭文件指针。请仔细阅读【程序清单 9.9】,理解 bmp文件中的文件头信息、RGB

信息、图像的长宽等信息。【程序清单 9.9】1. #include <stdio.h>

2. #include <stdlib.h>

3. int image_open(const char *file_source, const char *file_target)

4. {

5. FILE *fp_source = NULL; // 源文件指针初始化6. FILE *fp_target = NULL; // 目标文件指针初始化7. unsigned int i,j;

8. unsigned int height, width; // 定义变量 height, width为图像尺寸的长及宽9. unsigned char *image_source = NULL; //源图像指针变量10. unsigned char *image_target = NULL; // 目标图像指针变量11. unsigned char R, G, B; // 定义三个变量储存图像中的三种颜色(R,G,B)信息12. unsigned int avg_hei; // 长度平均值13. unsigned int inv_hei; // 反向垂直轴数值14. unsigned char header[54] = { //利用数组变量储存图像标头文件的必要信息,即位图头和位

图信息15. 0x42,

16. 0x4d,

17. 0, 0, 0, 0,

18. 0, 0,

19. 0, 0,

20. 54, 0, 0, 0,

21. 40, 0, 0, 0,

22. 0, 0, 0, 0,

23. 0, 0, 0, 0,

24. 1, 0,

25. 24, 0,

26. 0, 0, 0, 0,

27. 0, 0, 0, 0,

28. 0, 0, 0, 0,

29. 0, 0, 0, 0,

30. 0, 0, 0, 0,

31. 0, 0, 0, 0

32. };

33. unsigned int image_size; // 定义变量作为图像大小34. unsigned int rgb_offset; // RGB起始的位移量35. fp_source = fopen(file_source, "rb"); // 利用 rb模式打开一个变量 file_source 所指的文件36. if (fp_source == NULL) // 若源文件指针为NULL,则输出提示字符串37. {

38. printf("文件读取错误\n");

252

Page 261: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

39. return -1;

40. }

41. fseek(fp_source, 10, SEEK_SET); // 利用文件搜寻函数 fseek,将源文件指针移 10 个字节来读取 RGB起始的位移量

42. fread(&rgb_offset, sizeof(unsigned int), 1, fp_source);

43. //将源文件指针移 18 个字节来读取图像的长及宽44. fseek(fp_source, 18, SEEK_SET);

45. fread(&width, sizeof(unsigned int), 1, fp_source);

46. fread(&height, sizeof(unsigned int), 1, fp_source);

47. // 移动位移值至 rgb_offset,读取图像 RGB原始数据48. fseek(fp_source, rgb_offset, SEEK_SET);

49. //为源图像指针变量动态配置内存50. image_source = (unsigned char *)malloc((size_t)width * height * 3);

51. if (image_source == NULL) // 若源图像指针为NULL,则输出提示字符串52. {

53. printf("源图像配置内存错误\n");

54. return -1;

55. }

56. //为目的图像指针变量动态配置内存57. image_target = (unsigned char *)malloc((size_t)width * height * 3);

58. if (image_target == NULL) //若目标图像指针为NULL,则输出提示字符串59. {

60. printf("目的图像配置内存错误\n");

61. return -1;

62. }

63. fread(image_source, sizeof(unsigned char), (size_t)(long)width * height * 3, fp_source);

64. // 读取每一个像素并储存颜色数值65. avg_hei = height-1;

66. for(j = 0; j != height; ++j)

67. {

68. for(i = 0; i != width; ++i)

69. {

70. R = *(image_source + 3 * (width * j + i) + 2);

71. G = *(image_source + 3 * (width * j + i) + 1);

72. B = *(image_source + 3 * (width * j + i) + 0);

73. inv_hei = j;

74. *(image_target + 3 * (width * inv_hei + i) + 2) = R;

75. *(image_target + 3 * (width * inv_hei + i) + 1) = G;

76. *(image_target + 3 * (width * inv_hei + i) + 0) = B;

77. }

78. }

79. //开启一新的文件来储存 bmp 图档80. fp_target = fopen(file_target, "wb"); //利用wb模式打开一个变量 file_target 所指的文件81. if (fp_target == NULL) //若目标文件指针为NULL,则输出提示字符串

253

Page 262: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

82. {

83. printf("文件读取错误\n");

84. return -1;

85. }

86. image_size = width * height * 3 + rgb_offset; // 定义图像完整尺寸大小87. header[2] = (unsigned char)(image_size & 0x000000ff);

88. header[3] = (image_size >> 8) & 0x000000ff;

89. header[4] = (image_size >> 16) & 0x000000ff;

90. header[5] = (image_size >> 24) & 0x000000ff;

91. //定义图像宽度92. header[18] = width & 0x000000ff;

93. header[19] = (width >> 8) & 0x000000ff;

94. header[20] = (width >> 16) & 0x000000ff;

95. header[21] = (width >> 24) & 0x000000ff;

96. // 定义图像长度97. header[22] = height &0x000000ff;

98. header[23] = (height >> 8) & 0x000000ff;

99. header[24] = (height >> 16) & 0x000000ff;

100. header[25] = (height >> 24) & 0x000000ff;

101. // 输出图像标头文件102. fwrite(header, sizeof(unsigned char), rgb_offset, fp_target);

103. // 输出图像文件104. fwrite(image_target, sizeof(unsigned char), (size_t)(long)width * height * 3, fp_target);

105. fclose(fp_source); //文件处理完毕,关闭源文件指针106. fclose(fp_target); //文件处理完毕,关闭目标文件指标107. return 0;

108. }

109. //主程序中,调用已定义的子函数 image_open来开启一个文件名为 source.bmp的图像文件,并储存至文件名为 target.bmp的图像文件

110. int main()

111. {

112. image_open ("source.bmp", "target.bmp");

113. }

运行前将 source.bmp文件放在程序的当前文件夹下,运行后将在这个文件夹下增加一个复制的 target.bmp文件。程序说明:本案例主要目的在于利用标准 C语言来打开一个已知文件名称的 bmp 图像,并储存至

另一个新的 bmp文件中。其中 image_open用于打开图像文件,输入参数为:源文件名称及目标文件名称的字符串; 程序中的第 14~32行定义的数组变量 header用于定义图像标头文件的必要信息:图像颜色格式,尺寸大小,颜色排列方式(使用何种算法),RGB颜色的

254

Page 263: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

位移值,bmp 信息标头文件,bmp文档的长及宽,平面位,单一像素所使用位数,压缩信息,数据大小,水平及垂直分辨率,使用的颜色数目,及重要颜色等信息。程序中第 41~48

行利用搜寻函数 fseek来搜寻图像标头文件中相关信息,并储存。利用读取的图像大小来动态配置源图像及目标图像的内存。程序的第 66~78行根据反向算法从像素读取源图像中的颜色信息,并按序储存至目标图像中。程序的第 86~100行则定义图像长宽及尺寸大小相关信息。最后在主程序中直接调用已定义的开启图像文件的子程序即完成一个利用指针变量来读取及输出图像的程序功能。本程序主要内容含指针、文件处理、图像文件的数据结构。本例重点是在使读者能体会图像文件的处理,相关的C语言内容,可自行参照本书其它章节。

255

Page 264: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

习题1. 将文本文件 student1.txt复制到 student3.txt

student1.txt文件内容如下:申请国外大学如何请老师写推荐信呢?相信众多学生都在为请老师写推荐而烦恼。请老师写推荐信并不

是难事,要想成功得到推荐信,充分的准备是必要的。如在邮件最后附上个人简历,及时和老师沟通等等。一起来看看吧。相信大家一定会收成良多。  我最初的思路是:  1. 先感谢老师在课堂上付出的时间,表示自己收成很大;  2. 然后写想申请某某大学的研究生项目;  3. 最后表示但愿教授能为自己写一份推荐信。  后来我溘然意识到这是一个完全错误的顺序。有人玩笑说,西方人读东方人的信函要从下往上读,不然完全不知所云,由于来信真正的目的往往泛起在最末尾。这样说不是毫无道理。东方人重蕴藉,西方人喜直接,这是东西方思维习惯上的迥异。所以尊重西方人的习惯,终极成文的顺序正好相反,倒置成 3.2.1。字体可用Arial,5 号。2. 在 student1.dat的第三条记录之前插入一条记录,内容为:

20120703037 陈文静 女 20

student1.dat原来的内容如下:学号 姓名 性别 年龄20130703001 张大军 男 19

20130703002 古怀勇 男 18

20130703003 李华萍 女 19

3. 从键盘输入 10 个字符串保存到文件 test1.txt,再从此文件中读入这 10 个字符串放在一个字符串数组中;最后把字符串数组中的字符串输出到终端屏幕。

4. 从键盘输入 10 个浮点数,以二进制形式存入文件 test2.dat。再从此文件读出数据显示在屏幕上。

5. 把文本文件 test3.txt中的小写字母改为大写字母。test3.txt文件内容如下:

Professor David Greenaway took up office as the sixth Vice-Chancellor of The University of Nottingham in

2008. He was appointed to the University as a Professor of Economics in 1987 and was previously a Dean, a Pro-

Vice-Chancellor, and founding Director of the Leverhulme Centre for Research on Globalisation and Economic

Policy. He is a Member of the Government's Asia Task Force and Higher Education Task Force and a Deputy

Lieutenant of Nottinghamshire. In 2012, Professor Greenaway was made an Honorary Citizen of the City of

Ningbo in China. He is currently leading 'Shape of Training', a national review of the training and professional

development of Doctors in the UK, being coordinated by the General Medical Council.

6. 有文件 file1.txt和 file2.txt,请将 file2.txt连接到 file1.txt后面形成新的 file1.txt。file1.txt文件内容如下:

256

Page 265: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

DESCRIPTION flex is a tool for generating scanners: programs which recognized lexical patterns in text. flex reads the given input files, or its standard input if no file names are given, for a description of a scanner to generate. The description is in the form of pairs of regular expressions and C code, called rules. flex generates as output a C source file, lex.yy.c, which defines a routine yylex(). This file is compiled and linked with the -lfl library to produce an executable. When the executable is run, it analyzes its input for occurrences of the regular expressions. Whenever it finds one, it executes the corresponding C code.

file2.txt文件内容如下:SOME SIMPLE EXAMPLES

First some simple examples to get the flavor of how one uses flex. The following flex input specifies a scanner which whenever it encounters the string "username" will replace it with the user's login name:

%% username printf( "%s", getlogin() );By default, any text not matched by a flex scanner is copied to the output, so the net effect of this scanner is to copy its input file to its output with each occurrence of "username" expanded. In this input, there is just one rule. "username" is the pattern and the "printf" is the action. The "%%" marks the beginning of the rules. Here's another simple example: int num_lines = 0, num_chars = 0; %% \n ++num_lines; ++num_chars; . ++num_chars; %% main() { yylex(); printf( "# of lines = %d, # of chars = %d\n", num_lines, num_chars ); }This scanner counts the number of characters and the number of lines in its input (it produces no output other than the final report on the counts). The first line declares two globals, "num_lines" and "num_chars", which are accessible both inside yylex() and in the main() routine declared after the second "%%". There are two rules, one which matches a newline ("\n") and increments both the line count and the character count, and one which matches any character other than a newline (indicated by the "." regular expression).

7. 有 10 个学生,每个学生有 3门课的成绩,从键盘输入数据(包括学生号、姓名、3门课

257

Page 266: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

的成绩),计算出平均成绩,将原有数据和计算机的平均成绩存放在磁盘文件student.dat中。

258

Page 267: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附录 A 关键字

ANSI C 标准 C语言共有 32 个关键字,这些关键字如表A.1 所示:表A.1 C语言的关键字表

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 union unsigned void

volatile while

1999年 12月 16日,ISO推出了 C99 标准,该标准新增了 5 个 C语言关键字:Inline restrict Bool Complex Imaginary

2011年 12月 8日,ISO发布 C语言的新标准 C11,该标准新增了 1 个 C语言关键字:Generic

259

Page 268: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附录 B 常见错误

1. 一个程序中出现多个主函数C语言规定一个程序只能有一个 main函数,否则出错信息为:function main() already has a body

2. 语句结尾漏掉分号C语言规定每个语句(不是每行)的结束要加分号。语法错误提示关键字:missing ';' before identifier

3. 变量重复定义C语言规定在同一区域不允许出现同名变量语法错误提示关键字:变量名 redefinition

4. 变量使用前未定义或标识符大小写不一致C语言规定任何变量都必须在使用前定义,否则编译时会出错。C语言严格区分大小字

符,标识符大小写也有严格区别,习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。语法错误提示关键字:变量名 undeclared identifier

5. 输入输出的数据的类型与所用格式说明符不一致6. 调用系统函数没有加对应的头文件在调用系统函数时必须在#include命令中包含相应的头文件*.h。语法错误提示关键字:函数名 undeclared identifier

7. 忘记使用地址符号“&”

scanf语句要求格式控制串后面跟的是地址列表,对于普通变量要加地址符号“&”。否则运行结果会出错。这个错误没有提示信息,需要同学们着重检查。8. “=”与“==”混淆

“=”是赋值运算符,“==”是关系运算符;误用会造成严重后果。特别是在 if语句的条件表达式中,如果“==”误写成“=”,将造成条件式永远成立或永远不成立。

260

Page 269: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

错误例子:if(s=0)a=1;条件永远为假,不管 s是否为 0,赋值语句都不会执行。 if(s=3)a=7;条件永远为真,不管 s是否为 3,赋值语句都会执行,a变为 7。前面二例,编译器均不报错,如果写成 if(3=s)a=7,则容易发现错误。

9. “&”与“&&”,“|”与“||” 混淆逻辑“与”的运算需要两个字符“&&”,逻辑“或”运算也是两个字符“||”,如果是

单个的字符,含义就完全不同了。如:if(a&& b)误写为 if(a & b)条件式中的关系与运算会变为位运算中的与运算,结

果大不相同。10. 花括号的使用在选择语句或循环语句一个子句,若需要执行的语句有多条,应加花括号成为复合语

句,如缺少花括号,会导致整个逻辑错误。为了养成良好的程序设计习惯,可以在每种逻辑条件执行语句加花括号(单条语句也如此,避免以后修改循环体代码后遗漏花括号)。11. switch语句每个 case后缺少 break语句,会执行下面的 case语句,从而造成运行

结果混乱。12. switch语句的 case分支中缺少常量表达式语法错误提示关键字:expected constant expression

13. for循环或while循环多加分号for循环或while循环的循环语句一般写在底下一行,如果在第一行多加分号,会造

成循环体为空语句,导致循环什么都不做,甚至可能造成死循环。例:for(sum=0,k=1;k<=100;k++);sum+=k;

14. 在做累加或连乘时没有进行初始化累加的初值应为 0、连乘的初值应为 1。

15. 引用数组元素下标越界C语言数组下标从 0开始,例如:当定义一个数组长度为 100 时,下标只能从 0取到

99,不能取为 100,否则会造成下标越界,出现结果异常。16. 超大的数组定义成局部变量

如果超大的数组被定义成局部变量,则很容易出现 Runtime Error,定义成全局变量

261

Page 270: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

即可。17. 程序代码出现非法的汉字或中文标点符号语法错误提示关键字:unknown character '0xa3'

18. 函数缺少返回值非 void函数必须要有对应的返回值语法警告提示关键字:no return value

19. 程序还没停止运行又重新编译运行在程序代码修改后,要重新运行前要确保上一次的运行已经关闭语法错误提示关键字:cannot open Debug/TEST1.exe for writing

262

Page 271: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附录 C 程序调试

程序调试也叫Debug 。Bug原意是小虫,这里指程序中的错误,Debug就是测试程序,查找错误的过程。

1. 对于语法错误,我们常用:(1) 查看提示,查找错误所在的行;(2) 查看书上对语句及格式的描述。

2. 对于逻辑错误,我们常用:(1)按{}查程序块(2)查变量的位置,初始化的位置;(3)查条件判断。

3. 对于结果的错误,常用:(1)设断点,查变量的值。(2)分断排除

4. 利用VC中Debug手段查错在VC中提供了Debug的工具,各按钮的功能如图 C.1和图 C.2 所示:

263

Page 272: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 C.1 Debug工具

264

Page 273: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 C.2 Debug工具 使用Debug 调试程序最有效的手段有设置断点、单步执行和观察数据变化。(1)设置断点:设置的某一位置,强制程序执行到该位置暂时停止运行。如图 C.3 所示。

图 C.3 断点的设置与取消按钮

(2)分步执行,有一组的按钮:

:单步执行程序,若遇见函数调用语句,则进入调用函数的内部。单击 Debug工具栏上的 Step Into按钮(快捷键为 F11)也可以完成该功能。

:单步执行程序,若遇见函数调用语句,不进入调用函数的内部,跳过该函数。单击Debug工具栏上的 Step Over按钮(快捷键为 F10)也可以完成该功能。

:从当前的函数中跳出,有时无意进入某个不想跟踪的函数,可单击 Debug工具栏上的 Step Out按钮,此时光标将指向该函数调用结束后要执行的语句。

:运行到光标处。可以按键盘中的 Ctrl+F10。(3)查看变量值的具体实现先在要找问题的范围设置断点,一般是某个函数、某个循环。打开Watch窗口,输入要查看的变量名,数组或结构体可直接输入名字,会自行展开。再按步运行,同时查看变量的值。

【样例 1】赋初值及初值的位置错误【调试代码 1】

265

Page 274: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

1. //求输入若干个数的和2. #include <stdio.h>3. int main()4. {5. int x,sum;6. while(scanf("%d",&x)!=EOF)//每次读入一个数,读到文件尾7. {8. sum += x;//求和9. }10. printf("sum=%d\n",sum);11. return 0;12. }

运行过程为:2 3 4

^Z

sum=-858993451

而期待的是 sum=9

调试过程:(1)在第 8行设置断点,也就是程序调试期间暂停的位置,方法是将光标移到行首,

按下“ ”(或快捷键 F9)即可在该行设下断点;

(2)按 运行(或快捷键 F5);(3)在控制台窗口中输入 2 3 4;(4)观察 sum的值,如图 C.4 所示,sum的初值不是预期的 0。

图 C.4 查看变量的值(5)按按钮(或组合键 Shift+F5)停止调试;(6)修改第 4行为:int x,sum=0;

(7)按 重新开始,结果正确。注意:输入的数据在运行窗口一出现时就要粘贴进去,或用 freopen(“input.in”,”r”,stdio)

语句把数据放在 input.in的文件中。对于 scanf()这样的函数不想看详细的读入数据过程,就

266

Page 275: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

选 执行。【样例 2】条件判断的错误,如:if(x=0)。【调试代码 2】1. //判断 x是否为 02. #include <stdio.h>3. int main()4. {5. int x;6. while(scanf("%d",&x)!=EOF)7. {8. if(x=0) 9. printf("x=0\n");10. else11. printf("x!=0\n");12. }13. return 0;14. }

运行过程为:0

x!=0

2

x!=0

3

x!=0

也就是当 x=0 时,运行结果不对。调试过程:(1)设置断点,用 运行程序,如图以.5 所示:

图 C.5 调试过程图发现 if(x=0)语句没有执行。

267

Page 276: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

(2)改成 if(x==0)重新调试。【样例 3】数组问题【调试代码 3】1. //************2. //*将数组 *3. //*1 2 3 *4. //*4 5 6 *5. //*转成 *6. //*1 4 *7. //*2 5 *8. //*3 6 *9. //************10. #include <stdio.h>11. int main()12. {13. int i,j,a[2][3]={{1,2,3},{4,5,6}};14. for(i=1;i<=2;i++)15. {16. for(j=1;j<=3;j++)17. printf("%d ",a[i][j]);18. printf("\n");19. }20. return 0;21. }

运行结果为:5 6 3

2 1245120 4199081

调试过程:(1)输出的行列不对,先让 i进行 3 次循环,j进行两次循环。改 14~19行为:

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

for(j=1;j<=2;j++)printf("%d ",a[j][i]);

printf("\n");}

运行结果为:5 1

6 1245120

1 4199081

268

Page 277: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

对应的数据不对,出现未知数据;(2)设断点,进入调试后,先查看数组的 a的数据情况。在watch窗口输入数组变量 a,再展开,如图 C.6 所示。

图 C.6 调试过程图发现:数组 a的行下标是 0、1,列下标是 0、1、2

(3)改循环变量 i、j的初始值和终值成:for(i=0;i<3;i++)

{for(j=0;j<2;j++)

printf("%d ",a[j][i]);//j指行、i指列printf("\n");

}(4)再调试和运行,得正确结果:

1 4

2 5

3 6

【样例 4】指针无空间问题【调试代码 4】1. //用指针变量处理字符串2. #include <stdio.h>3. #include <stdlib.h>

269

Page 278: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

4. #include <string.h>5. int main()6. {7. char *str,*p;//定义两个字符指针8. int i,L;9. strcpy(str,"abcd");//对 str 赋值10. p = str;11. L = strlen(str);12. for(i=0;i<L;i++)13. printf("%c",*(p+i));14. printf("\n");15. return 0;16. }

运行后,弹出窗口如图 C.7 所示:

图 C.7 指针变量无使用空间的出错窗口一般指针变量无空间就使用时,编译和链接都不会出错,而是弹出窗口让你去调试。

这是无法调试,只能为它先申请空间。也就是在第 8行前加上一句:str = (char *)malloc(10*sizeof(char));

就可以。你再进入 debuge来查看,可以看到:申请空间前 p、str的地址如图 C.8 所示:

图 C.8 p、str地址申请空间后的 p、str地址如图 C.9 所示:

图 C.9 申请空间后的 p、str地址对 str 赋值后的 p、str地址如图 C.10 所示:

270

Page 279: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

图 C.10 对 str 赋值后的 p、str地址执行 p = str;后的 p、str地址如图 C.11 所示:

图 C.11 执行 p = str;后的 p、str地址【样例 5】查看建立好的链表在【程序清单 8.5】执行完 creat()函数后,我们可以查看链表的情况。你逐个把 next前的

“+”点开,如图 C.12 所示。

图 C.12 链表的结构调试(debug)只是一个工具,是一个展示程序运行过程中变量值及地址的一个工具,

不能直接告诉你是什么错。你得根据设计程序的逻辑,以及期待出现的结果进行观察和判断。但是不会使用 debug工具,是无法对一个复杂的、较长的代码进行调试的。当然,有时

271

Page 280: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

你可以在适当的位置加上输出语句来查看个别变量的结果,但不能替代整个 debug的功能。

272

Page 281: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附录 D 库函数

库函数并不是 C语言的一部分,它是由人们根据需要编制并提供用户使用的。每一种 C

编译系统都提供了一批库函数,不同的编译系统所提供的库函数的数目和函数名以及函数功能是不完全相同的。ANSI C 标准提出了一批建议提供的标准库函数,它包括了目前多数C编译系统所提供的库函数,但也有一些是某些 C编译系统未曾实现的。考虑到通用性,本书列出VC上通用的部分库函数。读者在编译 C程序时可能要用到更多的函数,请查阅相关手册。

1. 数学函数调用数学函数时,要求在源文件中包含头文件,即使用以下命令行:

#include <math.h>或 include “math.h”

函数名 函数原型说明 功能 返回值 说明abs int abs (int x); 求整数 x的绝对值。 计算结果  

acos double acos (double x); 计算 cos-1(x)的值。 计算结果 x在-1 ~ 1 范围内asin double asin (double x); 计算 sin-1(x)的值。 计算结果 x在-1 ~ 1 范围内atan double atan (double x); 计算 tan-1(x)的值。 计算结果  

atan2 double atan2 (double x); 计算 tan-1(x/y)的值。 计算结果  

cos double cos (double x); 计算 cos (x)的值。 计算结果 x的单位为弧度cosh double cosh (double x); 计算双曲余弦 cosh(x)的值。 计算结果  

exp double exp (double x); 计算 ex的值。 计算结果  

fabs double fabs(double x); 求 x的绝对值。 计算结果  

floor double floor (double x); 求不大于 x 最大整数。 该 整 数 的双精度数。  

fmodDouble fmod (double x,double

y);求整除 x/y的余数。  余数的双

精度数。  

frexpDouble frexp (double

val,int*eptr);

把双精度数 val分解尾数 x和以2为底的指数 n,即 val=x*2n,n

存放在 eptr 所指向的变量中。返回尾数 x

0.5≤x<1 

273

Page 282: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

log double log (double x); 求 logex,即 ln x。 计算结果  

log10 double log10 (double x); 求 log10x。 计算结果  

modfdouble modf (double

val,double *iptr);

把双精度数 val分解成整数部分和小数部分,整数部分存放在 iptr 所指的单元。

Val 的小数部分  

powDouble pow (double x,double

y);计算 xy的值。 计算结果  

rand Int rand(void) 产生-90~32767间的随机整数 随机整数sin double sin (double x); 计算 sin (x)的值。 计算结果 x的单位为弧度sinh double sinh (double x);

计算 x的双曲正弦函数 sinh(x)

的值。 计算结果  

sqrt double sqrt (double x); 计算 x的平方根。 计算结果  x≥0

tan double tan (double x); 计算 tan (x)的值。 计算结果 x的单位为弧度tanh double tanh

计算 x的双曲正切函数 tanh(x)

的值 计算结果  

2. 字符函数和字符串函数ANSI C 标准要求在使用字符串函数时要包含头文件“string.h”,在使用字符函数时要

包含头文件“ctype.h”。有的 C编译不遵循 ANSI C 标准的规定而用其他名称的头文件,使用时请查有关手册。

函数名 函数原型说明 功能 返回值 包含文件isalnum int isalnum(int ch);

检查 ch是否为字母或数字

是,返回 1;否则返回 0

ctype.h

isalpha int isalpha(int ch); 检查 ch是否为字母 是,返回 1;否则返回 0

ctype.h

iscntrl int iscntrl(int ch);检查 ch是否为控制字符

是,返回 1;否则返回 0

ctype.h

isdigit int isdigit(int ch); 检查 ch是否为数字 是,返回 1;否则返回 0

ctype.h

isgraph int isgraph(int ch);

检查 ch是否为(ASCII

码值在 ox21到 ox7e)的可打印字 符(即不包含空格字符)

是,返回 1;否则返回 0

ctype.h

islower int islower(int ch);检查 ch是否为小写字母

是,返回 1;否则返回 0

ctype.h

isprint int isprint(int ch);检查 ch是否为字母或数字

是,返回 1;否则返回 0

ctype.h

274

Page 283: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

ispunct int ispunct(int ch);

检查 ch是否为标点字符(包括空格),即除字母、数字和空格以外的所有可打印字符。

是,返回 1;否则返回 0

ctype.h

isspace int isspace(int ch);检查 ch是否为空格、制表或换行字符

是,返回 1;否则返回 0

ctype.h

isupper int isupper(int ch);检查 ch是否为大写字母

是,返回 1;否则返回 0

ctype.h

isxdigit int isxdigit(int ch);检查 ch是否为 16进制数字

是,返回 1;否则返回 0

ctype.h

memccpy

void *memccpy(void *dest, void

*src, unsigned char c, unsigned int

count);

由 src 所指内存区域复制不多于 count 个字节到 dest 所 指 内 存 区域,如果遇到字符 c 则停止复制。

如果 c没有被复制,则返回 NULL,否则,返回字符 c 后面紧挨一个字符位置的指针。

string.h

memchrvoid memchr(void *buf, char ch,

unsigned count);

在 buf 的前 count 个字符里搜索字符 ch 首次出现的位置

返回指向 buf中 ch的第一次出现的位置指针。若没有找到 ch,返回 NULL

string.h

memcmpint memcmp(void *buf1, void *buf2,

unsigned count);

按字典顺序比 较由buf1 和 buf2 指向的数组的前 count 个字符

buf1<buf2,为负数buf1=buf2,返回 0

buf1>buf2,为正数string.h

memcpyvoid *memcpy(void *to, void *from,

unsigned count);

将 from指向的数组中的前 count 个字符拷贝到 to 指 向 的 数 组中。From和 to指向的数组不允许重叠

返回指向 to的指针 string.h

memicmpint memicmp(void *buf1, void *buf2,

unsigned int count);

比较内存区域 buf1 和buf2的前 count 个字节但不区分字母的大小写

buf1<buf2,为负数buf1=buf2,返回 0

buf1>buf2,为正数string.h

memmovevoid *memmove(void *to, void

*from, unsigned count);

将 from指向的数组中的前 count 个字符拷贝到 to 指 向 的 数 组中。From和 to指向的数组不允许重叠

返回指向 to的指针 string.h

memsetvoid *memset(void *buf, char ch,

unsigned count);

将 字 符 ch 拷贝到 buf

指向的数组前 count 个字符中

无返回值 string.h

movedata

void  movedata(int segsrc,int offsrc,

int segdest,int offdest,  unsigned

numbytes);

将源地址(segsrc:offsrc)

处的 numbytes 个 字 节复 制 到 目 标 地 址(segdest:offdest)

无返回值 string.h

275

Page 284: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

movememvoid  movemem(void *source,void

*destin,unsigned len)

从 source 处复制一块长 len 字 节的数据到destin.若源地址和目标地址字符串重迭 ,则选择复制方向 ,以便正确的复制数据.

无返回值 string.h

setmemvoid setmem(void *buf, unsigned int

count, char ch);

把 buf 所指内存区域前count 个字节设置成字符 ch。

返回指向 buf的指针 string.h

strcat char *strcat(char *s1,char *s2);把字符串 s2 接到 s1后面 s1 所指地址 string.h

strchr char *strchr(char *s,int ch);

在 s把指字符串中,找出第一次出现字符 ch

的位置返回找到的字符的地址 , 找 不 到 返 回NULL

string.h

strcmp int *strcmp(char *s1,char *s2);对 s1和 s2 所指字符串进行比较

s1<s2, 返 回 负数 , s1=s2, 返 回0,s1>s2,返回正数。

string.h

strcpy char *strcpy(char *s1,char *s2);把 s2指向的串复制到s1指向的空间 s1 所指地址 string.h

strcspnsize_t strcspn(const char *s1,const

char *s2);

顺序在字符串 s1中搜寻与 s2中字符的第一个相同字 符,包括结束符 NULL

返回这个 字 符在 S1

中第一次出现的位置。

string.h

strdup char *strdup(char *s);将字符串 s复制到最近建立的单元

返回一个指针,指向为复制字符串分配的空间 ; 如果分配空间失败,则返回 NULL 值。

string.h

stricmp  int stricmp(char *s1,char * s2);

比较字符串 s1和 s2,但不区分字母的大小写。

s1<s2,为负数s1=s2,返回 0

s1>s2,为正数string.h

strlen unsigned strlen(char *s); 求字符串 s的长度 返回串中字符(不计最后的‘\0’)个数 string.h

strlwr char *strlwr(char *s);

将字符串 s中的大写字母全部 转 换成小写字母

返回转换后的字符串 string.h

strncatchar *strncat(char *dest,char *src,int

n);

把 src 所指字符串的前n 个字符添加到 dest 结尾处(覆盖 dest 结尾处的'\0')并添加'\0'。

返回指向 dest 的指针 string.h

strncmp int strncmp(char *str1, char *str2, int

maxlen);比较字符串 str1和 str2

的前maxlen 个字符。如果前 maxlen 字节完全相等,返回值就=0;如果出现 str1[n]

与 str2[n]不等,则返

string.h

276

Page 285: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

回(str1[n]-str2[n])strncpy

char   strncpy(char *dest,const char

*src,size_t maxlen)

复制 src中的前 maxlen

个字符到 dest中 返回指向 dest的指针 string.h

strnicmp int strnicmp(char *str1, char *str2,

unsigned maxlen);

比较字符串 str1和 str2

的前 maxlen 个字符串字典序的大小,但是不区分字母大小写。

str1< str2,为负数str1= str2,返回 0

str1> str2,为正数string.h

strnsetchar *strnset(char *str, char ch,

unsigned n);

将一个串中的前 n 个字符都设为指定字符ch

返回指向 dest的指针 string.h

strpbrk char *strpbrk(char *s1, char *s2);

在字符串 s1中寻找字符串 s2中任何一个字符相匹配的第一个 字符的位置,空字 符NULL不包括在内。

返回指向 s1中第一个相匹配的字 符的指针,如果没有匹配字符 则 返 回 空 指 针NULL。

string.h

strrchr char *strrchr(char *str, char c);

查找一个字符 c在另一个字符串 str中末次出现的位置(也就是从str的右侧开始查找字符 c 首次出现的位置)

返回从字符串中的这个位置起,一直到字符串结束的所有字符。如果未能找到指定字符,那么函数将返回 NULL。

string.h

strrev char *strrev(char *s);

把字符串 s的所有字符的顺序颠倒过来(不包括空字符 NULL)

返回指向颠倒顺序后的字符串指针。 string.h

strset char *strset(char *s, char c);把字符串 s中的所有字符都设置成字符 c。 返回指向 s的指针。 string.h

strspnsize_t strspn(const char * str1,const

char * str2); 扫描字符串 str1

返回字符串 str1开头连续包含字符串 str2

内的字符数目. 

string.h

strstr char *strstr(char *s1,char *s2);

在 s1 所指字符串中,找到字符串 s2第一次出现的位置

返回找到的字符串的地址,找不到返回NULL

string.h

strtokchar *strtok(char *s, const char

*delim);

分解字 符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。

返回从 s开头开始的一个个被分割的串。当没有被分割的串时则返回 NULL。

string.h

strupr char *strupr(char *s);字符串 s 转换为大写形式 返回指向 s的指针 string.h

tolower int tolower(int ch);把 ch中的字母转换成小写字母 返回对应的小写字母 ctype.h

toupper int toupper(int ch);把 ch中的字母转换成大写字母 返回对应的大写字母 ctype.h

277

Page 286: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

3. 输入输出函数凡用以下的输入输出函数,应该使用#include<stdio.h>把 stdio.h头文件包含到源程序文

件中。函数名 函数原型说明 功能 返回值 说明

clearerr void clearer(FILE * fp);清除与文件指针 fp有关的所有出错信息。 无。

close int close(int fp); 关闭文件。 关闭成功返回 0,不成功返回-1。

非 ANSI 标准函数。

creatint creat (char *

filename,int mode);

以mode 所指定的方式建立文件。

成功则返回正数,否则返回-1。

非 ANSI 标准函数。

eof Inteof (int fd); 检查文件是否结束。 遇文件结束,返回 1;否则返回 0。

非 ANSI 标准函数。

fclose int fclose(FILE * fp);关闭 fp 所指的文件,释放文件缓冲区

出错返回非 0,否则返回 0。

feof int feof(FILE * fp); 检查文件是否结束 遇文件结束返回非 0,否则返回 0。

ferror int ferror(FILE *fp);测试 fp 所指的文件是否有错误

无错返回 0,否则返回非 0

fflush int fflush(FILE *fp);将 fp 所指的文件的全部控制信息和数据存盘

存盘正确返回 0,否则返回非 0

fgetc int fgetc(FILE * fp);从 fp 所指的文件中取得下一个字符

出错返回 EOF,否则返回所读字符。

fgetschar * fgets(char * buf, int

n, file * fp);

从 fp 所指的文件中读取一个长度为 n - 1的字符串,将其存入 buf 所指存储区

返回 buf 所指地址,若遇文件结束或出错返回 NULL。

fopenFILE * fopen(char *

filename, char * mode);

以mode指定的方式打开名为 filename的文件

成功,返回文件指针(文件信息区的起始地址),否则返回NULL。

fprintfint fprintf(FILE * fp,char

* format,args,…);

把 arg的值以 format指定的格式输出到 fp 所指定的文件中

实际输出的字符数。

fputcint fputc(char ch,FILE *

fp);

把 ch中字符输出到 fp 所指文件

成功返回该字符,否则返回 EOF。

fputsint fputs(char * str,FILE *

fp);

把 str 所指字符串输出到 fp

所指文件成功返回非 0,否则返回 0。

fread

int fread(char *

pt,unsigned size,unsigned

n,FILE * fp);

从 fg 所指文件中读取长度为 size的 n 个数据项存到 pt

所指文件中读取的数据项个数。

fscanf int fscanf(FILE * fp,char *

format,args,…);

从 fg 所指定的文件中按format 指定的格式把输入

已输入的数据个数,遇文件的结束或出错

278

Page 287: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

数据存入到 args,…所指的内存中 返回 0。

fseekint fseek(FILE * fp,long

offer,int base);

移动 fp 所指文件的位置指针

成功返回当前位置,否则返回-1。

ftell int ftell(FILE * fp);求出 fp 所指文件当前的读写位置 读写位置。

fwrite

int fwrite(char *

pt,unsigned size,unsigned

n,FILE * fp);

把 pt 所指向的 n * size 个字节输出到 fp 所指文件中 输出的数据项个数。

getc int getc(FILE * fp);从 fp 所指文件中读取一个字符

返回所读字符,若出错或文件结束返回EOF。

getchar int getchar(void);从标准输入设备读取下一个字符。

返回所读字符,若出错或文件结束返回-1。

getw int getw (FILE * fp);从 fp 所指向的文件读取下一个字(整数)。

输入的整数。如文件结束或出错,返回-1。

非 ANSI 标准函数。

openInt open (char *

filename,int mode);

以mode指出的方式打开已存在的名为 filename 的文件。

返回文件号(正数)。如打开失败,返回-1。

非 ANSI 标准函数。

printfint printf (char *

format,args,…);

按 format 指向的格式字符串所规定的格式,将输出表列 args的值输出到标准输出设备。

输出字符个数。若出错,返回负值。

format 可以是一个字符串,或字符数组的起始地址。

putc int putc(int ch,FILE * fp); 同 fputc 同 fputc

putcahr int putcahr(char ch); 把 ch输出到标准输出设备 返回输出的字符,若出错,返回 EOF。

puts int puts(char * str);

把 str 所指字符串输出到标准设备,将‘ \0’转换成回车换行符

返回 换行符,若出错,返回 EOF。

putw int putw (int w,FILE * fp);将一个整数 w(即一个字)写到 fp指向的文件中。

返回输出的整数;若出错,返回 EOF。

非 ANSI 标准函数。

readint read (int fp,char *

buf,unsigned count);

从文件号 fp 所指示的文件中读 count 个字节到由 buf

指示的缓冲区中。返回真正读入的字节个数。如遇文件结束返回 0,出错返回-1。

非 ANSI 标准函数。

rename

int rename(char *

oldname,char *

newname);

把 oldname 所指文件名改为newname 所指文件名。

成功返回 0,出错返回-1。

rewind void rewind(FILE * fg);

将 fp指示的文件位置指针置于文件开头,并清除文件结束标志和错误标志。

无。scanf int scanf (char *

format,args,…);

从 标准输入设备按 format

指定的格式把输入数据存读入并赋给 args 的数据个数。遇文件结束返

args 为 指针。

279

Page 288: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

入到 args,…所指的内存中。 回 EOF,出错返回 0。write

int write (int fd, char *

buf,unsigned count);

从 buf 指示的缓冲区输出count 个字符到 fd 所标志的文件中。

返回实际输出的字节数。如出错返回-1。

非 ANSI 标准函数。

  4. 动态分配函数ANSI 标 准 建 议 设 4 个 有 关 的 动 态 存 储 分 配 的 函 数 , 即

calloc()、malloc()、free()、realloc()。实际上,许多 C编译系统实现时,往往增加了一些其他函数。ANSI 标准建议在 "stdlib.h"头文件中包含有关的信 息,但许多 C 编译系统要求用"malloc.h"而不是"stdlib.h"。读者在使用时应查阅有关手册。

ANSI 标准要求动态分配系统返回 void指针。void指针具有一般性,它们可以指向任何类型的数据,但目前有的 C编译所提供的这类函数返回 char指针。无论以上两种情况的哪一种,都需要用强制类型转换的方法把 void或 char指针转换成所需的类型。

函数名 函数原型说明 功能 返回值calloc

void * calloc(unsigned

n,unsigned size);

分配 n 个数据项的内存空间,每个数据项的大小为 size 个字节。

分配内存单元的起始地址;如不成功,返回 0。

free void free(void p); 释放 p 所指的内存区。 无malloc

void * malloc(unsigned

size);分配 size 个字节的存储空间。 分配内存空间的地址;如

不成功返回 0。realloc

void * realloc(void *

p,unsigned size);

把 p 所指内存区的大小改为 size 个字节。

新分配内存空间的地址;如不成功返回 0。

280

Page 289: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附 录 E 常 用 字 符 与 ASCII码 对 照 表

ASCII 字 符 控 制 字 ASCII 字 ASCII 字 符 ASCII 字 符 ASCII 值 字 符 ASCII 字 ASCII 字 符 ASCII 字 符000 null NUL 032 (spac 064 @ 096 ’ 128 Ç 160 á 192 └ 224 α001

☺SOH 033 ! 065 A 097 a 129 Ü 161 í 193 ┴ 225 β

002☻

STX 034 " 066 B 098 b 130 é 162 ó 194 ┬ 226 Γ003 © ETX 035 # 067 C 099 c 131 â 163 ú 195 ├ 227 π004 ¨ EOT 036 $ 068 D 100 d 132 ā 164 ñ 196 ─ 228 Σ005 § END 037 % 069 E 101 e 133 à 165 Ñ 197 † 229 σ006 ª ACK 038 & 070 F 102 f 134 å 166 ª 198 ╞ 230 µ007 beep BEL 039 ' 071 G 103 g 135 ç 167 º 199 ╟ 231 τ008 backspac BS 040 ( 072 H 104 h 136 ê 168 ¿ 200 ╚ 232 Φ009 tab HT 041 ) 073 I 105 i 137 ë 169 ┌ 201 ╔ 233 θ010 换行 LF 042 * 074 J 106 j 138 è 170 ┐ 202 ╩ 234 Ω011 ♂ VT 043 + 075 K 107 k 139 ï 171 ½ 203 ╦ 235 δ012 ♀ FF 044 , 076 L 108 l 140 î 172 ¼ 204 ╠ 236 ∞013 回 车 CR 045 - 077 M 109 m 141 ì 173 ¡ 205 ═ 237 ø014 ♫ SO 046 . 078 N 110 n 142 Ä 174 « 206 ╬ 238 є015 ☼ SI 047 / 079 O 111 o 143 Å 175 » 207 ╧ 239 ∩016 ► DLE 048 0 080 P 112 p 144 É 176 ░ 208 ╨ 240 ≡017 ◄ DC1 049 1 081 Q 113 q 145 æ 177 ▒ 209 ╤ 241 ±018 ↕ DC2 050 2 082 R 114 r 146 Æ 178 ▓ 210 ╥ 242 ≥019 ‼ DC3 051 3 083 S 115 s 147 ô 179 | 211 ╙ 243 ≤

Page 290: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

020 ¶ DC4 052 4 084 T 116 t 148 ö 180 ┤ 212 ╘ 244 ⌠021 § NAK 053 5 085 U 117 u 149 ò 181 ╡ 213 ╒ 245 ⌡022 ▂ SYN 054 6 086 V 118 v 150 û 182 ╢ 214 ╓ 246 ÷023 ↨ ETB 055 7 087 W 119 w 151 ù 183 ╖ 215 ╫ 247 ≈024 ↑ CAN 056 8 088 X 120 x 152 ÿ 184 ╕ 216 ╪ 248 °025 ↓ EM 057 9 089 Y 121 y 153 ö 185 ╣ 217 ┘ 249 ·026 → SUB 058 : 090 Z 122 z 154 Ü 186 || 218 ┌ 250 .027 ← ESC 059 ; 091 [ 123 { 155 ¢ 187 ╗ 219 █ 251 √028 └ FS 060 < 092 \ 124 ¦ 156 £ 188 ╝ 220 ▄ 252 ⁿ029 ↔ GS 061 = 093 ] 125 } 157 ¥ 189 ╜ 221 ▌ 253 ²030 ▲ RS 062 > 094 ^ 126 ~ 158 P

t190 ┘ 222 ▐ 254 ▮

031 ▼ US 063 ? 095 _ 127 ⌂ 159 ƒ 191 ┐ 223 ▀ 255 Blank’

Page 291: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附录 F 常用 C 库文件

C系统提供了丰富的系统文件,称为库文件,C的库文件分为两类,一类是扩展名为".h"的文件,称为头文件, 在前面的包含命令中我们已多次使用过。在".h"文件中包含了常量定义、 类型定义、宏定义、函数原型以及各种编译选择设置等信息。另一类是函数库,包括了各种函数的目标代码,供用户在程序中调用。 通常在程序中调用一个库函数时,要在调用之前包含该函数原型所在的".h" 文件。注意:编译器的不同,会导致一些头文件的不同。ALLOC.H    说明内存管理函数(分配、释放等)。ASSERT.H    定义 assert 调试宏。BIOS.H     说明调用 IBM—PC ROM BIOS 子程序的各个函数。CONIO.H    说明调用DOS 控制台 I/O 子程序的各个函数。CTYPE.H    包含有关字符分类及转换的名类信息(如 isalpha和 toascii等)。DIR.H     包含有关目录和路径的结构、宏定义和函数。DOS.H     定义和说明 MSDOS和 8086 调用的一些常量和函数。ERRON.H    定义错误代码的助记符。FCNTL.H    定义在与 open 库子程序连接时的符号常量。FLOAT.H    包含有关浮点运算的一些参数和函数。GRAPHICS.H   说明有关图形功能的各个函数,图形错误代码的常量定义,针对不同驱动程序的各种颜色值,及函数用到的一些特殊结构。IO.H      包含低级 I/O 子程序的结构和说明。LIMIT.H    包含各环境参数、编译时间限制、数的范围等信息。MATH.H     说明数学运算函数,还定了 HUGE VAL 宏, 说明了 matherr 和matherr 子程序用到的特殊结构。MEM.H     说明一些内存操作函数(其中大多数也在 STRING.H 中说明)。PROCESS.H   说明进程管理的各个函数,spawn…和 EXEC …函数的结构说明。

Page 292: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

SETJMP.H    定义 longjmp和 setjmp函数用到的 jmp buf类型, 说明这两个函数。SHARE.H    定义文件共享函数的参数。SIGNAL.H    定义 SIG[ZZ(Z] [ZZ)]IGN和 SIG[ZZ(Z] [ZZ)]DFL 常量,说明 rajse和signal 两个函数。STDARG.H    定义读函数参数表的宏。(如 vprintf,vscarf函数)。STDDEF.H    定义一些公共数据类型和宏。STDIO.H    定义 Kernighan和 Ritchie在 Unix System V 中定义的标准和扩展的类型和宏。还定义标准 I/O 预定义流:stdin,stdout和 stderr,说明 I/O 流子程序。STDLIB.H    说明一些常用的子程序:转换子程序、搜索/ 排序子程序等。STRING.H    说明一些串操作和内存操作函数。SYS\STAT.H   定义在打开和创建文件时用到的一些符号常量。SYS\TYPES.H  说明 ftime函数和 timeb 结构。SYS\TIME.H   定义时间的类型 time[ZZ(Z] [ZZ)]t。TIME.H     定义时间转换子程序 asctime、localtime和 gmtime的结构,ctime、 difftime、 gmtime、 localtime和 stime用到的类型,并提供这些函数的原型。VALUE.H    定义一些重要常量, 包括依赖于机器硬件的和为了与Unix System V

相兼容而说明的一些常量,包括浮点和双精度值的范围。

Page 293: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

附录 G 预处理预处理是指编译器对源代码进行处理前由预处理程序完成的工作。C语言提供了多种预

处理功能,如文件包含、定义宏、条件编译等。 预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。

#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令:

        指令 用途         #include      包含一个源代码文件         #define        定义宏         #undef         取消已定义的宏         #if               如果给定条件为真,则编译下面代码         #ifdef          如果宏已经定义,则编译下面代码         #ifndef        如果宏没有定义,则编译下面代码         #elif            如果前面的#if给定条件不为真,当前条件为真,则编译下面代码         #endif         结束一个#if……#else条件编译块         #error        停止编译并显示错误信息

1. 文件包含#include 预处理指令的作用是在指令处展开被包含的文件。包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。在程序中包含头文件有两种格式:

        #include <my.h>

        #include "my.h"

        第一种格式是用尖括号把头文件括起来。这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。第二种格式是用双引号把头文件括起来。这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不

Page 294: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

到,再搜索编译器自带的头文件。        采用两种不同包含格式的理由在于,编译器是安装在公共子目录下的,而被编译的应用程序是在它们自己的私有子目录下的。一个应用程序既包含编译器提供的公共头文件,也包含自定义的私有头文件。采用两种不同的包含格式使得编译器能够在很多头文件中区别出一组公共的头文件。

2. 宏宏定义了一个代表特定内容的标识符。预处理过程会把源代码中出现的宏标识符替换

成宏定义时的值。宏最常见的用法是定义代表某个值的全局符号。宏的第二种用法是定义带参数的宏,这样的宏可以象函数一样被调用,但它是在调用语句处展开宏,并用调用时的实际参数来代替定义中的形式参数。(1) #define指令#define 预处理指令是用来定义宏的。该指令最简单的格式是:首先声明一个标识符,

然后给出这个标识符代表的代码。在后面的源代码中,就用这些代码来替代该标识符。这种宏把程序中要用到的一些全局值提取出来,赋给一些记忆标识符。

            #define MAX_NUM 10

            int array[MAX_NUM];

            for(i=0;i<MAX_NUM;i++)  /*……*/

       

在这个例子中,对于阅读该程序的人来说,符号 MAX_NUM就有特定的含义,它代表的值给出了数组所能容纳的最大元素数目。程序中可以多次使用这个值。作为一种约定,习惯上总是全部用大写字母来定义宏,这样易于把程序宏的宏标识符和一般变量标识符区别开来。如果想要改变数组的大小,只需要更改宏定义并重新编译程序即可。宏表示的值可以是一个常量表达式,其中允许包括前面已经定义的宏标识符。例如:            #define ONE 1

            #define TWO 2

            #define THREE (ONE+TWO)

注意上面的宏定义使用了括号。尽管它们并不是必须的。但出于谨慎考虑,还是应该加上括号的。例如:

            six=THREE*TWO;

        预处理过程把上面的一行代码转换成:

Page 295: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

            six=(ONE+TWO)*TWO;

        如果没有那个括号,就转换成 six=ONE+TWO*TWO;了。        宏还可以代表一个字符串常量,例如:            #define VERSION "Version 1.0 Copyright(c) 2003"

(2) 带参数的#define指令带参数的宏和函数调用看起来有些相似。看一个例子:            #define Cube(x) (x)*(x)*(x)

可以时任何数字表达式甚至函数调用来代替参数 x。这里再次提醒大家注意括号的使用。宏展开后完全包含在一对括号中,而且参数也包含在括号中,这样就保证了宏和参数的完整性。看一个用法:

            #define num (8+2)

            volume=Cube(num);

展开后为(8+2)*(8+2)*(8+2);

如果没有那些括号就变为 8+2*8+2*8+2了。下面的用法是不安全的:            volume=Cube(num++);

如果 Cube是一个函数,上面的写法是可以理解的。但是,因为 Cube是一个宏,所以会产生副作用。这里的参数不是简单的表达式,它们将产生意想不到的结果。它们展开后是这样的:

            volume=(num++)*(num++)*(num++);

很显然,结果是 10*11*12,而不是 10*10*10;

那么怎样安全的使用 Cube宏呢?必须把可能产生副作用的操作移到宏调用的外面进行:            int num=8+2;

            volume=Cube(num);

            num++;

3. 条件编译指令条件编译指令将决定那些代码被编译,而哪些是不被编译的。可以根据表达式的值或

者某个特定的宏是否被定义来确定编译条件。(1) #if指令

Page 296: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

#if指令检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,知道出现#else、#elif或#endif为止;否则就不编译。(2) #endif指令#endif用于终止#if 预处理指令。            #define DEBUG 0

            main()

            {

                #if DEBUG

                    printf("Debugging\n");

                #endif

                    printf("Running\n");

            }

由于程序定义 DEBUG宏代表 0,所以#if条件为假,不编译后面的代码直到#endif,所以程序直接输出 Running。

如果去掉#define语句,效果是一样的。(3) #ifdef和#ifndef

        #define DEBUG

         main()

        {

            #ifdef DEBUG

                printf("yes\n");

            #endif

            #ifndef DEBUG

                printf("no\n");

            #endif

        }

#if defined等价于#ifdef; #if !defined等价于#ifndef

(4) #else指令#else指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面

的代码。#endif指令将中指上面的条件块。

Page 297: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

        #define DEBUG

        main()

        {

            #ifdef DEBUG

                printf("Debugging\n");//

            #else

                printf("Not Debugging\n");

            #endif

                printf("Running\n");

       }

(5) #elif指令#elif 预处理指令综合了#else和#if指令的作用。例如:#define TWO

main()

{

    #ifdef ONE

        printf("1\n");

    #elif defined TWO

        printf("2\n");

    #else

        printf("3\n");

    #endif

}

程序很好理解,最后输出结果是 2。

Page 298: C程序设计思考与实践 - " + ID EESX Welcome + "218.5.241.13:8060/oj/download/Cchengxushejishijianjiao... · Web view在“工程”选项卡中选择Win32 Console Application选项,在“工程名称”的文本框中输入自己定义的项目名称(这里使用Hello),在“位置”的文本框中输入保存项目的路径,单击“确定”按钮进入图1.2的界面,选择“一个空工程”,单击

参考文献

[1] 李文新.郭炜.余华山.程序设计导引及在线实践.北京:清华大学出版社,2007.[2] 吴文虎.徐明星.程序设计基础.北京:清华大学出版社,2010.[3] Stephen Prara. .技桥工作室译 C Primer Plus.人民邮电出版社,2002.[4] Stanley B.Lippman & Josée Lajoie & Barbara E.Moo 著.李师贤,蒋爱军,梅晓勇,林瑛译.C++PRIMER. 人民邮电出版社,2010[5] 谭浩强.C程序设计(第四版) .北京:清华大学出版社,2010.[6] 陈良银.游洪跃.李旭伟.C语言程序设计(c99 版).北京:清华大学出版社,2006.[7] 衡友跃等.Java趣味编程 100例.北京:清华大学出版社,2013.[8] 网络资源