版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第1章C语言入门
第2章基本数据类型
第3章运算符与表达式
第4章结构化程序设计
第5章数组
第6章函数
第7章指针
第8章自定义数据类型
第9章从C到C++
第10章类与对象
第11章继承和多态1.1初识C程序1.2C程序从编辑到运行1.3变量与赋值1.4输入与输出1.5流程控制1.6函数1.7编程风格1.1初识C程序对于初学者来说,C语言的词汇即关键字,接近于我们使用的自然语言(这里指英语),在某种程度上可以见名知义。下面就让我们通过一个简单的程序来认识和了解C语言。【例1.1】在屏幕上输出一行文字:欢迎使用C语言!对于上述代码,我们需要进行编辑、保存、编译和运行,从而在屏幕上输出相应的文字。编辑代码,必须有一个可以进行文字编辑的软件。Windows操作系统中自带的记事本或者MSWORD等软件,均可以完成代码的编辑与存储功能。在C语言程序设计中,程序代码编写完成后保存在扩展名为“.c”的文件中,该文件即为源程序文件。我们将上述代码保存在Lianxi_1_1.c源程序文件中。由于C语言是高级语言,因此需要将源程序翻译成计算机可以识别的机器语言,也就是要对源程序进行编译。程序在编译成功以后,即可以运行,在屏幕上输出相应的文字。程序执行后,输出结果显示在Windows的Console控制台(也称作Windows的命令行DOS框,本书中简称为控制台)中。运行结果中,在标题栏列出了当前运行的程序“Lianxi_1_1.exe”,该程序即源程序编译之后的可执行程序。控制台上显示出要求输出的文字“欢迎使用C语言!”,以及该程序执行所用时间与返回值。当根据控制台上的提示“请按任意键继续…”操作时,该程序运行结束。虽然例1.1仅有短短数行程序代码,但是已经具备了C语言的基本框架和特征。源程序中符号“//”后面的内容为注释,注释的作用是在源程序中对特定的代码进行简要解释,起到标记相应代码的作用,以增强程序的可读性,尤其是在复杂的源程序文件中,注释对理解源代码起到了非常重要的作用。当程序运行时,注释不会对程序产生任何作用。C语言中的注释有两种形式:(1)单行注释:使用双斜线符号“//”注释其后的内容,表示双斜线以后到本行结束的内容均为注释部分。(2)多行注释:使用一对符号“/*”与“*/”完成内容注释,表示从符号“/*”开始到符号“*/”结束之间的内容均为注释,无论这些内容是在一行还是多行中。单行注释短小精悍,多用于代码中对某语句的解释。多行注释可以详细描述某个部分的具体功能。C语言编译器在编译源程序时,对注释部分忽略不计,不会为注释生成机器代码。源程序的第二行以“#”开始的部分,是一个预处理指令。该指令在对程序进行编译之前告诉预处理器,该程序要包括标准输入输出函数库。其中“stdio”是“standardinput&output”的缩写,扩展名“.h”中的“h”是英文单词head的缩写,意为头文件。C语言头文件stdio.h中包含与输入/输出相关的函数,在本程序中使用的printf( )函数即定义在该文件中。因此凡是涉及与输入/输出相关的函数时,需要确认标准函数库中是否已经定义,若已定义,则可以直接使用,并在源程序中应用上述预处理指令。代码“intmain( )”是任何C语言程序必不可少的一部分。C语言程序由一系列的函数所构成,C语言程序设计的基本单位是函数,这些函数可以在一个源文件中,也可以根据不同功能而分布在多个源文件中。在这一系列的函数中,必须有一个而且只能有一个以main为名的函数,这个函数称为主函数,整个程序由主函数开始执行,一般也是以主函数结束。该行代码中,关键字int表示该主函数需返回一个整型数值,与程序最后一行的“return0;”相对应。代码“printf("欢迎使用C语言!");”告诉计算机执行一个输出动作,它是一条可执行语句。“printf”为“printfunction”的缩写,是一个格式化输出函数,该函数在标准输入/输出文件stdio.h中定义。该函数将双引号中的内容输出到屏幕上。C语言的语法规定分号“;”是一条语句的终止符号,每一条可执行语句都必须以分号结束,但是只要符合语法,多条语句可以在一行书写,一条语句也可以在多行书写。1.2C程序从编辑到运行一个简单的C语言程序,从编写到运行经过了几个必不可少的过程,如图1.2所示。在编辑阶段,使用文字处理软件编写代码,并将文件保存为以“.c”为扩展名的源程序文件。在编译阶段,编译器(Compiler)将源程序翻译为计算机可识别和执行的机器指令,即目标程序,文件以“.obj”为扩展名。和源程序一样,目标程序也不能直接执行,需要经过连接器(Linker),将目标程序同C语言库中提供的支持程序和其他相关目标模块连接起来,然后就生成了可以直接运行的可执行文件(以“.exe”为扩展名)。连接器为C语言提供了丰富的手段,通过与外在资源的连接,迅速地扩充了C语言,从而得到了功能强大的可执行程序。Dev-C++ 是一个Windows环境下的集成开发环境,可用于C语言或者C++ 语言程序的开发。作为一款自由开源软件,它集成了众多C/C++ 语言开发环境的优点,免费且实用。Dev-C++ 遵循C11标准并兼容C99标准,其开发环境包括多页面窗口、工程编辑器以及调试器等,在工程编辑器中集成了编辑器、编译器、连接程序和执行程序,提供高亮度语法显示以减少编辑错误,具备基本的调试功能,可以进行单步语句跟踪调试。最重要的是Dev-C++ 有中文界面,这也是目前很多C语言开源软件不具备的优势。该软件可通过网络免费下载使用,在下载了该软件之后,双击该软件,软件即开始自动安装;在安装完成后第一次运行时,需要对运行环境进行配置,即选取开发界面所使用的语言,如图1.3(a)所示。这时如果选择中文,软件的开发界面则为中文模式(见图1.3(b))。下面我们结合例1.1来介绍如何使用Dev-C++ 实现从源程序编辑到程序执行的完整过程。1.源程序编辑选取菜单项【文件】→【新建】→【源代码】,进入源代码的编辑界面。按照例1.1的内容输入代码,并保存为Lianxi_1_1.c源程序文件。在学习C语言程序之初,就应该有一个良好的编程习惯,除了前文提到的对代码进行详尽的注释之外,还应该将代码编写得错落有致,不同部分之间以空行间隔,这样程序的可读性也会随之提高。2.源程序编译在程序编写完成后,选取菜单项【运行】→【编译】,如图1.6所示,即开始对源程序进行编译。编译过程中相关信息的反馈以及编译结果会显示在开发环境的编译日志中。在编译日志中,我们可以看到当前编译的文件个数、文件名及所使用的编译器的名称。编译过程中会进行C语言的语法检查,对于没有遵守语法规则所引起的错误,编译器会显示错误信息,从而使程序编写人员可以很容易地定位该错误并进行修正。如果我们将例1.1中printf语句后的分号去掉,再进行编译,就会看到,在开发界面下部的编辑器窗口中显示了错误信息,并且指明了错误产生的位置。同时,在编译日志中,也相应地指出了程序错误及错误发生的位置。在编译结果中,显示出错误发生数目(1个),而且由于编译过程中有错误产生,编译没有生成可执行程序(如图1.9所示)。3.程序执行当源程序编译成功之后,即生成了相应的可执行文件,选取菜单项【运行】→【运行】,可运行该程序。此时,运行的是编译生成的可执行文件,而不是源程序文件。这时将弹出Windows控制台窗口,显示运行结果。1.3变量与赋值【例1.2】使用C语言编写程序,实现两个整数的加法运算,并将结果显示在屏幕上。程序第一行的预处理指令引入标准输入/输出函数库,因此在程序中可以直接使用printf( )标准输出函数。在主函数main( )中,定义了三个变量,名称分别是a、b、sum。所谓变量,就是程序中用来存放数据的对象,在程序运行期间其值可以改变。每一个变量都应该有一个名字,即变量名,便于在程序设计过程中使用。C语言规定所有变量在使用前必须先定义,包括定义变量的数据类型和变量名。通常,变量的定义会放在函数的开始部分、其他可执行语句之前。C语言的变量除了可以定义为整型外,还可以定义为其他类型。不同的数据类型,对应的存储空间不同,存储的数据也不同。在定义变量的时候,需要遵从C语言的语法规则:变量的定义至少应包含变量的数据类型与变量名,即也可以通过逗号间隔,定义同一类型的多个变量:根据上述规则,例1.2中的三个变量可以分别定义,如下:由于这三个变量均为整型变量,也可以定义为变量必须先定义后使用,如果变量在使用之前没有定义,则在对程序进行编译时,编译器会返回错误信息,指出该变量在使用前没有定义。C语言强制要求变量在使用之前被定义,可以起到以下作用:
(1)如果在定义变量时明确指定了数据类型,则程序在编译时就能为该变量分配相应的存储空间,并检查该变量的使用是否正确。(2)在定义变量时,除了指定数据类型,还需要为变量命名,如例1.2中的变量名a、b和sum。为变量命名就好像为饭店的每一个包厢指定名称一样,便于程序设计过程中对其进行操作。C语言规定变量的命名需要遵循一定的规则:①变量名只能由字母、数字或下划线组成;②变量名的第一个字符只能是下划线或者字母。此外,C语言对字母的大小写敏感,即认为大写字母与小写字母是两个不同的字符。因此在上述变量名中,firstName与FirstName是两个不同的变量名。除了上述两项规则以外,C语言的相关标准并没有规定变量名的长度,以及如何给变量命名,因此变量名的选择相对来说是自由的。而且C语言也没有限定变量名的长度,理论上讲,变量名可以无限长。但是为了程序书写的便利以及阅读的方便,变量名应控制在有限长度内,并且变量的名字应该有一定的含意(与英文含意相对应)。变量必须先定义后使用,但是变量也不能重复定义,因为在编译时会根据变量的类型进行空间分配,如果变量重复定义,则编译器会给出错误信息。在变量被定义以后即可以按照其数据类型来使用。变量可以在使用的时候赋值,也可以在定义的时候赋值。在定义的同时对变量进行赋值称作变量的初始化。如果变量在定义之后、使用之前没有赋值,变量中所存储的数据不确定,则编译程序时并不会出错,但是程序执行的结果会出错。1.4输入与输出在例1.2的程序中,对变量a和b分别赋值23与24,那么该程序只能实现对整数23与24的求和运算。如果我们想要实现对任意两个整数的求和计算,则需要将程序做适当的修改,如下例。【例1.3】编写程序,实现对任意两个整数的求和运算。对例1.3程序编译成功之后,运行该程序,Windows的控制台第一行显示结果如图1.11所示。通过键盘输入数字23之后按回车键,则显示结果如图1.12所示。通过键盘输入数字24之后按回车键,则程序计算出两个整数的和。在程序执行的过程中实现了简单的人机交互,按照程序执行过程中对数据类型的要求,通过键盘分别输入两个整数,从而实现了对任意两个整数的求和计算。在例1.3中,使用了前面提到的标准输出函数printf,给用户进行提示,并且使用了一个新的函数scanf,用于获取从键盘输入的信息。函数scanf与函数printf一样,都被定义在了标准输入/输出函数库<stdio.h>中。因此,通过程序的预处理指令“#include<stdio.h>”,即可在程序中使用这两个函数。在例1.3中,函数scanf通过逗号分隔开两个参数,分别是“%d”和“&a”。第一个参数,我们在例1.2中的函数printf中也用到了,该参数是格式控制字符串,指出程序希望接收的输入数据。字符串“%d”中,字符“d”指出该数据应该是十进制的整型数据(字母d即decimal的首字母),“%”是一个特定的字符,指出其后紧跟格式控制符。函数的第二个参数“&a”中的字符“a”对应着前面定义的整型变量a,而符号“&”表示该变量的地址,又称作取地址运算符,表明了通过该语句输入的数据要存放到变量a中。符号“&”是函数scanf要求使用的,函数printf并不需要。例1.3中的标准输出函数printf有两种形式,即无格式输出和有格式输出,分别为和无格式输出时,只有一个参数,该参数被双引号括起来。程序执行时将按照双引号内的字符串原样显示,即显示有格式输出时,函数printf有两个参数,第一个参数为格式控制字符串,双引号内的字符串将按照顺序输出,但是遇到格式控制符“%d”时,将使用第二个参数,即变量sum中的数据(假设为47)对格式控制符进行替换,从而输出函数scanf与printf的一般形式分别为其中,变量列表即用逗号分隔的一个或多个变量;而格式控制字符串中,需要有对应数目的格式控制符。注意,函数scanf中变量列表的每一个变量前都需要有地址符号“&”。而函数printf正如前面所述,可以只有一个参数,即省略参数变量列表。1.5流程控制例1.3中实现了最简单的人机交互,即根据程序的提示和要求通过键盘输入两个整数,然后程序计算出两个整数的和。现在我们希望程序能够根据计算的结果,指出结果是大于0、等于0还是小于0。因此在源程序代码中,需要引入能够根据结果进行判断的语句。【例1.4】编写程序,由键盘输入两个整数,求和并判断结果是大于0还是小于0。程序编译成功后,执行该程序,并根据屏幕提示分别输入第一个整数25和第二个整数-30,如图1.14所示。在程序编译成功而开始执行时,首先提示输入第一个整数,通过键盘输入25后按回车键,将数值25赋给整型变量a;接着程序提示输入第二个整数,通过键盘输入 -30后按回车键,将数值 -30赋给整型变量b。然后,程序计算变量a与变量b的和并赋值给整型变量sum。到目前为止,程序中的语句按照它们在源代码中的顺序一句一句地被执行。这就是顺序结构。然而在执行求和语句之后,需要根据结果进行判断,不同的结果将显示输出不同的内容。选择结构就是为了完成类似的任务而产生的,在源程序中通过if语句来判断结果并根据结果输出相应的内容。对于例1.4中的if语句:可以理解为,当程序按顺序执行到if语句时,判断变量sum是否大于0,如果成立,则输出“结果大于0”。在例题中,整数a+b的结果为 -5,不满足if语句的判断条件,因此程序将不执行紧跟着if的语句,而是执行下一条if语句。同理,若该判断条件也不成立,则程序继续执行下一条判断语句。因为sum的值为 -5,小于0,if语句的条件满足,所以程序执行紧跟着该if语句的输出语句,显示“结果小于0”。if语句的出现,为程序的执行增添了多种可能性。在需要进行判断的场合,均可以根据需要使用if语句。图1.15的流程图简单示意了基于判断的选择语句。if语句的一般形式为程序执行到if语句时,首先计算条件判断表达式的结果。如果该条件成立,则执行紧跟着if的语句,否则不执行该语句。如果条件成立,有多个操作语句需要执行,可以使用“{”和“}”将条件成立时需执行的语句括起来。1.6函数如果我们继续将例题的功能复杂化,要求可以判断从键盘输入的两个数据的大小,则根据上一节的内容,我们可以很容易地将例1.4修改为例1.5。【例1.5】由键盘输入两个整数,判断结果是大于0还是小于0,并判断哪个数字较大。在分析题目的要求以及程序时,可以看到程序已经具备了两个基本功能:(1)根据求和结果,输出不同的内容。(2)根据输入数据大小,输出较大的数据。功能的不断增加,使主程序本身的功能变得模糊。如果能够将程序的代码根据功能的不同分别组织起来,程序在阅读及编写上将会变得条理清晰。C语言程序设计的基本单位就是函数,将复杂功能通过函数的形式封装起来,可以重复使用,而通过函数调用语句,就可以完成相应的复杂功能。因此根据例1.5的要求,采用函数调用形式将其改写为例1.6。【例1.6】由键盘输入两个整数,判断结果是大于0还是小于0,并判断哪个数字较大。从程序源代码中可以看到整个程序由三部分组成,我们用结构图简化为图1.16。正如前面所述,主函数main是C语言程序中必不可少的函数,程序从主函数开始执行,一般也在主函数结束运行。通过函数调用的形式将不同的功能模块组合在一起,便于程序代码的编写、阅读以及管理。函数的重复调用,也可以减少重复编写代码的工作量。主函数的起始部分:对程序后面使用到的函数进行了声明,正如前面提到的C语言对变量要求先定义后使用,对函数也有同样的要求。在本例中,因为函数定义在了主函数的后面,而主函数中又需要使用这两个函数,因此在主函数的开始部分,对两个函数进行声明以便在程序中使用。如果两个函数的定义部分写在了主函数之前,则主函数中的声明部分可以省略。编写函数的过程也就是定义函数的过程。函数定义的基本格式为函数的定义包含了函数头和函数体两部分。函数头定义函数的名字和参数。函数体则定义该函数要完成的功能。函数的命名也遵循前面提到的与变量命名一致的规则,即函数名只能由字母、数字、下划线组成,并且首字符只能是字母或下划线。函数的声明则相对要简单,只需要符合下面的格式即可:函数定义与声明的不同是显而易见的。函数的声明有时也称作是函数的原型。函数的定义、函数的声明以及函数的调用三者应一致,否则将导致编译错误。通常一个程序中可以根据需要定义任意多个函数。函数定义出现的次序和位置可以是任意的,并且这些函数可以放在一个源程序文件中,也可以根据功能的不同放在多个源程序文件中。我们前面提到的文件<stdio.h>,就将与输入/输出相关的函数整合到了一个文件中。1.7编程风格所谓编程风格,也称作程序设计风格,是指在程序编写或者设计过程中,遵循一定的规范,从而表现出来的特征。从学习一门程序语言之初就应注重培养良好的编程风格。良好的编程风格,可以使程序结构合理,逻辑清晰。良好的编程风格有助于程序的阅读、理解和维护。编写程序代码时,也需要将程序代码写得错落有致,要注意语句的缩进,不同层次的代码缩进的字符数不同。这样,编写的代码就更清晰和易于阅读。对代码进行注释,是初学者需要注意养成的一个良好的编程习惯。前面的章节中提到注释对代码起到了文档化的作用,帮助对程序进行文字性记录,有助于程序的阅读。解释程序功能的部分要做到“精”、“准”,代码阅读者根据这些注释知道应该对程序作什么样的调整。在不断的练习和代码编写过程中,要逐步地掌握注释的恰如其分,而不是做过多的注释。因此,对于注释的内容需把握以下几点:描述程序的目的、解释程序的功能、提示程序的细节。命名符合一定的规范,是我们形成良好编程风格的一个基本条件。简单地说,就是对程序编写过程中的标识符采取有含义的名字,比如对变量的命名、对函数的命名等,应该能够通过名字很容易地判断出变量所要存储的数据或者类型、函数所要实现的功能,而不是随意采用一个字母或无关的词汇进行命名。代码编写简单化,即KeepItSimple(KIS),是作为初学者应该掌握的一个基本原则。简单的程序容易编写,产生的错误就较少,同时也易于维护。程序代码简单,人们就不必为了读懂它而花费较多的时间和精力。代码编写得简单,不需要动脑就可以看明白,是对该原则的最好描述。2.1整型数据2.2字符型数据2.3浮点型数据2.4格式化的输入与输出2.1整型数据2.1.1整型数据的进制整型数据,顾名思义,即是没有小数点部分的整数数据。整型数据以二进制补码的形式在内存中存储。整型常量即整型常数,可正可负。在C语言中,整型常量有三种形式,即八进制整数、十进制整数和十六进制整数。十进制的计数规则为逢10进1,基本数字为0、1、2、3、4、5、6、7、8、9。十进制数的每一位都是10的指数幂。八进制的计数规则为逢8进1,基本数字为0、1、2、3、4、5、6、7。在C语言中,八进制整数的表示以0开头,如0367表示八进制数367。八进制数的每一位都是8的指数幂,因此可以转化为十进制数。同理,十进制数也可以转换为八进制数,其规则为该十进制数除以8,求得商和余数,并继续用商除以8,直到商比8小为止。如十进制数247除以8等于30余7,30大于8,所以继续;30除以8等于3余6,3比8小,因此将所剩的余数按自下而上的顺序排列即得八进制数367。该计算过程用图2-2方法表示则更清晰。十六进制的计数规则为逢16进1,基本数字包括0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。在C语言中,十六进制的整数以0x或者0X开头,如0x367,0X1AF2。十六进制整数与十进制整数之间也可以相互转换,其方法与八进制整数和十进制整数之间的转换一样。而将十进制整数871转换为十六进制,参考图2-2可得图2-3,即得到十六进制数0x367。十六进制整数与八进制整数之间也可以相互转换,可以通过十进制作为中间转换数制,即将十六进制数先转换为十进制数,再将十进制数转换为八进制数。二进制是计算技术中广泛采用的一种数制。二进制使用0和1两个数码来表示数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,是由18世纪德国数理哲学大师莱布尼兹(Leibniz)发明的。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以二进制补码的形式存储。设计补码的目的是简化运算规则。所谓补码的概念,主要是针对负数而言的。对于一个正数来说,原码、反码及补码是一样的。而对于负数来说,其补码等于其绝对值按位取反再加1。二进制数向八进制数或十六进制数的转换十分方便。由二进制数到八进制数,只需从右向左,取三位合一位,不够三位的前面补0,如图2-4所示。同理由二进制数转换到十六进制数,只需从右向左,取四位合一位,不够四位的前面补0。而八进制数、十六进制数向二进制数的转换,仅需对应地将每一位用三位或四位二进制数表示即可。2.1.2整型变量整型变量的基本类型符为int(英文integer的缩写),在整型的表示符号int之前,分别加上不同的修饰符,便可以扩展整型的类型为基本整型:int。短整型:shortint,可简写为short。长整型:longint,可简写为long。双长整型:longlongint,可简写为longlong。在数学上,整数可以是正数或负数。整型数据的正、负之分,在C语言中是用有符号数与无符号数的概念来定义的。如果预先知道某变量要处理的数据不会有负数存在,这时候就可以使用无符号类型。无符号和有符号类型的区分是由类型符int前的修饰符所定义的,通过有符号(signed)和无符号(unsigned)两个修饰符来表示。如果没有加修饰符,则默认为有符号(signed)。由于数据在内存中的存储占用一定的空间(字节数),因此数据就有相应的取值范围。C语言本身并没有明确规定各类型数据占多少字节,仅保证了short类型不比int长,而long类型不会比int短。早期C语言这种规定的目的是适应不同的机器。在计算机中,数据使用二进制表示,即0或1,每一位(bit)就代表了一个0或者1。每8个位组成一个字节(byte),字节是数据存储的单位。例如,在C语言的数据类型中,通常把short定义为2个字节,即16位。虽然C语言本身没有规定各种数据类型所占字节数,但是C语言标准中提出了将相关的数值取值范围的限制定义在头文件limits.h、float.h、stdint.h中。因此如果我们要确定某一数据类型所占字节数,可以通过查阅这几个文件或者通过sizeof( )函数来确定数据类型的字节数。各种数据类型所占字节数和取值范围与编译器如何实现C语言标准有很大关系,本书列出Dev-C++ 中的整型数据的取值范围,如表2-1所示。在确定了编译系统的各数据类型的取值范围之后,就可以根据程序对相应数据的需求,来设计变量的类型。比如人的年龄,就可以使用unsignedchar类型。由于表2-1的取值范围的存在,在计算过程中,会出现例2.1中超出某数据类型取值范围的状况存在。2.1.3整型常量上一节中提到了整型常量即是整型常数,包括十进制数、八进制数和十六进制数。我们在例2.1中使用到的整数,都可以作为整型常量来使用。整型变量根据所表示数字的范围不同以及正负数的不同,可以有多种扩展类型。由此可知,整型常量也不局限于int类型。C语言标准(C11)中,对于扩展整型常量的表示法,通过添加后缀来实现,如表2-2所示。以一个十进制整数为例,由表2-2可知,如果该整数没有加后缀,则根据其数值所在的范围来确定它的类型。2.1.4整数的存储当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以二进制补码的形式存储的。下面以短整型数据的存储为例来介绍计算机内部整型数据的表示。如果有一个短整型变量a:首先我们将其转换为二进制数,有十进制数 123二进制数 1111011二进制补码 1111011那么根据表2-1,短整型shortint的数据位数为16位,因此在内存中,该数字存储为整型数据分为有符号数和无符号数。对于无符号数,根据表2-1,unsignedshort的数据位数为16位,其取值范围为0~65 535,在内存中的表示如下:0:65 535:对于有符号数,其最左边的一位(称作最高位)表示符号位,如果该位的数字为1,则表示负数;如果为0,则表示非负数(0或正数)。有符号的shortint数据同样占据16位的存储空间,其中第一位为符号位,因此数字0只能用15位表示,则有0:最大的正数为32 767。如果正数32767 + 1,则有符号位是1,所以该数字为负数(-32 768)。根据前面讲到的负数在计算机中存放的补码是该数的绝对值的原码取反再加1,我们对负数 -32 768取绝对值,得到32 768。其二进制为对其取反,得再加1,则有所以,根据上述推导过程,我们可以得出当有符号位时,32 767 + 1在计算机中表示为 -32 768。那么 -32 767为以此类推,最大的负数为-12.2字符型数据2.2.1字符型变量字符型变量用来存放程序中使用的字符型数据。字符型变量通过关键字char来定义。字符型变量属于整型数据类型的范畴,可以参与运算,也可以使用signed(有符号)和unsigned(无符号)两个修饰符来修饰。其中,signed可省略,即在没有使用修饰符来定义字符型变量时,则认为是signedchar。使用signed或者unsigned定义字符型变量时,二者的取值范围不同。signedchar型变量的最高位为符号位,因此仅能存放7位二进制数,取值范围为 -128~127;使用码值0~127表示标准ASCII字符,使用码值 -1~-128表示扩展的ASCII字符。unsignedchar型变量的最高位不是符号位,因此可以存放8位二进制数,取值范围为0~255;使用码值0~127表示标准ASCII字符,使用码值128~255表示扩展的ASCII字符。字符型变量的存储单元长度和取值范围如表2-3所示。2.2.2字符型常量正如整型数据一样,字符型数据既可以是变量,也可以是常量。字符型常量是单引号括起来的字符,如 'a' 。注意,这里讲的字符是指ASCII和EASCII字符集中的单字节字符。双字节字符(如中文字符),不能定义为字符型常量。C语言中还有一类字符称作转义字符(escapesequence),这类字符是以反斜杠“\”开头的字符序列,它包含了如表2-4所示的转义字符。2.3浮 点 型 数 据C语言的基本数据类型之一的浮点型数据,用来表示实数。浮点型数据有三种类型,即单精度(float)、双精度(double)和长双精度(longdouble)。浮点型数据在内存中的存储方式与整数不同,它由三部分构成:由此,导致浮点型数据的精度是不确定的,即浮点数只能近似地表示某个实数,而不是精确地等于某个实数。具体来说,这个实数是由一个整数乘以某个基数(常用2)的整数次幂得到的。在计算机中,数值都是用二进制数字表示的,对于4个字节的单精度浮点数(float)而言,总共有32位,其中符号位占1位,尾数部分占23位,指数部分占8位。从这里也可以看出,尾数部分占的位数越多,表示的浮点数有效数字越多,精度越高;指数部分占的位数越多,则能表示的数值范围越大。因此,我们可以得到单精度浮点数的十进制表示的有效数字个数为10n-1≥223-1即n≥log10223
这里n的最小值为7,当浮点数的绝对值大于等于1时,小数点后有效位数为6位。对于双精度浮点数(double)而言,占8个字节共64位,其中指数部分为11位,符号部分占1位,尾数部分为52位,因此它的有效数字为15~16位。同理可得到长双精度浮点数(longdouble)的有效数字为18~19位。由于浮点数的近似表示特点,导致了浮点数参与计算时容易产生误差,特别是当参与运算的两个数值相差很大时。浮点型常量的表示法可以通过在浮点数后加后缀来实现,后缀可以是f或F(表示float类型)、l或L(表示longdouble类型);如果没有后缀,则认为是double类型。也可以通过科学计数法表示浮点型常量,通过使用指数符号e(或E)来表达,其格式为2.4格式化的输入与输出2.4.1printf函数函数printf的作用是向系统默认的输出设备(一般是显示器)按照指定格式输出信息。虽然C语言要求变量与函数在使用前一定要声明或定义,但作为一个特例,在使用printf的时候可以不包含stdio.h(在这种情况下,编译器一般会警告启用了内置不兼容的隐式声明的printf)。printf函数的一般格式为作为函数而言,printf函数有返回值,其返回值的类型是整型。当成功执行该函数后,返回输出的字符的个数;如果有错误发生,则输出负值。printf函数包含了两个参数,即格式控制字符串和输出列表。输出列表是需要输出的数据,可以是变量,也可以是表达式。不同的输出变量与表达式之间需要使用逗号分隔开。格式控制字符串规定了输出列表中的数据输出的方式,因此输出列表中所要输出的数据的个数应与格式控制字符串中指定的数据格式的个数一一对应。如果格式控制字符串中指定格式的数据个数多于输出列表个数,则会输出错误数据;如果输出列表中的数据个数多于格式控制字符串中指定格式的数据个数,则多出的输出列表中的数据不被输出。printf函数的两个参数中,输出列表可以省略。当没有输出列表时,printf函数可以输出格式控制字符串中的信息。格式控制字符串,顾名思义,是一个字符串,它的一般格式为printf函数中的每一个指定格式的说明总是从符号“%”开始,然后才是格式控制符,它的作用是将输出数据转换为指定的格式,在符号“%”与格式控制符之间,可以加入不同的格式控制选项。1.格式控制符printf函数中可使用的格式控制符如表2-5所示。2.[标识]格式控制字符串中的标识可以根据需要设置:(1)如果标识没有指定,则表示输出为右对齐,左边填充0或者空格。(2)如果标识是“ - ”,则表示输出为左对齐,右边根据需要填充0或者空格。(3)如果标识是“+”,则表示输出结果为有符号数,根据数据转换结果添加正号( + )或者负号( - )。(4)如果标识是空格,若输出结果为正数,则显示空格;若输出结果为负数,则显示负号。(5)如果标识是“#”,则当格式控制符为c、d、i、s、u中任意一种时,不起作用,而①当格式控制符为“o”时,输出时加前缀0;②当格式控制符为“x”或“X”时,输出时分别加前缀0x或0X;③当格式控制符为“g”或“G”时,总是显示小数点及无意义的0;④当格式控制符为“e”或“E”或“f”时,总是显示小数点。3.[宽度][精度]对于整型数据,[精度]选项不起作用,只有[宽度]选项起作用。当指定宽度为m时,如果输出的整型数据的位数小于m,则左端补空格;若大于m,则以整型数据的实际长度输出。对于浮点型数据,[宽度]和[精度]两个选项均起到控制作用。当宽度为m、精度为n时,如果输出的浮点型数据的位数小于m,则左端补空格;若大于m,则以浮点型数据的实际长度输出。如果浮点型数的小数点后位数小于n,则右端补0,凑够n位小数;如果浮点型数据的小数点后位数大于n,则第n+1位四舍五入后输出n位小数。对于字符串,[宽度]和[精度]两个选项均起到控制作用。当宽度为m、精度为n时,其作用是输出m列n个字符。如果字符串的实际长度大于m,则按字符串实际长度输出;若小于m,则左补空格;如果n小于m,则输出m列,不足部分补空格;若n大于m,则保证n个字符的正常输出。4.printf函数输出详解(1) %c:作用:以单个字符形式输出。说明:格式符c前可加入[标识]及[宽度]控制。(2) %d(或者%i):作用:整数以有符号的十进制整数输出,正整数的符号忽略。说明:格式控制符 %i与 %d的使用一致,格式符d(i)前可加入[标识]、[宽度]控制,前还可加字符l或L输出长整型。(3) %e(或者%E):作用:以指数形式输出浮点数。说明:可有效控制浮点型数据的输出格式,格式符e(E)前可加入[标识]、[宽度]、[精度]控制。(4) %f:作用:以小数形式输出浮点数,小数点后保留6位数字。说明:可有效控制浮点型数据的输出格式,格式符f前可加入[标识]、[宽度]、[精度]控制。(5) %g(或%G):作用:系统自动选取控制符“%f”或“%e”格式中输出宽度较短的格式输出浮点数,并且不输出无意义的0。说明:可有效控制浮点型数据的输出格式,格式符g(G)前可加入[标识]、[宽度]、[精度] 控制。使用“%G”时,若输出指数形式,则指数部分使用大写的E。(6) %s:作用:输出字符串。说明:只能用于字符串的输出,格式符前可加入[标识]、[宽度]、[精度]控制。“%s”输出字符串,是通过指向字符串第一个字符位置的指针来实现的,通过该指针将字符串中的字符依序读出,直到遇到空字符 '\0' 才停止。可以使用[标识]来控制字符串的对齐位置,也可以规定输出字符串的[宽度]及[精度](字符个数)。若指定精度n,则输出字符串中的前n个字符。如果精度n小于宽度m,则补充空格。如果精度n大于宽度m,则忽略宽度m,输出n个字符。(7) %o、%u、%x(或%X):作用:无符号整数分别以无符号八进制、无符号十进制、无符号十六进制输出。说明:用于整型数据的输出格式控制,格式符前可加入[标识]、[宽度]控制。2.4.2scanf函数scanf函数的作用是从系统默认的输入设备(例如,键盘)按照指定的格式读入信息。虽然C语言要求变量与函数在使用前一定要声明或定义,但作为一个特例,在使用scanf函数的时候也可以不包含stdio.h。scanf函数的一般格式为scanf函数按照格式控制字符串中的内容扫描从标准输入设备输入的数据,并将结果存储在地址列表中各内存地址所对应的变量或字符串中。作为函数,scanf有返回值,其返回值的类型是整型;如果scanf函数成功执行,则返回地址列表中成功赋值的参数个数。scanf函数有两个参数,分别是格式控制字符串和地址列表。地址列表中包含的是不同变量的地址,而不是变量名。所谓地址,即该变量在内存中的存储位置,通过取地址运算符“&”,可以得到变量的地址。地址列表中包含的多个地址,需使用逗号间隔开来,地址列表中所包含的地址的个数,需要与格式控制字符串中的控制符的个数相对应。scanf函数的格式控制字符串的一般格式为与printf函数不同的是,scanf函数没有[标识]和[精度]控制项。但其使用的格式控制符与printf函数所使用的基本一致。1.格式控制符scanf函数中可使用的格式控制符如表2-8所示。2.scanf函数输入详解scanf函数从标准输入设备读入数据,其方式是按照格式控制字符串中的内容,依次读取,遇到格式控制符,则将输入数据按照该格式存入对应的地址。当输入的字符与格式控制符数目不匹配时,该输入字符及其后的输入字符将不能被scanf函数读取,而继续保留在内存中。1)输入数据的读取scanf函数从标准输入设备读入数据是按照格式控制字符串中的内容依次读取的。2)输入数据的间隔因为scanf函数读入数据的方式是按照格式控制字符串中的内容依次读取的,因此,输入的数据,尤其是对同种类型的输入数据,如果使用间隔符号,比如空格或者逗号等区隔开来,则会使输入数据与地址列表中变量的对应关系更加清晰。scanf函数的格式控制符为同一类型且没有使用任何间隔符号进行区别,那么系统会将所有连续的输入都认为是第一个控制符的输入内容,直到发生下列情况:(1)遇到空格,scanf函数会将空格符后的内容认为是下一个输入数据。(2)遇到回车换行,scanf函数会将回车换行后的内容认为是下一个输入数据。(3)遇到格式无法转换的输入数据或者输入的数据与控制符不匹配,则读取失败,该数据及其后内容将不被读取而继续留在内存中。因此对于输入数据,最好是以逗号、空格等间隔开来,以方便程序阅读。3)输入数据的宽度限制scanf函数的格式控制字符串中,可以使用[宽度]参数限制所读取的输入数据的列数,系统将自动按照[宽度]限制,截取所需长度的数据,存入相应的地址中。4)格式控制符s根据C语言规定,“%s”的作用是读取输入字符串。在读取输入的字符串时,以非空格开始读入,以非空格结束读入,并且系统会自动在读入的字符串结尾加结束标志,即空字符“\0”。如果宽度大于要存入的字符数组的长度,则系统只能将与字符数组长度n一致的前n个输入字符存入数组中。对于格式输入,应注意以下几点:(1) scanf函数中使用变量的地址接收输入的数据,而不是变量名,注意符号&的使用。(2)注意数据输入的间隔。(3)在连续输入字符时,包括分隔符和转义字符在内的所有可以用键盘敲入的符号均会被视为有效的字符输入。(4)在连续输入数值时,可以通过以下符号间隔数据:①空格符、水平制表符、回车换行符;②不属于数值的非法字符;③使用域宽设定数据长度。2.4.3putchar函数putchar函数即字符输出函数,其作用是向标准输出设备输出一个字符。调用putchar函数的一般格式为putchar(c)其中,参数c可以是字符常量、字符变量、整型常量、整型变量以及表达式,putchar函数将参数的值以字符的形式向标准输出设备输出。2.4.4getchar函数getchar函数即字符输入函数,其作用是从标准输入设备输入一个字符。调用getchar函数的一般格式为getchar函数由标准输入设备读入一个字符。getchar函数读取的字符可以赋值给一个字符型变量或整型变量,也可以不赋给任何变量,仅作为表达式的一部分,参与表达式的运算。3.1概述3.2算术运算符和算术表达式3.3赋值运算符和赋值表达式3.4自增与自减运算符及其表达式3.5关系运算符和关系表达式3.6逻辑运算符和逻辑表达式3.7逗号运算符及逗号表达式3.8隐式类型转换3.9强制类型转换3.1概述运算符(operator)就是一些特定的符号,用来表示对数据执行的特定操作,也称作操作符。C语言中的运算符,根据参与运算对象的多少,可分为单目运算符(或称作一元运算符)、双目运算符(或称作二元运算符)、三目运算符(或称作三元运算符);根据参与运算的对象的结合方向,可以分为从左向右和从右向左两类;根据实现运算的作用不同,可分为算术运算符、赋值运算符、逻辑运算符、关系运算符、条件运算符、逗号运算符、位操作运算符等等。本节将重点介绍一些基本而且常用的运算符,其他运算符在后续章节的学习中将陆续介绍。表达式(expression)最基本的形式就是一个数据,也称为操作数。操作数可以是任意类型的常量或变量。将操作数与运算符结合,可以构建一个新的表达式,继而使用多个运算符连接多个操作数形成更为复杂的表达式。C语言的表达式由运算符、常量、变量所组成。表达式的结尾不能加分号。当一个表达式由多个不同运算性质的操作符和多个不同数据类型的操作数构成时,选择不同的运算顺序可能会得出不同甚至错误的结果。因此,C语言通过规定运算符的“优先级”和“结合性”来保证运算结果的正确性和唯一性。在对表达式求值时,应按运算符优先级的高低次序执行。由于乘法运算符“*”比加法运算符“+”的优先级高,因此先计算子表达式“b*c”的结果,再用该结果与a相加。如果操作数两侧的运算符优先级相同,则按运算符的结合性处理。由于加法运算符“+”和减法运算符“-”同属算术运算符,且优先级相同,而算术运算符的结合性为“从左至右”,因此先计算子表达式“a+b”的结果,再用该结果与c相减。表达式的名称由表达式中优先级最低的运算符的名称决定。表达式在通过运算实现特定功能的同时,本身也将获得一个确定的值。表达式与语句的区别在于表达式的结尾不加分号,而语句必须以分号标识结束。由“表达式”加“分号”构成的语句,称为表达式语句。3.2算术运算符和算术表达式算术运算符为双目运算符,结合性为从左至右,包括 +、-、*、/、%。其中,运算符%称作模运算符或者求余运算符。算术运算符的优先级为:算术运算符是程序设计中使用最多的一类运算符,使用方法类似于数学上的四则运算,但有两个特点需要注意:(1)除法运算符“/”连接的两个操作数均为整型数据时,结果向零取整,不进行四舍五入,直接舍去小数部分。只有除法运算符“/”连接的两个操作数中有浮点型数据时,才会出现小数部分。(2)求余运算符“%”连接的两个操作数必须同为整型数据。除了运算符“%”只能连接整型数据外,其他所有算术运算符连接的操作数都可以是任意的数据类型,计算机以这些数据所代表的数值参与运算,算术表达式的运算结果为数值。3.3赋值运算符和赋值表达式赋值运算符为双目运算符,结合性为从右至左,包括赋值运算符(=)和复合赋值运算符(*=、/=、%=、+=、-=)。赋值运算符的优先级低于算术运算符。赋值运算是将运算符右边操作数的值赋给左边操作数。因此,赋值运算符左边的操作数必须是变量(有接收数据的存储单元),右边的操作数可以是常量、变量以及表达式,只要保证有确定的值就可以。整个赋值表达式的值就是执行赋值运算后左边操作数的值。使用复合运算符的目的是简化程序的书写,使程序更加精炼,同时也可以提高编译效率。当赋值运算符两侧的操作数类型不一致时,系统自动将右操作数的类型转换为左操作数(变量)的类型。发生数据类型转换时,需要注意转换前后的取值范围是否存在越界。3.4自增与自减运算符及其表达式自增与自减运算符为单目运算符,结合性为从右至左,包括 ++ 和 --。自增与自减运算符的优先级大于算术运算符。自增运算符“++”的作用是实现对操作数的值加1,自减运算符“--”的作用是实现对操作数的值减1。表达式的值即为操作数更新后的值。自增与自减运算符要求操作数的值是允许被改变的,即操作数必须是变量(更新后的值能够被存储)。例如:以变量i为例,自增与自减运算符有两种使用形式,即前缀运算符和后缀运算符。例如:i++ 与 ++i(或i-- 与 --i)在各自作为一个独立完整的表达式时,从结果上看并没有区别。例如:然而,当i++ 与 ++i(或i-- 与 --i)作为表达式或语句的一个组成部分时,区别就表现出来了。执行表达式 ++i,先将i值加1,再以更新后的i值作为该表达式的值参与下一步运算(即“先改变,后使用”);执行表达式i++,先以i的初始值作为该表达式的值参与下一步运算,再将i值加1(即“先使用,后改变”)。例如:自增、自减运算符常用于循环控制变量的递增或者递减,也可用于指针变量,使指针指向上一个或下一个地址。3.5关系运算符和关系表达式关系运算符为双目运算符,结合性为从左至右,包括 >、<、>=、<=、==、!=。其中,前四个表示的关系分别是大于、小于、大于或等于、小于或等于,其含义与在数学上使用的一样。而符号 == 表示等于,即判断两个操作数是否相等,这一点与在前面的章节中介绍的赋值运算符 = 完全不同,这也是初学者最容易犯错误的地方。符号 != 表示不等于,即判断或者比较两个参与运算的操作数是否不相等。关系指的是参与运算的两个操作数之间的关系。操作数可以是变量,也可以是常量或表达式,但是操作数必须有确定的值。关系运算符的优先级为:关系运算符的优先级低于算术运算符,高于赋值运算符,所以有下列表达式:几个关系运算符的优先级也不同,其中,运算符 >、<、>=、<= 的优先级相同,并且均高于运算符 == 与 != 的优先级,而运算符 == 与 != 的优先级相同。因此,有下列表达式:上述两个表达式分别表示:a>b==c,先将a与b进行比较,即判断a是否大于b,之后将两者比较的结果再与c进行是否相等的比较。a!=b>c,先将b与c进行比较,即判断b是否大于c,之后将两者比较的结果再与a进行是否不等的比较。关系表达式用于判断两个操作数之间的关系是否成立,如果关系成立,则表达式的结果为真(true),即表达式的值为1;如果关系不成立,则表达式的结果为假(false),即表达式的值为0。此外,还规定了表达式的值为int类型。简单地说,关系表达式的值不是整型数值1就是整型数值0。3.6逻辑运算符和逻辑表达式逻辑运算符包含一个单目运算符(!)和两个双目运算符(&&、||),用逻辑运算符将操作数连接起来就构成逻辑表达式。逻辑运算符的优先级为:逻辑表达式与关系表达式一样,常用于选择结构中的条件判断。逻辑运算符不关心操作数的值具体为多少,只需要知道操作数的值是否为0,将值为0的操作数转换为逻辑值“假”,将值为非0的操作数转换为逻辑值“真”。整个逻辑表达式的结果只有两个:1(真)或者0(假)。1.逻辑与运算符&&符号&&表示逻辑与,相当于中文的“且”。其优先级低于逻辑非( ! )而高于逻辑或( || ),结合性为从左至右。&&为双目运算符,左右两边操作数的值全部为真(值为非0)时,表达式的结果才为真(值为1),否则表达式的结果为假(值为0),即“全真才真”。2.逻辑或运算符 ||符号 || 表示逻辑或,相当于中文的“或”。其优先级是逻辑运算符中最低的,结合性为从左至右。|| 为双目运算符,左右两边操作数的值全部为假(值为0)时,表达式的结果才为假(值为0),否则表达式的结果为真(值为1),即“有真就真”。3.逻辑非运算符!符号 ! 表示逻辑非,相当于中文的“非”,为单目运算符,其优先级与同为单目运算符的自增自减运算符级别相同。不但高于同为逻辑运算符的 && 和 ||,还高于算术运算符、关系运算符以及赋值运算符。其结合性也与所有的单目运算符相同,为从右至左。运算符!的作用是对操作数的值取反。如果操作数的值为0 (假),则表达式的结果为1 (真);如果操作数的值为非0 (真),则表达式的结果为0 (假)。针对逻辑运算有相应的真值表,以操作数a、b为例,与逻辑运算符组合后的各种可能结果如表3-1所示。3.7逗号运算符及逗号表达式在C语言中,逗号有两种用途:一种是作为分隔符使用。比如,在下列语句中分隔多个同类型的变量或多个参数:一种是作为运算符使用。使用逗号运算符连接两个表达式形成一个逗号表达式,其一般形式为逗号运算符是所有运算符中优先级别最低的,结合性为从左至右。逗号运算符又称为“顺序求值运算符”,逗号表达式按照从左至右的顺序对运算符连接的各个表达式逐一求解,即先计算表达式1的值,再计算表达式2的值,依次计算,直到计算完表达式n的值,而整个逗号表达式的值即为表达式n的值。3.8隐式类型转换在对由运算符连接不同类型数据构成的表达式进行计算之前,首先要将运算符连接的不同类型数据转换为同一类型,这一类型转换过程由系统自动完成,称为“隐式类型转换”。隐式类型转换的规则遵循将“短”的数据类型转换为“长”的数据类型,精度低的向精度高的转换,取值范围小的向取值范围大的转换,以提高运算精度。其具体实现如图3-2所示。图中向右的箭头表示转换方向,即在发生数据类型转换时,char类型和short类型的数据都必须先转换为int类型的;int类型的数据必须转换为unsigned类型的;float类型的数据必须转换为double类型的。综上所述,如果short型数据与float型数据进行混合运算,应先将两个类型的数据一同转换为double类型的。3.9强制类型转换除了依靠系统自动实现隐式类型转换外,程序设计者还可以利用强制类型转换将一个表达式转换为程序所需要的数据类型。强制类型转换的一般形式为强制类型转换运算符为单目运算符,其优先级与结合性和同为单目运算符的“!”、“++”、“--”一致。需要注意的是,隐式类型转换是为满足计算的需要而由系统自动实现的,这样的类型转换是符合算法要求的;而强制类型转换是由设计者人为控制的,在处理前应认真检查该转换是否会影响算法的逻辑性和结果的正确性。强制类型转换与隐式类型转换一样,也只是针对参与计算的数据的类型进行转换,并不实际改变变量的类型。强制类型转换与隐式类型转换的规则无关,只是根据目标(类型)将(表达式)的结果强制转换为目标类型。4.1顺序结构4.2选择结构4.3循环结构4.1顺序结构顺序结构是最简单的程序结构,结构中各语句按自上而下的顺序依次执行,如图4-1所示。在结构化程序设计中,由于三种基本结构都遵循“单入口、单出口”的原则,因此无论程序中包含了什么样的结构,程序的总流程都是按照顺序结构执行的。程序的执行始终是按照语句自上而下的顺序,在执行过程中不会有任何跳转或变化,这就是典型的顺序结构的程序执行方式。4.2选择结构在现实生活中,我们往往需要通过对给定条件的判断,决定下一步行为。在程序设计中,也会遇到相同的情况。当程序执行到某个阶段,出现了可选的不同处理方案,此时就需要根据对某一特定条件的判断,选择其中的一个分支来执行。选择结构按照程序分支的多少可以分为单分支、双分支和多分支三种形式;根据使用的关键字不同,可以分为if语句和switch语句。4.2.1if语句if语句是最常用的一种选择结构,其基本形式包括单分支选择结构、双分支选择结构以及多分支选择结构。1.单分支选择结构if语句的单分支选择结构的基本格式为或者程序的控制流程进入单分支选择结构时,首先需要对圆括号中的表达式进行判断,该表达式即单分支选择结构是否执行的条件。如果条件成立,即表达式的值非0,则执行选择结构中的语句;如果条件不成立,即表达式的值为0,则不执行选择结构中的语句,直接执行选择结构后的语句。其结构如图4-2所示。需要注意的是,如果选择结构中必须包含多条语句,则需要用“{”和“}”括起,形成复合语句。复合语句在程序执行的过程中作为完整的个体,即花括号中的语句全部执行,或者一条也不执行。2.双分支选择结构if语句的双分支选择结构的基本格式为或者程序的控制流程进入双分支选择结构时,首先需要对圆括号中的表达式进行判断,该表达式即双分支选择结构是否执行的条件。如果条件成立,即表达式的值非0,则执行选择结构中的语句;如果条件不成立,即表达式的值为0,则不执行选择结构中的语句,直接执行选择结构后的语句。其结构如图4-3所示。3.多分支选择结构if语句的多分支选择结构的基本格式为程序的控制流程进入多分支选择结构时,按照条件表达式出现的顺序进行判断,首先判断表达式1的条件是否成立,如果成立,则执行该条件控制的语句后结束选择结构;如果表达式1的条件不成立,则对表达式2进行条件判断,依此类推,按序进行;若所有的条件均不成立,则执行else后的内嵌语句。若其中有一条判断表达式成立,则其后的判断表达式将不再执行,因此符合多选一的原则。其结构如图4-4所示。4.2.2if语句的嵌套if语句中若包含一个或多个if语句,则称为if语句的嵌套。其基本格式为关于if语句的几点说明:(1) if语句先对(表达式)求解,根据结果的逻辑值(真或假)选择相应的语句执行。(2) if…else是一个完整的语句,else是if语句的一部分,但else前后的内嵌语句都要加分号。(3) else语句不能单独使用,并且总是与上面的、最近的、未配对的if语句进行匹配。(4) if语句可以嵌套,但必须是一条if语句完整地包含另一条if语句,即两个分支结构可以嵌套但不能有交叉。4.2.3条件运算符对于二选一的情况,在程序设计中会经常出现。C语言优化了这个过程,定义了条件运算符来实现,其基本格式为条件运算符是C语言的运算符之一,它是一个三元运算符,因为需要三个操作数。条件运算符的执行过程为从条件运算符的执行过程中可以看出,它与双分支选择结构基本一致,但是它比if...else语法更加简便。4.2.4switch语句除了if语句之外,C语言还为选择结构定义了switch语句,即多路判断语句,用于处理多分支的问题。其基本格式为在基本格式中,需要注意:(1)语句部分可以是一条语句,也可以是多条语句;在swicth语句的格式中,即使是多条语句,也不强制使用花括号{},这一点与if语句的语法不同。(2)语句后的break表示停止、中断,即结束对switch语句的执行。break语句可根据需要添加。(3) default语句部分指缺省状况,如果switch语句中的所有分支都没有执行到,则执行default语句部分,该部分出现与否,可以根据需要而定。(4) switch(表达式)中的表达式的值只能是整型值。(5) case之后的常量可以是整型常量,也可以是整型常量表达式,并且不能出现两个case之后的常量表达式的值相同的状况。(6)如果switch(表达式)中表达式的值与任意一个case后的常量的值不匹配,而且该语句也没有提供default部分,则不执行switch中的任何语句。switch语句的执行过程是:(1)计算switch(表达式)语句中表达式的值。(2)将该表达式的值依次与case后的整型常量表达式的值进行比较。(3)如果某个case后的整型常量表达式的值与该表达式的值相等,则执行该case后的语句。执行完毕,若没有遇到break语句,则继续执行switch结构内的后续语句;若遇到break语句,则结束switch结构的执行。(4)如果switch(表达式)语句中表达式的值与任何一个case后的整型常量表达式的值都不相等,若语句中包含default部分,则执行default后的语句;若语句中没有default部分,则结束switch结构的执行。关于switch语句的几点说明:(1) switch后括号内的表达式和case后的常量表达式均有确定的整型值。(2) switch语句用花括号限定一个复合语句,其中可以包含若干条case语句和最多一条default语句。case和default分支中可以是一条也可以是多条语句,此处不必用花括号限定。多个case分支也可以共用一组执行语句。(3)每一个case分支的整型常量表达式的值必须互不相同。(4)当表达式的值与某一个case分支的整型常量表达式的值相等时,控制流程就从此case语句进入,顺序执行后面的语句。若所有case分支的整型常量表达式的值都与switch后表达式的值不匹配,则执行default分支语句;若没有default分支语句,则不执行任何操作。(5) break语句的作用是结束switch结构语句的执行。(6) case和default的出现次序不影响执行结果。4.3循环结构循环结构是结构化程序设计中一种很重要的结构,其特点是在给定条件成立时,反复执行某程序段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。C语言提供了三种循环结构,分别是while型循环结构、do…while型循环结构以及for型循环结构。在这三种结构中,以for型循环结构的使用最为灵活、使用频率最高。4.3.1while型与do...while型循环1.while型循环使用关键字while构成的循环结构,称作while型循环结构,也称作当型循环结构。其基本格式为while型循环的处理过程为:先判断表达式是否成立(即对表达式求解),如果表达式成立(值为非0),则执行循环体中的语句;执行完后,再次对表达式求解,只要表达式的值为非0,则循环体即被反复执行;直到表达式的值等于0(即循环条件不成立),才结束循环结构的执行。其结构如图4-5所示。2.do...while型循环do...while型循环结构是在循环体执行结束之后才对循环条件进行判断,因此也称作直到型循环。其基本格式为do...while型循环的处理过程为:首先执行循环体中的语句,然后求解while表达式的值,只要表达式的值为非0(即循环条件成立),循环体将被反复执行,直到表达式的值等于0(循环条件不成立),控制流程才结束循环结构的执行,其结构如图4-6所示。while型循环与do...while型循环在格式和用法上有如下区别:(1) while型循环先判断条件,后执行循环体语句;do...while型循环先执行循环体语句,后判断条件。(2)若循环条件表达式的初始值为真,则两种循环语句的执行结果相同。若循环条件表达式的初始值为假,while语句不执行循环体中的语句,而do…while语句则执行一次循环体中的语句。(3) while语句中,while(表达式)后接语句;do…while语句中,while(表达式)后接“;”。(4) while语句适合解决“当型”循环问题;do…while语句则更适合解决“直到型”循环问题。4.3.2for型循环使用关键字for建立的循环结构是C语言中功能最强大、使用最广泛的一种循环结构。其基本格式为或者其中,表达式1通常用于循环控制变量的初始化,一般是赋值表达式;表达式2通常是循环条件,一般为关系表达式或逻辑表达式;表达式3通常用于更新循环控制变量的值,使循环条件能够不成立,从而结束循环,一般多为自增或自减表达式。这三个表达式可以是单一的表达式,也可以是使用逗号分隔的逗号表达式。其执行过程为:(1)执行表达式1,完成循环控制变量的初始化,使其能够参与表达式2的条件判断。(2)计算表达式2的值,即判断循环条件是否成立。如果表达式2的值为假(0),即循环条件不成立,则不执行循环体;如果表达式2的值为真(非0),即循环条件成立,则执行循环体中的语句。(3)计算表达式3的值,即更新循环控制变量的值。(4)控制流程转回第(2)步,依次重复执行,直到循环条件(即表达式2的值为假)不成立。在整个for循环过程中,表达式1只计算一次,表达式2和表达式3则可能计算多次。循环体可能被多次执行,也可能一次都不执行,其结构如图4-7所示。for语句的书写非常灵活,只要遵循for型循环结构的求值顺序,循环功能的实现将不受影响。在书写时,可以:(1)在表达式1、3的位置书写与循环控制无关的表达式。(2)将循环体内或外的语句添加到表达式1、3的位置,形成逗号表达式。(3)任意省略表达式1、2、3和循环体内的语句(相应位置的分号不能省)。三种循环语句的比较:(1)使用while型和do...while型循环,循环变量的初始化应在进入while和do...while语句之前完成;在for型循环中可由表达式1实现。(2)使用while型和do...while型循环,循环体内应包含使循环趋于结束的语句;在for型循环中可由表达式3实现。(3)使用while型和do...while型循环,while后面的括号内应说明循环结束的条件;在for型循环中可由表达式2说明。(4)一般情况下,三种循环可以互相代替。while语句更适合处理“当”型循环;do...while语句更适合处理“直到”型循环;for语句书写灵活、功能最强,适合处理各种循环问题。使用循环结构处理问题时,通常需要考虑如下几个关键点:(1)进入循环结构前需要对循环控制变量赋初值。(2)循环条件表达式可以是任意类型,但是结果只能是0(假)和非0(真)两种情况。(3)循环结构中应该有使循环趋于结束的语句,避免出现死循环。(4)当循环体包含一条以上的语句时,应该用花括号限定,以复合语句的形式出现。4.3.3循环结构的嵌套一个循环结构内包含另一个完整的循环结构,称为循环结构的嵌套。内嵌的循环体中还可以继续嵌套循环,这就是多层循环嵌套。与选择结构嵌套的要求相同,循环嵌套必须是一个循环结构包含另一个完整的循环结构,即两个循环结构可以嵌套但不可以交叉。4.3.4break语句与continue语句break语句不但可以使用在switch选择结构中,而且可以用在三种循环结构中,执行break语句可以结束其所在的选择结构或者循环结构的执行。与break语句相比,continue语句只能出现在循环结构中,执行continue语句可以提前结束本次循环,即循环体内continue语句后的语句将不再执行,而直接进入下一次循环的判断执行。continue语句与break语句的区别在于:(1) continue语句只结束本次循环;break语句则结束整个循环。(2) continue语句只限于循环结构;break语句则可用于循环结构和switch选择结构。5.1一维数组5.2二维数组5.3字符数组5.4字符串输入、输出函数5.1一维数组一维数组是最简单的数组类型,数组中每个元素由相同的数组名和唯一的下标来确定并相互区别。5.1.1一维数组的定义一维数组定义的基本格式为其中,类型符用于指定数组的数据类型。数组是同一类型的有序数据的集合,因此数组的数据类型也是该数组中所有组成元素的数据类型。数组名是表示某个特定数组的标识符,其命名方法遵循标识符命名规则。[常量表达式]用来表示数组的长度,说明所包含元素的个数。C语言不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值,因此方括号中的“常量表达式”可以是整型常量或整型常量表达式,但不能是变量。5.1.2数组元素的引用C语言规定,必须先对数组进行定义,然后才能对数组元素进行逐个引用,也就是要遵循“先定义,后使用”的原则。需要注意的是,由基本数据类型所构造的数据类型,只能引用其组成成员,而不能引用其本身,即数组名不代表整个数组。数组中每个元素的类型由数组的类型决定,每个数组元素由统一的数组名和唯一的下标确定。下标可以是常量、变量或表达式,但必须有确定的整数值。数组元素的下标总是从“0”开始的。所有元素以各自的下标为顺序,在内存中占用一段连续的存储单元。数组常与循环结构结合在一起使用,通过数组的下标和循环结构的控制变量产生联系,可以很方便地引用数组元素。5.1.3一维数组的初始化为使程序简洁,常在定义数组的同时为各数组元素赋值,称为数组的初始化。常见的初始化形式包括:(1)为全部元素赋值,按顺序将数值依次赋给数组中各元素。(2)若省略数组长度,则可由初始化式中数值的个数确定其长度。(3)若初始化式中数值的个数小于数组的长度,则不足的部分默认初始值为0。(4)利用上一特性,可以方便地为全部元素赋初值0。需要注意的是,初始化式以花括号限定,数值间用逗号隔开,初始化式不允许完全为空,即花括号内至少要有一个数值。如果在定义的同时不对数组初始化,则各元素的初始值并不确定。5.1.4一维数组的存储形式数组的所有元素在内存中是以连续字节的形式存放的,数组中各元素所占内存的大小由该数组的数据类型决定,整个数组所占内存的大小为一个元素所占内存的大小与元素的个数乘积。5.2二维数组维数超过一维的数组统称为多维数组。多维数组也是同类型数据的有序集合,存储形式与一维数组相同,即所有元素按顺序占用一段连续的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026福建泉州安溪县凤城中学招聘秋季编外合同教师备考题库及参考答案详解
- 2026内蒙古赤峰市人大常委会办公室所属事业单位竞争性比选人员3人备考题库及1套完整答案详解
- 2026湖州银行嘉兴分行招聘备考题库及完整答案详解1套
- 某纸业厂生产安全制度
- 2026福建泉州安溪县凤城中学招聘秋季编外合同教师备考题库及1套完整答案详解
- 2026华东师范大学附属闵行虹桥学校教师招聘备考题库及1套完整答案详解
- 2026广东广州市增城区朱村街第五幼儿园招聘2人备考题库及1套完整答案详解
- 2026春人教版数学三年级下册期末复习重点必练易错专项练习卷含参考答案
- 2026四川省经济和信息化厅所属事业单位选调8人备考题库及完整答案详解1套
- 2026江苏南京大学艺术学院准聘长聘岗位(事业编制)招聘备考题库含答案详解
- T-CSTM 00632.3-2022 建筑涂饰工程用涂料产品技术要求 第3部分:无机建筑涂料体系
- 保育教师食品安全培训
- 2025汽轮机启动调试导则
- 供电设备运行维护管理方案
- 某市水库扩容工程施工合同三篇
- 四川省德阳市旌阳区2023-2024学年四年级下学期期末检测语文试题
- HG∕T 4214-2011 脲铵氮肥 标准
- TSGD7006-2020压力管道监督检验规则
- JC-T 474-2008砂浆混凝土防水剂
- 2023年全国统一高考英语试卷(甲卷)及答案解析
- 2023年06月贵州遵义市播州区选调区外在编在职教师笔试历年高频考点题黑钻摘选附带答案详解析
评论
0/150
提交评论