描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302462118丛书名: 高等院校“十三五”应用技能培养规划教材·移动应用开发系列
本书根据应用的需要,合理取舍,精选内容,采用读者容易理解的方法,力求深入浅出、通俗易懂。
本书的主要特色如下。
(1) 讲解预备知识,以飨基础薄弱者,利于无障碍地学会编程。
(2) 增加了运行环境介绍,使用VC编译工具,接轨国家等级考试。
(3) 详解程序调试,通过真题进行实战讲解,专门针对上机考试。
(4) 例题都给出了程序运行的真实截屏效果,以保障所讲解的程序是能够运行的。
(5) 习题经过细心琢磨,专为应试做准备,部分习题选自历年的考题。
(6) 各章末尾的案例实训是精选的综合性案例,具有一定的实用性。
(7) 篇末的项目实践贯穿主要的知识点,以加强系统性和实践性。
(8) 精选了网上的一些内容,博采众家之长,集众多优质案例于一书。
C语言是国内外使用*广泛的程序设计语言之一,更是高等院校工科学生应该具备的基础知识。学会使用C语言进行程序设计,也是计算机工作者的一项基本功。
本书系统而全面地介绍了C语言的知识,适合零基础的读者自学。在内容方面,由于位运算多用于检测和控制领域,常规编程较少触及,各类考试也很少涉及,故本书未将此部分内容纳入。
与一般的C语言教材相比,本书增加了“预备知识”和“VC环境下C语言的运行与调试”两部分内容。前者主要解决晦涩难懂的补码问题,有助于读者理解C语言整型数据的存储;后者则有助于读者上机考试。书中每道例题的输出结果,均以屏幕截图的方式提供,原滋原味地呈现给读者,便于分析程序。
本书可作为普通高等院校及大专院校各专业的C语言教材,亦可供读者自学C语言使用,尤其适合作为各类C语言考试的培训教材。
目 录
第1章 C语言基础…. 1
1.1 计算机语言的概念… 2
1.2 C语言的发展和特点… 3
1.2.1 概述… 3
1.2.2 C语言的发展历史… 4
1.2.3 C语言的特点… 5
1.3 计算机中数的表示及进制转换… 6
1.3.1 数制的概念… 6
1.3.2 数码、基数与位权… 6
1.3.3 各种进制之间的转换… 7
1.4 字节和位的概念… 9
1.5 整数的表示方法——原码、反码
和补码… 10
1.5.1 整数的原码表示… 10
1.5.2 整数的反码表示… 10
1.5.3 整数的补码表示… 10
1.6 书写程序时应遵循的规则… 11
1.7 C语言程序的结构… 11
1.7.1 源程序结构… 11
1.7.2 C语言的字符集… 13
1.7.3 C语言的词汇… 14
1.8 简单的C程序举例… 15
1.9 运行C语言程序的步骤和方法… 17
第2章 VC环境下C程序的运行
和调试…. 19
2.1 在VC下运行一个C程序… 20
2.1.1
启动VC.. 20
2.1.2
编辑程序… 20
2.1.3
编译程序… 21
2.1.4
运行程序… 22
2.2 在VC下调试C程序的方法… 23
2.2.1
VC调试功能简介… 23
2.2.2
使用VC调试C程序的方法… 26
第3章 数据描述…. 31
3.1 C语言的数据类型… 32
3.2 常量和变量… 33
3.2.1 常量和符号常量… 33
3.2.2 变量… 34
3.3 整型数据… 34
3.3.1 整型常量的表示方法… 34
3.3.2 整型变量… 36
3.4 实型数据… 40
3.4.1 实型常量的表示方法… 40
3.4.2 实型变量… 41
3.4.3 实型常数的类型… 42
3.5 字符型数据… 42
3.5.1 字符常量… 42
3.5.2 转义字符… 43
3.5.3 字符变量… 44
3.5.4 字符数据在内存中的存储形式
及使用方法… 44
3.5.5 字符串常量… 45
3.6 为变量赋初值… 46
3.7 算术运算符和算术表达式… 46
3.7.1 C语言的运算符简介… 47
3.7.2 算术运算符和算术表达式… 47
3.8 赋值运算符和赋值表达式… 50
3.9 逗号运算符和逗号表达式… 52
3.10 各类数值型数据之间的混合运算… 53
3.11 本章小结… 56
习题… 57
第4章 C程序的流程设计…. 59
4.1 C语句概述… 60
4.2 赋值语句… 62
4.3 数据输入输出的概念及在C语言中
的实现… 63
4.4 字符数据的输入输出… 63
4.4.1 putchar函数(字符输出函数) 63
4.4.2 getchar函数(键盘输入函数) 64
4.5 格式输入与输出… 65
4.5.1 printf函数(格式输出函数) 65
4.5.2 scanf函数(格式输入函数) 68
4.6 结构化程序设计的方法… 74
4.7 顺序结构程序设计… 76
4.7.1 顺序结构的程序… 76
4.7.2 顺序结构程序的案例实训… 76
4.8 选择结构程序设计… 77
4.8.1 关系运算符和关系表达式… 77
4.8.2 逻辑运算符和逻辑表达式… 79
4.8.3 if语句… 81
4.8.4 switch语句… 89
4.8.5 分支结构程序的案例实训… 91
4.9 循环结构程序的设计… 94
4.9.1 概述… 94
4.9.2 goto语句以及用goto语句
构成的循环… 95
4.9.3 while语句… 95
4.9.4 do-while语句… 98
4.9.5 for语句… 100
4.9.6 循环的嵌套… 103
4.9.7 几种循环的比较… 103
4.9.8 break语句和continue语句… 104
4.9.9 循环结构程序的案例实训… 106
4.10 本章小结… 110
习题… 113
第5章 数组…. 117
5.1 一维数组的定义和引用… 118
5.1.1 一维数组的定义方式… 118
5.1.2 一维数组元素的引用… 119
5.1.3 一维数组的初始化… 121
5.1.4 一维数组应用举例… 122
5.2 二维数组的定义和引用… 123
5.2.1 二维数组的定义… 123
5.2.2 二维数组元素的引用… 124
5.2.3 二维数组的初始化… 126
5.2.4 二维数组程序举例… 127
5.3 字符数组… 128
5.3.1 字符数组的定义… 128
5.3.2 字符数组的初始化… 128
5.3.3 字符数组的引用… 129
5.3.4 字符串及其结束标志… 129
5.3.5 字符数组的输入输出… 130
5.3.6 字符串处理函数… 132
5.4 案例实训… 135
5.5 本章小结… 138
习题… 139
第6章 函数…. 143
6.1 概述… 144
6.2 函数定义的一般形式… 145
6.3 函数的参数和函数的值… 147
6.3.1 形参和实参… 147
6.3.2 函数的返回值… 149
6.4 函数的调用与被调用函数的声明… 150
6.4.1 函数调用的一般形式… 150
6.4.2 函数调用的方式… 150
6.4.3 被调用函数的声明和函数
原型… 152
6.5 函数的嵌套调用… 153
6.6 函数的递归调用… 155
6.7 数组作为函数参数… 157
6.8 局部变量和全局变量… 163
6.8.1 局部变量… 163
6.8.2 全局变量… 165
6.9 变量的存储类别… 167
6.9.1 动态存储方式与静态存储
方式… 167
6.9.2 auto变量… 168
6.9.3 用static声明局部变量… 168
6.9.4 register变量… 170
6.9.5 用extern声明外部变量… 170
6.10 内部函数和外部函数… 172
6.10.1 内部函数… 172
6.10.2 外部函数… 172
6.10.3 建立包含多个文件的程序… 174
6.11 案例实训… 177
6.12 本章小结… 181
习题… 183
第7章 编译预处理…. 189
7.1 概述… 190
7.2 宏定义… 190
7.2.1 无参宏的定义… 190
7.2.2 带参宏定义… 193
7.3 文件包含… 199
7.4 条件编译… 200
7.5 案例实训… 202
7.6 本章小结… 203
习题… 204
第8章 指针…. 207
8.1 指针的基本概念… 208
8.2 变量的指针和指向变量的指针
变量… 209
8.2.1 定义一个指针变量… 209
8.2.2 指针变量的引用… 210
8.2.3 指针变量作为函数参数… 214
8.2.4 关于指针变量几个问题的
进一步说明… 218
8.3 数组的指针和指向数组的指针
变量… 221
8.3.1 指向数组元素的指针… 222
8.3.2 通过指针引用数组元素… 223
8.3.3 数组名与指针变量作为函数的
参数… 227
8.3.4 指向多维数组的指针和指针
变量… 235
8.4 字符串的指针和指向字符串的指针
变量… 239
8.4.1 字符串的表示形式… 239
8.4.2 字符串指针变量与字符数组的
区别… 244
8.5 函数指针变量… 244
8.6 指针型函数… 246
8.7 指针数组和指向指针的指针… 247
8.7.1 指针数组的概念… 247
8.7.2 指向指针的指针… 251
8.7.3 main函数的参数… 253
8.8 有关指针的数据类型和指针运算
小结… 254
8.8.1 有关指针的数据类型小结… 254
8.8.2 指针运算小结… 255
8.8.3 void指针类型… 256
8.9 案例实训… 256
8.10 本章小结… 258
习题… 259
第9章 结构体与共用体…. 263
9.1 结构体类型的定义… 264
9.2 结构体变量的说明… 265
9.3 结构体变量成员的引用方法… 267
9.4 结构体变量的赋值… 268
9.5 结构体变量的初始化… 268
9.6 结构体数组的定义… 269
9.7 结构体指针变量的说明和使用… 271
9.7.1 指向结构体变量的指针… 271
9.7.2 指向结构体数组的指针… 273
9.7.3 结构体指针变量作为函数
参数… 274
9.8 动态存储分配… 276
9.9 用指针处理链表… 278
9.9.1 链表概述… 278
9.9.2 链表的建立和输出… 279
9.10 共用体… 288
9.10.1 共用体的定义… 288
9.10.2 共用体的引用… 289
9.11 枚举类型… 290
9.11.1 枚举类型的定义和枚举变量
的说明… 290
9.11.2 枚举类型变量的赋值
和使用… 290
9.12 用typedef定义已有类型… 292
9.13 案例实训… 293
9.14 本章小结… 295
习题… 298
第10章 文件的输入输出…. 303
10.1 文件概述… 304
10.2 文件指针… 305
10.3 文件的打开与关闭… 305
10.3.1 文件的打开(fopen函数) 305
10.3.2 文件的关闭(fclose函数) 307
10.4 文件的顺序读写… 307
10.4.1 字符读写函数fgetc
和fputc. 307
10.4.2 字符串读写函数fgets
和fputs. 311
10.4.3 数据块读写函数fread
和fwrite. 313
10.4.4 格式化读写函数fscanf
和fprintf 314
10.4.5 文件结束检测函数feof 316
10.5 文件的随机读写… 316
10.5.1 文件定位函数… 317
10.5.2 文件随机读写… 317
10.6 文件读写的出错检测… 318
10.7 案例实训… 319
10.8 本章小结… 321
习题… 321
第11章 项目实践…. 325
11.1 题目要求… 326
11.2 系统分析… 326
11.3 系统设计… 326
11.3.1 总体设计… 326
11.3.2 详细设计… 327
11.4 系统实施… 334
11.5 关于项目实践的几点说明… 345
附录A ASCII代码表…. 347
附录B C语言中的关键字…. 349
附录C C语言的常用库函数…. 351
附录D 运算符的优先级与结合性…. 359
参考文献…. 361
前 言
计算机程序设计语言现今已有数百种,常用的也有数十种,但很少有哪一种语言像C语言那样充满活力,流行近半个世纪经久不衰;也很少有哪一种语言像C语言那样在中国如此普及。国家计算机等级考试中,各级考试均离不开C语言的身影;国内高等院校几乎都把计算机文化基础和C语言作为理工科学生步入计算机领域的”敲门砖”,C语言程序设计已成为理工科学生的技能之一。
C语言是20世纪70年代初期推出的编译型程序设计语言。经过近半个世纪的发展,C语言表现出了强大的生命力,已经从早期在少数小型机机种上使用的算法语言,发展成了当今在各类平台上普遍使用的通用程序设计语言。因为C语言具有强大的处理功能,特别是在某些方面可以替代汇编语言,所以熟练掌握C语言是现代计算机工作者应具备的基本条件,也是学习更高层次面向对象的C 语言的基础。
在近半个世纪的发展过程中,C语言的体系日臻完善,功能不断增强。与此相应,各种新型的C编译系统相继问世,C语言已从早期的”传统模式”发展为当前的”现代模式”。
鉴于目前流行的C语言编译系统大多数是以ANSI C89为基础开发的,所以本书以C89为基础并结合当前常用的VC集成开发环境进行介绍,同时兼顾过去20年非常流行的Turbo C集成环境。总而言之,本书的宗旨在于向读者呈现一本内容新颖、系统全面、按现代编程风格介绍C语言程序设计的书籍。
本书共分为11章,各章的主要内容说明如下。
第1章介绍C语言的基础。考虑到计算机零基础读者的需要,本章适量增加了一些C语言预备知识。
第2章以VC为背景,介绍运行C语言程序的步骤与方法,并通过典型案例,介绍C语言程序的调试方法。
第3章介绍C语言的基本数据类型、常量、变量以及C语言的各种运算符与表达式。
第4章从结构化程序设计的角度,介绍C程序的流程设计,同时融入算法的概念。
第5章介绍简单的构造类型–数组。
第6章介绍各种类型的函数,以及函数间数据传递的方法。
第7章介绍编译预处理。
第8章讨论C语言重要的概念–指针及其特性。
第9章介绍C语言的另一种构造类型–结构体与共用体,同时,还介绍枚举类型和用typedef定义既有类型的方法。
第10章从实用出发,介绍用C语言处理文件的方法。
第11章为项目实践,用一个大案例贯穿本书的主要知识点。书后的附录列出了ASCII码表、C语言关键字、常用库函数以及运算符的优先级与结合性。
此处提请读者注意:全书中紧随程序代码后的是程序的运行结果截图。在各截图标题栏中显示的文件名及路径仅是作者调试程序时使用的临时文件名和路径。
本书作者在多年从事C语言教学和软件开发的基础上,参考了国内外有关的C语言著作,参考了因特网上诸多的优秀程序,并参照了近几年来一直延用的《2013年计算机二级C语言程序设计考试大纲》,完成了编著工作。因此,本书既可作为普通高等院校及大专院校的教材使用,又可供参加各类计算机考试的人员学习和参考。
本书由天津工业大学的杨连贺教授、天津市信息安全测评中心的赵玉玲、天津广播电视大学的丁刚副教授主编,池明文、李俊荣为副主编。在本书的编写过程中,还得到了天津大学软件学院的刘石英副研究员、高翔副研究员、曹军老师、沈士强老师的热情帮助和指导。天津农学院计算机与信息工程学院的靳润昭教授、烟台大学计算机与控制工程学院的贺利坚副教授、西北工业大学计算机学院的张彦春副教授提供了不少案例,天津工业大学计算机科学与软件学院的硕士研究生董禹龙和房超在程序调试方面也做了不少工作,在此一并向他们表示衷心的感谢。
限于作者的经验和水平,书中的错误与不足之处在所难免,希望得到专家和读者的批评指正。
作 者
2017年2月于天津工业大学
第4章 C程序的流程设计
从流程的角度,可以把程序分为三种基本结构:顺序结构、分支结构、循环结构。理论上已经证明,无论多么复杂的程序,都可以使用这三种基本结构来编制。C语言提供了多种语句来实现这些程序结构。本章拟介绍这些基本语句及其在三种基本结构中的应用,使读者对C语言程序的基本结构有一个系统的认识,为后续各章的学习打下基础。
4.1
C语句概述
C语言程序的结构在第1章的1.7节已给出,图4-1给出的是更加详细的结构。
图4-1 C语言程序的详细结构
一个程序可以由多个源程序文件组成,一个源文件包括编译预处理命令、全局变量声明(二者均可以没有)以及一个或多个函数的定义。其中每个函数包括函数和函数体,函数体又包括局部变量声明和执行语句。
C语言程序的实质性部分是其执行部分,一般是由多条执行语句组成的,程序的功能就是通过这些执行语句来实现的。
C语言的语句可分为以下5类。
(1) 表达式语句。
(2) 函数调用语句。
(3) 控制语句。
(4) 复合语句。
(5) 空语句。
1. 表达式语句
前已提及,表达式语句是由表达式加上分号“;”组成的,其一般形式为:
表达式;
执行表达式语句,实际上就是计算表达式的值。例如:
x = y z;
/*赋值语句*/
y z;
/*加法运算语句(无实际意义,计算结果不能保留,编译虽无错,但给出警告)*/
3;
/*常数是表达式的特例,加分号也构成语句,虽无意义,但编译能通过*/
i ;
/*自增1语句,使i本身的值增1*/
2. 函数调用语句
函数调用语句由函数名、实参(实际参数)加上分号“;”组成,其一般形式为:
函数名(实参表);
执行函数语句就是调用该函数,并把实参赋给函数定义中的形参(形式参数),然后执行被调函数中的语句,求得函数值(在第6章中详细介绍)。
例如:
printf(“C Program”);
该函数调用语句的功能,是调用库函数printf,输出字符串“C Program”。
3. 控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构,它们由特定的语句定义符组成。
C语言有9种控制语句,可以分成以下三类。
(1) 条件判断语句:if语句、switch语句。
(2) 循环执行语句:do
while语句、while语句、for语句。
(3) 转向语句:break语句、goto语句、continue语句、return语句。
4. 复合语句
把多个语句用括号{}括起来组成的一个语句组,称为复合语句。
C语言把复合语句视为单条语句,而不是多条语句。
例如:
{
int temp;
temp = a;
a = b;
b = temp;
}
这就是一条复合语句,用于将a、b两个整型变量的内容交换。
复合语句内的各条语句都必须以分号“;”结尾,但在右括号}外不能加分号。
复合语句内可以定义变量。
5. 空语句
只由分号“;”组成的语句称为空语句。空语句什么也不执行,在程序中可用来作空循环体。
例如:
while(getchar() != ‘n’)
;
本语句的功能是,只要从键盘上输入的字符不是回车符,就重新输入。这里的循环体使用了空语句。
4.2 赋值语句
赋值语句是由赋值表达式加上分号而构成的表达式语句。其一般形式为:
变量 = 表达式;
赋值语句的功能和特点都与赋值表达式相同,它是程序中使用多的语句。
使用赋值语句时,需要注意以下几点。
(1) 因为赋值运算符“=”右边的表达式也可以是另一个赋值表达式,所以:
变量1 = (变量2 = 表达式);
是合法的,从而形成赋值的嵌套。其展开之后的一般形式为:
变量1 = 变量2 = …… = 表达式;
例如:
x=y=z=6;
由赋值运算的右结合性可知,上面的这条赋值语句实际上等效于下面的三条语句:
z = 6;
y = z;
x = y;
事实上,这一点也体现了C语言的简洁性(很多其他语言并不支持此类赋值操作)。
(2) 注意变量初始化和赋值语句的区别。
变量初始化(定义变量时为变量赋初值)是变量说明的一部分,赋初值后的变量与其后的其他同类变量之间仍必须用逗号间隔,而整个赋值语句则必须用分号结束。例如:
int x=6, y, z;
(3) 在变量说明中,不允许连续给多个变量赋初值。
例如,下面的变量说明语句是错误的:
int x=y=z=6; /* 错误!*/
必须写为:
int x=6, y=6, z=6;
而赋值语句却允许连续赋值。
请读者注意,写成如下形式是可以的:
int y, z, x=y=z=5;
这是因为,x被赋予了一个(赋值)表达式作为其初值,语法上并没有问题。
(4) 注意赋值表达式和赋值语句的区别。
赋值表达式是一种表达式,它可以出现在任何允许表达式出现的地方,而赋值语句则不能。
例如,下面的语句是合法的:
if((x=y 5)>0) z=x;
语句的功能是,若表达式x=y 5大于0,则将x值赋给z。
但下面的语句是非法的:
if((x=y 5;)>0) z=x; /* 错误!*/
因为“x=y 5;”是语句,不能出现在表达式中。
4.3 数据输入输出的概念及在C语言中的实现
在讨论输入输出时,要注意以下几点。
(1) 所谓输入/输出,是相对计算机主机而言的。
(2) C语言无输入/输出语句,所有的数据输入/输出均由相应的库函数实现,因此都是函数语句。
(3) 本章介绍的输入函数是从标准输入设备(键盘)输入数据。
(4) 本章介绍的输出函数是向标准输出设备(显示器)输出数据。
(5) 在使用C语言库函数时,要用编译预处理命令“#include”将有关的“头文件”包含到源文件中。
使用标准输入/输出库函数时,要用到stdio.h文件,因此源文件开头应有以下编译预处理命令:
#include
或者:
#include “stdio.h”
其中,stdio是standard input & output(标准输入/输出)的意思。
在大部分C编译系统下,考虑到printf和scanf两个函数使用频繁,所以系统允许在使用这两个函数时不加上述编译预处理命令。
4.4 字符数据的输入输出
4.4.1
putchar函数(字符输出函数)
putchar函数是单个字符输出函数,其功能是在屏幕上输出单个字符。
其一般形式为:
putchar(字符变量);
例如:
putchar(‘C’); /*
输出大写字母C */
putchar(c); /*
输出字符变量c的值 */
putchar(‘103’); /* 输出字符C */
对可视字符直接输出,对控制字符则直接执行控制功能,不在屏幕上显示。例如:
putchar(‘n’); /*
换行 */
putchar(‘a’); /*
响铃 */
【例4.1】输出单个字符:
#include
main()
{
int c;
char a;
c=65;
a=’B’;
putchar(c);
putchar(‘n’);
putchar(a);
putchar(‘n’);
}
正常输出时,函数返回值为显示的代码值;出错时返回EOF(即-1)。
4.4.2
getchar函数(键盘输入函数)
getchar函数是字符输入函数,其功能是从键盘上输入一个字符,一般形式为:
getchar();
通常把输入的字符赋给一个字符变量,构成赋值语句,例如:
char c;
c = getchar();
【例4.2】输入单个字符并输出:
#include
main()
{
int c;
printf(“Enter a character:”);
c = getchar();
printf(“%c—>hex%xn”, c,c);
}
使用getchar函数还应注意几个问题。
(1) getchar函数只接受单个字符,输入数字也按字符处理。输入多于一个字符时,只接收个字符。
(2) 正常输入时,本函数返回读取的代码值;出错时返回EOF(-1)。
(3) 使用本函数前,应包含stdio.h文件。
(4) 在C语言集成编辑环境下运行本程序时,将临时退出C集成编辑环境,进入用户屏幕,等待用户输入。输入完毕后显示输出结果,按任意键后,返回集成编辑环境。
(5) 若仅仅要显示所输入的字符,则可用下面两行的任意一行语句:
putchar(getchar());
printf(“%c”, getchar());
4.5 格式输入与输出
4.5.1
printf函数(格式输出函数)
printf函数是C语言中使用广泛的输出函数,称为格式输出函数。printf的末一个字母f即为“格式”(format)之意。该函数的功能是按用户指定的输出格式,将指定的数据显示到屏幕上。前面的例题中已多次使用过该函数。
1. printf函数调用的一般形式
printf函数是一个标准库函数,它的函数原型在头文件stdio.h中,一般编译系统要求在使用printf函数前,必须包含这一头文件。printf函数调用的一般形式如下:
printf(“格式控制字符串”, 输出列表);
其中的“格式控制字符串”用于指定输出格式。格式控制串由格式字符串和非格式字符串两种元素组成。格式字符串是以%开头的一个字符串,在%后面跟有各种格式字符,用以说明输出数据的类型、形式、长度、小数位数等。
(1) %d:表示按十进制整型格式输出。
(2) %ld:表示按十进制长整型格式输出。
(3) %c:表示按字符型格式输出。
非格式字符串在输出时照原样显示,在显示中起提示作用。
在“输出列表”中,给出了各个输出项,格式字符串和各个输出项在数量和类型上要求一一对应。
【例4.3】输出单个字符:
#include
main()
{
int a=65, b=66;
printf(“%d %dn”, a,b);
printf(“%o %on”, a,b);
printf(“%x %xn”, a,b);
printf(“%d,%dn”, a,b);
printf(“%c,%cn”, a,b);
printf(“a=%d,b=%dn”, a,b);
}
本例中6次输出了a、b的值,但由于格式控制串的不同,每次输出的结果也不尽相同。前3行分别以十进制、八进制、十六进制格式输出,第5行以字符格式输出。前3行的输出语句格式控制串中,两格式串%d之间加了一个空格(非格式字符),所以输出的a、b值之间有一个空格。第4行的printf语句格式控制串中加入了非格式字符——逗号,因此输出的a、b值之间加了一个逗号。第6行中,为了提示输出结果,又增加了非格式字符串,这些字符串均照原样输出。
2. 格式字符串
格式字符串的一般形式如下:
%[标志][输出小宽度][.精度][长度]类型
其中,用方括号括起来的项为可选项。
各项的意义如下。
(1) 类型:类型用单个字母标识,用以表示输出数据的类型,其格式符和意义如表4-1所示。
表4-1 printf输出函数的格式字符及含义
格式字符
意 义
d, i
以十进制形式输出带符号整数(正数不输出符号)
o
以八进制形式输出无符号整数(不输出前缀0)
x, X
以十六进制形式输出无符号整数(不输出前缀0x)
u
以十进制形式输出无符号整数
f
以小数形式输出单、双精度实数
e, E
以指数形式输出单、双精度实数
g, G
以%f或%e中较短的输出宽度输出单、双精度实数
c
输出单个字符
s
输出字符串
(2) 标志:标志字符为-、 、#和空格4种,其意义如表4-2所示。
表4-2 printf输出函数的标志字符及含义
标 志
意 义
–
结果左对齐,右补空格
输出符号(正号或负号)
空格
输出值为正时冠以空格,为负时冠以负号
#
对c、s、d、u类无影响;对o类,在输出时加前缀o;对x类,在输出时加前缀0x;对e、g、f 类,当结果有小数时,才给出小数点
(3) 输出小宽度:用十进制整数来表示输出所占的少位数。若实际位数多于给定的宽度,则按实际位数输出,若实际位数少于给定的宽度,则补以空格或0。
(4) 精度:精度格式符以“.”开头,后跟十进制整数。其意义是:如果输出数字,则表示小数的位数;如果输出字符,则表示输出字符的个数;若实际位数大于给定的精度,则截去超过的部分。
(5) 长度:长度格式符有h、l两种,h表示按短整型量输出,l表示按长整型量输出。
【例4.4】格式输出:
#include
main()
{
int a = 15;
float b = 123.1234567;
double c = 12345678.1234567;
char d = ‘p’;
printf(“a=%d,%5d,%o,%xn”, a,a,a,a);
printf(“b=%f,%lf,%5.4lf,%en”, b,b,b,b);
printf(“c=%lf,%f,%8.4lfn”, c,c,c);
printf(“d=%c,%8cn”, d,d);
}
本例的程序从第8行开始,以4种格式输出整型变量a的值,其中“%5d”要求输出宽度占5位,而a值为15,只有两位,故左补三个空格。第9行以4种格式输出实型量b的值,其中“%f”和“%lf ”格式的输出相同,说明“l”符对“f”类型无影响。“%5.4lf”指定输出宽度占5位,精度为4,由于实际宽度超过5,故按实际位数输出,小数位数超过4位部分被截去。第10行输出双精度实数,由于“%8.4lf”指定精度为4位,故截去了超过4位的部分。第11行输出字符量d,其中“%8c”指定输出宽度为8,故输出字符p时,左补7个空格。
使用printf函数时还要注意一个问题,那就是输出列表中的求值顺序。C标准并未规定这一顺序,故不同的编译系统求值顺序不一定相同,可以从左到右,也可以从右到左。TC、VC都是按从右到左的顺序进行求值的。
【例4.5】函数调用时的参数传递顺序:
#include
main()
{
int i = 8;
printf(“%dn%dn%dn%dn%dn%dn”,
i,–i,i ,i–,-i ,-i–);
}
由于函数调用时参数的求值顺序(确切地说,是函数参数的传递顺序)并非C语言本身的内容,与具体的编译系统有关,故考试命题时,多回避此类题目。
【例4.6】 ,–应用举例:
#include
main()
{
int i = 8;
printf(“%dn”, i);
printf(“%dn”, –i);
printf(“%dn”, i );
printf(“%dn”, i–);
printf(“%dn”, -i );
printf(“%dn”, -i–);
}
4.5.2
scanf函数(格式输入函数)
scanf函数是C语言中使用广泛的输入函数,称为格式输入函数,即按用户指定的格式从键盘上将数据输入到指定的变量中(更确切地说,是放在指定的地址处)。
1. scanf函数的一般形式
scanf函数是一个标准库函数,它的函数原型在头文件stdio.h中。与printf函数类似,一般的C编译系统也允许在使用scanf函数前不必包含stdio.h文件。
scanf函数的一般形式为:
scanf(“格式控制字符串”, 地址列表);
其中,格式控制字符串的作用与printf函数相同,非格式字符串的作用与printf函数相对(printf中的非格式字符串照原样输出,而scanf中的非格式字符串必须照原样输入)。地址列表中给出各变量的地址,地址是由变量名冠以地址运算符“&”组成的。例如,&a和&b分别表示变量a和b的地址。
&a和&b就是编译系统给a、b两个变量分配的内存地址。C语言中使用了“地址”这个概念,这是与其他语言不同的。应该区分变量的值和变量的地址这两个不同的概念。变量的地址是C编译系统为变量分配的,用户不必关心具体的地址是多少。
变量的地址和变量值的关系说明如下。
如果在赋值表达式中给变量赋值,例如:
a = 123;
则a为变量名,123是变量的值,&a是变量a的地址(该地址可以使用printf函数输出)。
但在赋值号的左边只能写变量名,不能写地址。scanf函数在本质上也是给变量赋值,但要求写变量的地址,如&a。这两者在形式上是不同的。&是一个取地址运算符,&a是一个表达式,其功能是求变量的地址(第8章介绍指针时,将对此做详细讨论)。
【例4.7】scanf的应用:
#include
main()
{
int a, b, c;
printf(“enter a,b,cn”);
scanf(“%d%d%d”, &a,&b,&c);
printf(“a=%d,b=%d,c=%dn”, a,b,c);
}
本例中,由于scanf函数本身不能显示提示信息,故先用printf语句在屏幕上输出提示“enter a,b,c”,要求用户输入a、b、c的值。执行scanf语句后进入用户屏幕,等待用户输入数据。用户输入“1 2 3”后,按Enter键,此时,系统又返回到集成编译环境。在scanf语句的格式串中,由于没有非格式字符在“%d%d%d”之间作为输入时的间隔,因此在输入时要用空格、Tab键或回车键作为相邻两个输入数据之间的间隔。例如:
1 2 3
或者:
123
或者:
1
2
3
2. 格式字符串
(1) 格式字符串的一般形式为:
%[*][输入数据宽度][长度]类型
其中,用方括号括起来的项为可选项,各项的含义如下。
① 类型:表示输入数据的类型,其格式符和意义如表4-3所示。
表4-3 格式符及其含义
格 式
字符意义
d, i
输入十进制整数
o
输入八进制整数
x
输入十六进制整数
u
输入无符号十进制整数
f或e
输入实型数(用小数形式或指数形式)
c
输入单个字符
s
输入字符串
② 星号“*”:称作抑制符,用以表示该输入项读入后不赋给相应的变量,即跳过该输入值。例如:
scanf(“%d %*d %d”,
&a,&b);
当输入“7 8 9”时,把7赋给a,8被跳过,9赋给b。
③ 宽度:用十进制整数指定输入的宽度(即字符数)。
例如:
scanf(“%3d”, &a);
输入123456后,只把123赋予变量a,其余部分被截掉。
又如:
scanf(“%4d%4d”, &a,&b);
输入12345678后,将把1234赋给a,而把5678赋给b。
④ 长度:长度格式符为l和h,l用于输入长整型数据(如%ld)和双精度浮点数(如%lf)。h用于输入短整型数据。
(2) 使用scanf函数时,须注意以下几点。
① scanf函数中没有精度控制,如scanf(“%6.2f”, &a);是非法的。不能企图用此语句输入小数位数为2的实数。
② scanf中要求给出变量的地址,如给出变量名,则会出错。如scanf(“%d”, a);是非法的,应将a改为&a才合法。
③ 在输入多个数值数据时,若格式控制串中没有非格式字符作为输入数据之间的间隔,则可用空格、Tab或回车符作为间隔。C编译程序在遇到空格、Tab、回车符或非法数据(如对“%d”输入“12A”时,A即为非法数据)时,即认为该数据结束。
④ 在输入字符数据时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。例如:
scanf(“%c%c%c”,
&a,&b,&c);
如果输入为:a b c(即以空格分隔),则把‘a’赋给a,‘
’赋给b,‘b’赋给c。
只有当输入为:abc(即连续输入abc)时,才能把‘a’赋给a,‘b’赋给b,‘c’赋给c。
如果在格式控制中加入空格作为间隔,例如:
scanf(“%c %c %c”,
&a,&b,&c);
则输入时,各数据之间必须加空格。
【例4.8】用scanf函数输入字符数据:
#include
main()
{
char a,b;
printf(“enter characters a,bn”);
scanf(“%c%c”, &a,&b);
printf(“%c%cn”, a,b);
}
从两次运行的结果可以看出,由于scanf格式控制串“%c%c”中没有空格,输入A B,结果输出只有A。而输入改为AB时,则可输出AB两个字符。
【例4.9】用scanf函数输入字符数据:
#include
main()
{
char a,b;
printf(“enter characters a,bn”);
scanf(“%c %c”, &a,&b);
printf(“n%c%cn”, a,b);
}
本例表明,因为scanf格式控制串“%c %c”之间有空格,所以输入的数据之间必须以空格间隔,以其他字符间隔是得不到正确结果的。
如果格式控制串中有非格式字符,则输入时也要输入该非格式字符。
例如:
scanf(“%d,%d,%d”,
&a,&b,&c);
其中,用非格式符“,”作为间隔符,若想给a、b、c分别输入1,2,3,则输入应为:
1,2,3
又如:
scanf(“a=%d,b=%d,c=%d”,
&a,&b,&c);
则输入应为:
a=1,b=2,c=3
如输入的数据与输出的类型不一致时,虽然编译能够通过,但结果可能不正确。
【例4.10】输入数据与输出数据的类型不一致:
#include
main()
{
int a;
printf(“enter a numbern”);
scanf(“%d”, &a);
printf(“%ld”, a);
}
这是TC和VC各自的输出结果,可见二者是不同的。
在TC中,由于输入数据类型为整型(2字节),而输出语句的格式串中说明为长整型(4字节),因此输出结果和输入数据不符。但在VC中,整型变量和长整型变量均占4个字节,因此输出结果没有问题。
如果输入数据与输出数据的类型一致(如例4.11),则两个编译系统下的运行结果相同。
【例4.11】输入数据与输出数据的类型一致:
#include
main()
{
long a;
printf(“enter a long integern”);
scanf(“%ld”, &a);
printf(“%ld”, a);
}
【例4.12】输入小写字母,输出大写字母:
#include
main()
{
char a,b,c;
printf(“enter characters a,b,cn”);
scanf(“%c %c %c”, &a,&b,&c);
printf(“%d,%d,%dn%c,%c,%cn”, a,b,c, a-32, b-32, c-32);
}
本例中输入的是三个小写字母,输出的是与其对应的ASCII码和相应的大写字母。
【例4.13】输出各种数据类型所占的字节数:
#include
main()
{
int i;
long l;
float f;
double d;
char c;
printf(“nint:%dnlong:%dnfloat:%dndouble:%dnchar:%dn”,
sizeof(i), sizeof(l), sizeof(f), sizeof(d), sizeof(c));
}
本例输出各种数据类型所占的字节数(左、右分别为TC和VC运行结果截图)。可以看出,TC和VC的整型变量所占的字节数是不同的。
4.6 结构化程序设计的方法
结构化程序便于书写,便于阅读,便于修改和维护,因而减少了程序出错的机会,提高了程序的可靠性,保证了程序的质量。所以C语言中十分强调结构化程序设计。一般来讲,采取以下方法可以保证得到结构化的程序:
◎
自顶向下。
◎
逐步细化。
◎
模块化设计。
◎
结构化编码。
早在1966年,Bohra和Jacopini就提出了结构化程序设计使用的三种基本结构:顺序结构、分支结构、循环结构。理论上已经证明,任何复杂的程序均可使用这三种基本结构来实现。
在程序设计中,经常提到“算法”这一概念。实际上,算法是一个广义的概念,不要认为只有程序设计才需要算法。为解决一个问题而采取的方法和步骤就是算法。当然,本书所关心的仅限于程序的算法,即计算机能执行的算法。例如,让程序完成“先输入一个小写字母,再转换成大写字母,后输出该大写字母”这一功能,就是顺序算法;让程序完成“如果a>b则输出a,否则输出b”这一功能,就是分支算法,或称选择算法;让程序完成“求100以内自然数之和”这一功能,就是循环算法。
算法有不同的表示方法,例如自然语言、框图(程序流程图)、伪代码、PAD图、N-S图等。C语言文献中多使用框图与N-S图。下面介绍一下三种基本结构的框图和N-S图。
(1) 顺序结构。就是一个程序从行一直运行到后一行,也就是程序从头到尾顺序运行,其算法可以用图4-2(a)所示的框图和N-S图来表示。
(2) 分支结构。亦称为选择结构,它依据一定的条件选择执行路径,而不是严格按照语句出现的物理顺序执行。分支结构程序设计方法的关键,在于构造合适的分支条件和分析程序流程,根据不同的程序流程选择适当的分支语句。分支结构适合于带有逻辑或关系比较等条件判断的计算,设计这类程序时,往往都要先绘制其程序流程图,然后根据程序流程写出源程序,这样做,把程序设计分析与所使用的编程语言分开,使得问题简单化,易于理解。分支结构的算法可以用图4-2(b)所示的框图和N-S图来表示。
(a) 顺序结构的框图与N-S图
(b) 分支结构的框图与N-S图
(c) 循环结构(当型)的框图与N-S图
(d) 循环结构(直到型)的框图与N-S图
图4-2 结构化程序设计中各种结构的流程图与N-S图
(3) 循环结构。亦称重复结构,程序根据给定的条件反复执行某个程序段。给定的条件称为循环条件,反复执行的程序段称为循环体。
有两类循环结构。
① 当型(while)循环结构。其特点是,在给定条件成立时,反复执行某程序段,直到条件不成立为止。其算法可以用图4-2(c)所示的框图和N-S图来表示。
② 直到型(until)循环结构。其特点是,先执行某程序段,然后判断给定的条件是否成立,如果成立,则继续执行该程序段,否则退出循环。其算法可以用图4-2(d)所示的框图和N-S图来表示。
本章后续各节分别介绍这三种基本结构,并结合具体的例题讨论算法与流程。
4.7 顺序结构程序设计
4.7.1
顺序结构的程序
顺序结构是简单的一种基本结构,程序中的语句自上而下执行,既无“回头”,又无“跳转”,是一种“直线式”的执行,其算法结构已示于前面的图4-2(a)。
4.7.2
顺序结构程序的案例实训
【例4.14】输入三角形的三边长,求三角形的面积。
若已知三角形的三边长a、b、c,则求三角形面积的公式(海伦公式)为:
其中s = (a b c)/2。
源程序如下:
#include
#include
main()
{
float a,b,c,s,area;
scanf(“%f,%f,%f”, &a,&b,&c);
s = 1.0/2*(a b c);
area = sqrt(s*(s-a)*(s-b)*(s-c));
printf(“a=%7.2f,b=%7.2f,c=%7.2f,s=%7.2fn”, a,b,c,s);
printf(“area=%7.2fn”, area);
}
程序自上而下顺序执行,首先输入三角形的边长(当然要保证任意两边之和大于第三边,否则将出现运行错误),然后计算边长和的一半,再利用海伦公式求三角形面积,后顺序输出三条边的长度、三边和的一半以及三角形的面积。
【例4.15】求方程ax2 bx c=0的根,a、b、c由键盘输入,设b2-4ac>=0。
求根公式(韦达定理)为:
,
令:
,
则x1=p q,x2=p-q。
求方程根的源程序如下:
#include
#include
main()
{
float a,b,c,disc,x1,x2,p,q;
scanf(“a=%f,b=%f,c=%f”, &a,&b,&c);
disc = b*b – 4*a*c;
p = -b/(2*a);
q = sqrt(disc)/(2*a);
x1=p q; x2=p-q;
printf(“nx1=%5.2fnx2=%5.2fn”, x1,x2);
}
程序同样是按照自上而下的顺序执行的,首先输入系数a、b、c的值(当然要保证b2-4ac>=0,否则将出现对负数开方这一运行错误),然后计算判别式的值,再利用韦达定理求两个实根,后顺序输出两个实根。
上述两个例子虽然很简单,但说明了顺序程序设计算法的概念。
评论
还没有评论。