Linux环境C语言程序设计――最终版new_第1页
Linux环境C语言程序设计――最终版new_第2页
Linux环境C语言程序设计――最终版new_第3页
Linux环境C语言程序设计――最终版new_第4页
Linux环境C语言程序设计――最终版new_第5页
已阅读5页,还剩127页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 程序设计 谌利 张连成 编写 目录目录2第一章C语言概述6本章目标61.1 计算机组成结构71.2 程序设计语言与C语言81.2.1程序的概念81.2.2 程序设计语言81.2.3 C语言的特点91.3 编写第一个C语言程序101.4 C语言程序结构特点11第二章C语言基本语法16本章目标162.1 语句和注释172.2 标识符和关键字182.3 基本数据类型192.4 数据类型转换202.5 常量与变量202.5.1 常量202.5.2 变量212.5.3 变量的存储类型242.5.4 变量的生存期和作用域252.6 运算符和表达式272.6.1 运算符27第三章流程控制37本章目标373

2、.1 语句和语句块383.2 顺序结构383.3 选择结构383.3.1 if.else语句393.3.2 switch.case语句453.4 循环结构483.4.1 for循环493.4.2 while循环523.4.3 do.while循环543.4.4 多重循环553.5 break、continue和return语句573.6 goto跳转语句59第四章 数组、指针和字符串61本章目标614.1 数组624.1.1数组的定义624.1.2数组的使用634.1.3数组的初始化634.1.4多维数组654.1.5数组示例654.2 字符数组704.3 字符串714.4 指针794.4.1

3、指针和指针变量794.4.2 指针和数组834.4.3 指针变量的运算854.4.4 指针和字符串854.4.5 指针数组和多级指针874.4.5 数组指针874.4.6 野指针88第四章函数90本章目标905.1 函数基础915.1.1函数概念915.1.2函数定义925.2 函数调用规则945.2.1值传递方式945.2.2址传递方式965.2.3 函数调用机制985.2.4 递归调用985.2.5 命令行参数1025.2.6 malloc()和free()函数104第五章构造类型106本章目标1066.1 结构型1076.1.1结构型定义和使用1076.1.2 结构型指针1096.2 共

4、用型1126.3 枚举型1136.4链表114第六章文件操作118本章目标1187.1 文件的基本概念1197.1.1文件概念1197.1.2文件类型1197.2 文件的基本操作1207.2.1文件打开与关闭1207.2.2文件读写1207.2.3其他文件操作1227.3文件操作示例123第七章文件预处理127本章目标1278.1 预处理和宏的概念1288.2 文件包含和预处理1308.3 条件编译131附录134参考文献134第一章 C语言概述本章目标 了解计算机组成结构的基础知识 了解程序设计语言的基本概念和发展历程 对C语言程序的有一个初步的认识 掌握一个最简单的C程序 掌握gcc工具的

5、基本使用方法 掌握在Linux/Unix环境编译并运行C程序的方法1.1 计算机组成结构一个完整的计算机系统包括硬件和软件两大部分。根据冯诺伊曼的计算机结构体系模型,计算机系统的硬件结构应该包括以下五个部分:运算器、控制器、存储器、输入设备和输出设备。运算器主要完成计算机的算术运算、逻辑运算等功能。控制器则控制各个设备之间的配合,是计算机的核心,目前计算机的中央处理器(CPU)就是典型的控制器。而存储器的主要功能则是存储计算机运算过程中的输入数据、输出结果以及中间运算数据等。输入设备和输出设备是实现人与计算机之间的交互的必要设备,人通过输入设备将所要处理的信息和数据输入到计算机,控制器管理控制

6、整个总线流程,控制运算器对输入数据进行运算和处理,再将计算的结果通过输出设备显示给人。整个处理过程完全在控制器的管理之下进行。运算器:完成数学运算和逻辑运算等控制器:控制各设备间协调配合存储器:存储运算结果和中间数据输入设备:向计算机输入待处理数据输出设备:计算机向外输出运算结果计算机系统硬件软件软件操作系统数据库系统网络系统程序设计语言与语言处理程序语言处理程序系统软件应用软件计算机的软件可以分为系统软件和应用软件两大类,系统软件的主要功能是实现对硬件资源的管理,并为用户提供良好的操作接口。计算机操作系统就是典型的系统软件,其他系统软件比如有数据库系统、网络系统、程序设计语言与语言处理程序等

7、。应用软件则种类更加繁多,为用户实现各种各样的功能。各种软件都是通过程序设计语言编写完成的。计算机系统的大体结构,我们可以用上图来表示。1.2 程序设计语言与C语言1.2.1程序的概念程序就是一系列的操作步骤,计算机程序就是由人事先规定的计算机完成某项工作的操作步骤。每一步骤的具体内容由计算机能够理解的指令来描述,这些指令告诉计算机“做什么”和“怎样做”。人们操作计算机都是通过程序的执行来实现的。程序主要由数据结构和算法构成,并通过一定的程序设计语言来表达。两者的关系可以表示为这样一个经典的等式: 数据结构 算法 程序 其中,数据结构主要用来描述数据的类型、数据的组织形式等;算法则是描述对数据

8、的操作步骤和方法。因此,可以说,数据结构体现了程序告诉计算机“做什么”,而程序的算法则告诉计算机应该“怎么做”。1.2.2 程序设计语言程序都是通过程序设计语言来表达的,程序设计语言就是用来表达程序内容的和计算机指令的计算机语言。程序设计语言经历了从低级到高级,从面向过程到面向对象等多个不同的发展历程。1、面向机器的语言最早最低级的程序设计语言是面向机器的语言,这种语言是针对某种特定类型的计算或者硬件设备编写的,这样的程序被称为面向机器的程序,语言被成为面向机器的语言。面向机器的语言有它自身的特点,既有优势也有缺点。一般而言,面向机器的语言能够充分发挥计算机硬件的运算速度快的优势,运行效率较高

9、。同时,面向机器的语言主要是各种机器语言和汇编语言,程序的可读性都比较差,程序的编写对程序员有很高的要求,程序员需要对相关的硬件或者特定的计算机非常熟悉,而且对程序的修改和扩展也都比较困难;另外,由于面向机器的程序是针对特定的硬件而设计的,因而,程序的可移植性也很差。2、面向过程的语言面向过程的语言出现于20世纪60年代左右,其特点是以数据结构和算法为核心,数据结构用来描述所要解决的问题,算法主要研究如何更加有效地来组织和解决问题。典型的面向过程的语言就包括BASIC、PASCAL、FROTRAN等,我们这里所要重点讲解的C语言也是最为典型的面向过程的语言。面向过程程序设计的一个典型特点就是:

10、自顶向下、逐步求精。自顶向下逐步求精,就是说要不断将所要解决的问题细分为小的子问题,通过对子问题的依次解决最终实现整个问题的解决。这是一个很典型也比较优秀的解决问题的方法。面向过程的语言相对于面向机器的语言有很多的优势,它极大地改善了程序的可读性和可维护性,大大地增强了程序的可移植性,但较大的程序,其管理和维护依然存在困难,另外一点就是,程序的可重用性不是很高。3、面向对象的语言面向对象的语言最早提出于20世纪60年代左右,到了20世纪80年代左右就较为成熟了。面向对象的语言采用了一种全新的思维模式,使程序设计思路对整个世界的认识更加一致。面向对象的程序设计,更加方便软件的扩展、管理和复用,相

11、对于之前的程序无论在质量上还是效率上都有较大的提高。典型的面向对象的程序设计语言有C+、Java、Python等。面向对象的程序设计语言在较大工程项目中,开发效率上有较大的优势。1.2.3 C语言的特点C语言是一种典型的面向过程的程序设计语言,它有以下一些特点:1、 语言简单、紧凑、灵活C语言只有32个关键字,9种控制语句。2、 运算符丰富,包含34种表达式3、 数据结构丰富,对于解决各种问题都能应付自如。4、 具有结构化的控制语句,也体现了其面向过程设计的典型特征:自顶向下、逐步求精。5、 目标代码质量高,程序执行效率高。相对于面向机器的语言具有更好的可读性和易维护性,相对于面向对象的程序设

12、计语言又接近底层,程序执行效率较高。6、 可移植性好,C语言程序可以移植到其他平台,并且几乎不需要改动。7、 兼有低级语言和高级语言的特点,既能够很好地处理和硬件密切相关的问题,也具备高级语言的一些特性。但是,作为计算机语言的C语言,毕竟和自然语言还有很多不同,我们通过下表来比较两者。自然语言C语言信息交流:地位相等、有思维和逻辑推理能力人机对话:命令行方式、无思维和逻辑推理能力、具有计算和逻辑判断能力语法规则和句法规则都较为灵活,可省略、可颠倒。例如:走啊,看电影去!看电影去,走啊!语言规则和句法规则较为固定,一般不可省略,如需颠倒必须依照一定的规则。例如:x=a+b;scanf(%d%d,

13、&a,&b)表达式多种多样算法多种多样1.3 编写第一个C语言程序我们首先来看一个最简单的C语言程序。下面我们来分析一下这个最简单的程序。第一句到第四句属于程序的注释,用/*和*/包含起来,可以是多行,在这个程序中,这段注释的主要内容包括程序源文件名、程序功能的简单描述以及程序编写的时间。第五句为空行,仅仅为了提高整个源程序文件的可读性,没有其他作用,编译器也不会对它做任何解释,直接忽略。第六句中的#include 意思是说将c语言标准输入输出库包含进来,以使用其中的输入输出相关的函数,该行中的/后面部分也是注释内容,/是单行注释的标志。第七句中我们定义了一个main函数,main函数是任何一

14、个C语言程序中都应该具有并且唯一具有的函数,称为主函数,这里面的int是函数的返回值类型,main后的括号中的void说明该函数没有输入参数;如果函数有输入参数,该处内容为形式参数表;该行中的/*主函数*/也是注释内容,编译器将忽略之。第八句和第十句的大括号标识了整个函数体,任何一个函数都应该在一对大括号中进行描述。第九句是函数体中的主要功能语句,该语句使用到了标准输入输出库中的printf函数,其功能是在标准输出设备上打印一行文字:This is a c program! ,并且之后将光标换到下一行中。下面,我们使用gcc工具来对刚刚写好的程序first.c编译并运行,查看其结果。我们常用g

15、cc main.c -o main命令编译一个程序,其实也可以分三步做,第一步生成汇编代码,第二步生成目标文件,第三步生成可执行文件: gcc -S main.c ,gcc -c main.s ,gcc main.o,-S选项生成汇编代码,-c选项生成目标文件,-E选项只做预处理而不编译,如果不加这些选项则gcc执行完整的编译步骤,直到最后链接生成可执行文件为止。1.4 C语言程序结构特点在上一节中,我们编写并运行了第一个C语言程序,在标准输出设备上打印出了一句话,这样,我们对C语言程序有了一个最基本的认识。在这一节中,我们再接触两个简单的C语言程序,然后对C语言程序的特点做一个大体的概括和总

16、结,以便有一个整体的认识。在开始例子之前,我们先来了解一下C语言的编译运行过程,C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。在Linux环境中,我们使用gcc工具来进行C语言程序的编译和链接,gcc的详细用法可以查看其manual页,最简单的使用方法是gcc后面直接跟我们的C语言源程序文件,其中较为常用的选项有-o表示指定输出的文件名称。第二个简单的例子程序:计算两个整数的和

17、。我们对这个程序做一个简单的分析。第一行到第五行为注释内容。第六行和第十二行为空行,除了增强程序可读性,无其他作用。第七行使用#include语句包含所需的头文件。第八行定义了主函数main,指明其返回值类型为int,没有任何输入参数。第九行和第十六行的大括号标明了函数体的位置。第十行内容定义了三个int型的变量,分别为a,b,sum。第十一行,使用了scanf函数,从标准输入读入两个数字并分别赋值给a和b。第十三行内容已经被注释掉了,被注释掉的内容功能是分别给两个变量a、b进行赋值,其中将a赋值为100,b赋值为200。第十四行中是一个计算a和b的和的表达式,将计算结果赋值给了变量sum.。

18、第十五行使用了pritnf函数将计算结果sum输出到标准输出设备显示出来。下面我们对这个程序进行编译和运行,结果如下。如果我们将上面的代码改成直接赋值的情形,而不是通过标准输入读取数字之后再赋值给变量a和b,那么我们可以将第11行注释掉,并将第13行取消注释,得到的代码如下。运行结果如下。第三个简单的例子程序。计算两个数中的最大值在这个程序中,我们分别定义了两个函数:max和main,其中的max函数有两个输入参数x和y,功能是返回其中最大的一个;main函数中,我们分别声明了三个变量a、b、和c,并通过标准输入设备将输入的数字分别赋值给a和b,然后调用max函数将计算结果赋值给变量c,最后是

19、使用printf函数将c的值打印出来。该程序的编译过程和运行结果如下。通过上面三个例子程序,我们大体可以总结出C语言程序结构的一般特点如下: 函数是组成C程序的基本结构 一个函数由两部分组成:函数说明部分 函数体函数体:说明部分执行部分 一个程序总是从main函数开始执行 语句以分号;结束 书写格式自由 用/*.*/做注释第二章 C语言基本语法本章目标 掌握语句和注释 掌握标识符和关键字 掌握基本数据类型 掌握常量与变量 掌握运算符和表达式2.1 语句和注释语句就是用C语言所编写的指令,如printf(This is a c program !);再如int name=23; char c=n

20、;。C语言中的语句是最基本的执行单位,各语句之间要用分号;来分隔,一条语句可以写在连续的若干行,一行也可以些多条语句,我们提倡一行写一条语句。用大括号括起来的一系列的语句称为语句块,也可以简称为块,语句块可以使用嵌套的方式,也就是说,可以在语句块中还有其他语句块,这样就会构成一个大括号中还会有大括号。C语言中除了语句之外,还有一个很重要的部分注释。虽然注释经常容易被忽略,但实际上,对于大型的程序或者工程项目来说,注释是非常重要的内容。因此,我们应该养成写注释的好习惯。C语言中的注释主要有两种形式:单行注释和多行注释。单行注释是以两个斜线/作为标志的,在双斜线后面的该行内容都将视为注释。多行注释

21、是以/*和*/包含起来的,可以是一个注释块,既可以使用在单行中,可以使用在多行中,但有一点需要特别注意:多行注释不可以嵌套,否则将会导致错误出现。下面我们还是拿前面用过的例子来说明单行注释和多行注释。如图,其中的第1行到第4行的内容就是多行注释。其中的第6行中/后面的部分就是单行注释。C语言程序对编码规范的基本要求是:程序结构清析,简单易懂,单个函数的程序行数不得超过100行;打算干什么,要简单,直接了当,代码精简,避免垃圾程序;尽量使用标准库函数和公共函数;不要随意定义全局变量,尽量使用局部变量;使用括号以避免二义性。 2.2 标识符和关键字在解释标志符和关键字这两个概念之前,我们首先需要了

22、解什么叫做字符集。在C语言中,程序允许出现的所有的基本字符的组合构成的集合,就称为C语言的字符集。C语言中的字符集可以分为以下几类:1、 大小写英文字母,共52个;2、 数字符号,共10个;3、 键盘符号,共33个;4、 转义字符,如n,r等。5、 C语言区分大小字母,因此a和A是两个不同的标识符。标识符就是用户在程序中自定义的一种字符序列,通常表示程序中需要分辨和标识的对象名称。在C语言中 ,标识符有一定的命名规则,其规则如下:(1) 标识符由大小字母和下划线开头的字母、数字、下划线所组成的一串符号。(2) 保留字不能作为标识符。(3) 下划线可以作为标识符的第一个字符,但一般用于库中代码,

23、因此,习惯上,我们不推荐用户在自定义标识符的时候使用下划线开头。我们举例说明什么是正确的标识符,如:sum、i、a2、a_2、_jim2、_3_admin ,而像2b、a?、a.m、a-3、b+4、if、while等这样的标识符则是错误的。关键字就是C语言中预先定义了一定功能的字符组合,如if、for等,我们在使用定义标识符的时候不能使用这些字符组合。C语言中的关键字有:C语言中的关键字autodoubleintstructbreakelselongswitchcaseenumregistertypedefcharexternreturnunionconstfloatshortunsigned

24、continueforsignedvoiddefaultgotosizeofvolatiledoifstaticwhilevolatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问

25、。一般说来,volatile用在如下的几个地方:1、中断服务程序中修改的供其它程序检测的变量需要加volatile;2、多任务环境下各任务间共享的标志应该加volatile;3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义。2.3 基本数据类型在这一节中,我们来学习C语言中各种不同的数据类型以及它们的特点,包括基本数据类型和构造数据类型。我们将重点放在基本数据类型上,有关构造数据类型的详细内容,将放在后面进行讲解。C语言中的基本数据类型包括以下四种:字符型、整型、实型、指针型。下面分别介绍这四种数据类型的基本特点:字符型 char型,占用一个字节的空

26、间,1Byte ,一般是一个字符,如c就是典型的char型数据。可以是字符集中的任何一个单独的字符。当在进行运算的时候,它会自动被转换成int型之后再运算。整型 int型,主要是整数,一般占用4个字节的空间,4Byte ,整型数据可以分为十进制、八进制和十六进制。十进制的数据不用加任何修饰符,八进制的整型数据应以0开头,例如076;十六进制的整型数据以0x或者0X开头,如0x8a等。实型 计算机中的浮点数为实型数据,可以分成单精度浮点数和双精度浮点数两种。单精度浮点数用关键字float表示,双精度浮点数用关键字double来表示。实型数据所能表示的数值范围要比整型和字符型都要大得多。指针型 作

27、为变量的地址,是一种较为特殊的数据类型。有关指针的详细内容,我们将在后续章节进行说明。2.4 数据类型转换在C语言中,我们经常需要很多种不同类型的数据,在处理过程中常常会遇到数据类型之间转换的问题。但一个操作符包含不同类型的操作数时,它们就会根据一定的规则转换成相同的类型。一般而言,类型之间的自动转换默认都是要保证数据的精度不丢失,从占用空间少的数据类型转换成占用空间较多的数据类型,例如在一个整型数据和一个实型数据进行算术运算的时候,就默认将一个整型数据自动转换成实型数据,计算的结果也是实型数据。对于可能导致数据丢失的类型转换,类如将一个浮点数赋值给整型变量,就会得到一个警告,提示可能导致数据

28、精度丢失。需要注意的是,虽然会得到警告,但并不意味着操作非法,也就是说编译可以通过,也可以正常执行。如果要强制转换,可以通过显示地指明变量类型的方式进行。格式如下:(数据类型)表达式默认的自动转换顺序为:byte、charintfloatdouble另外,在数据类型转换中,需要注意的是,一般在有signed和unsigned类型同时出现的时候,常常会自动转换为unsigned类型。2.5 常量与变量在C语言中,数据可以分为常量和变量两种。常量一般用来表示值基本固定不变的量,常量又称为字面量,可以理解为一般意义上的常数。变量是指值可以变化的量。2.5.1 常量常量可以有很多种,可以是基本数据类型

29、的任何一种。整型常量像1234这样的整数,表示常数,就是一个int型常量,整型常量可以添加限定词short或者long,分别表示占用不同大小空间的整型常量。不加任何限定词时表示最一般的int型,占用空间大小和具体的机器有关;short一般是16bits大小,即占用两个字节,而int可能是16bits也可能是32bits ,具体的情形和编译器也有一定关系,但有一点是确定的,short型常量和int型常量最少应该是16bits ,long型常量至少是32bits ,short不能长于int ,int不能长于long。长整型的常量要在尾部加上l或者L,如L。另外,signed和unsigned限定词

30、也可以放在整型常量或者字符型前面。无符号数总是整数或者是零,符合二进制按位加权计算的规则,比如,当char型常量大小是8bits时,所能表示的数据范围为0至255 ,而有符号数的范围则可以是-128至127。无符号的整型常量要在尾部加上字母u或者U,当以ul或者UL结尾时,表示该数据为unsigned long型。Long double可以表示范围更大的数据,可以视为浮点数(float)的扩展。实型常量含有一个小数点或者表示为指数形式,也可以是既含有小数点又表示成指数形式,默认实型为double型,例如23.34就是double型,如果要表示单精度浮点数float,一定要在数的尾部加上f或者F

31、,而如果以l或者L较为则是long double型。字符型常量实质上就是一个整数,要用单引号括起来表示一个字符。字符型和它对应ASCII码的值的整数是相同的。除了上面所说的整型常量、实型常量、字符常量以外,还有一种叫做字符串常量。字符串常量表示一个字符串,是用双引号括起来的字符序列,例如:stringa = hello;要声明一个常量,必须使用const关键字,例如:const PI = 3.141; const char NAME ;等。2.5.2 变量在C语言中,变量是指值可以改变的量。C语言中规定,变量应该先声明再使用,在使用之前一定要进行变量的声明。声明变量的方法是:数据类型 变量名;

32、数据类型既可以是基本数据类型,如整型、实型、字符型和指针型,也可以是构造类型,如枚举类型、结构体类型或者数组类型等。变量名是用户自定义的名称,推荐使用具有一定实际意义的名称,变量名应该符合C语言标识符的命名规则。末尾的分号表示一个语句的结束。例如: int a; float b; char c;等变量可以在声明的同时进行赋值,也可以先声明再赋值,两种方法的效果基本是相同的。当选择先声明再赋值的方式时,编译器默认会对只声明但还没有赋值的变量给一个初始值。初始值的具体内容与变量的类型有密切关系。例如int型的变量会被分配一个随机的数值,float和double型的变量初始值则为0.0。我们可以通过

33、下面程序观察得到:在上面的程序中,代码第9到11行中,分别定义了三个变量,整型的变量i,单精度浮点型的变量f,双精度浮点型的变量d,需要注意的是,我们没有对三个变量进行赋值。代码第12到14行中,分别输出三个变量的值,也就是默认的该类型变量的初始值。下面是运行结果:通过上面的运行结果,我们可以看出,int型变量初始值在几次运行过程中不断变化,不是一个固定的数值,而是是一个随机的数值,而float和double型的则是0.。变量也可以在定义的同时进行赋值,其格式为:数据类型 变量名变量值;例如,下面的程序。代码第8行中,定义了一个整型变量i同时赋值100。代码第9行输出该变量的值。编译过程和运行

34、结果如下:变量的各种数据类型有关内容,各种数据类型的关键字以及各种数据类型占用的字节数的多少,我们可以总结为下表:数据类型类型符号占用字节数数据类型类型符号占用字节数整型int 4无符号长整型unsignedlong4短整型short 2单精度实型float4长整型long4双精度实型double8无符号整型unsigned int4字符型char1无符号短整型unsigned short22.5.3 变量的存储类型C语言中,变量不仅可以具有多种类型,而且不同变量还具有不同的存储类型。变量的存储类型标识了变量的存储位置不同的特点,有的变量存储在内存的堆栈区中,有的变量存储在寄存器中,还有的变量

35、存储在内存数据区。存储在内存堆栈区中的变量,其存储类型为自动型,关键字为auto;寄存器型的变量关键字为register,存储在CPU的通用寄存器中;静态存储类型的变量用关键字static来表示,它存储在内存数据区;还有一种存储类型的变量,叫做外部参照型,用关键字extern来表示。由于变量具有不同的存储类型,因此在定义变量的时候,不仅可以指定变量的数据类型,还可以指定变量的存储类型,以及初值。于是,完整的变量定义的格式如下:存储类型 数据类型 变量名初值;我们将变量不同存储类型的特点总结为下表内容。存储类型存储类型符存储地点自动型auto内存堆栈区寄存器型registerCPU通用寄存器中静

36、态型static内存数据区外部参照型extern2.5.4 变量的生存期和作用域一般而言,变量不是一直都存在于内存中的,当不再需要使用某个变量的时候,之前所分配给该变量的内存单元就会被收回。我们把变量从开始分配内存单元到分配的内存单元被收回的期间称为变量的生存期,也叫做变量的生命周期。变量不仅具有生存期,而且变量所能使用的程序区也是有一定界限的。在变量的生存期中,我们把变量可以使用的程序区域称为变量的作用域。变量的作用域大体可以分为以下四类:代码块作用域:变量仅在一定的代码块中有效;文件作用域:变量仅在某个特定的文件中有效,在其他范围则无效;函数作用域:变量仅在某个特定的函数中有效,例如函数的

37、形式参数,该变量的作用域就是函数作用域。除了以上三种之外,还有一种变量作用域称作原型作用域。有关作用域的详细内容,我们将在函数一章进行讲述。2.5.4 程序的内存空间一个典型的Linux C程序内存空间由如下几部分组成:BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。代码段:代码段(code segment/text segment

38、)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“”中定义的变量(但不包括static声明的变量

39、,static意味着在数据段中存放变量)。除此以外,在函数被调用时其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。2.6 运算符和表达式前面已经讲过,在C语言中最基本的执行单位就是语句。而构成语句的基本元素就是运算符和表达式,运算符提供了各种数学运算和逻辑运算的能力,表达式则是运算符的组合。丰富的运算符和表达式充分体现了C语言功能特性。2.6.1 运算符用来表示各种运算的符号就叫做运算符。运算符一定有自己的运算对象,构成下面的形式。

40、操作符(operator) 操作数(operands)针对一定的运算符,都有规定的的数据类型,同时运算结果也有确定的数据类型。每个运算符都有自己特定的运算规则。当表达式中出现多个运算符时则必须考虑运算符的优先级。同时,运算符还规定了结合性。C语言中运算符包括算术运算符、关系运算符、逻辑运算符、赋值运算符、逗号运算符、条件运算符、长度运算符、位运算符(包括位逻辑运算符和位移位运算符)等。下面,我们分别来介绍这些运算符的特点:算术运算符 包括常见的算术运算,如加法、减法、乘法、除法、取模运算、取正或取负等。这些符号分别为+、-、*、/、%、+、-,其中只有取正或取负是单目运算符(即只有一个操作数)

41、,其他的都是双目运算符(即一个运算符对应两个操作数)。有关算术运算符的优先级、结合性等内容,我们用下表来表示。 运算符名称优先级结合性+、-取正、取负2自右向左*、/、%乘、除、取余数3自左向右+、-加、减4自左向右算术运算符中还有一种比较特殊的运算:自加和自减,分别用+和表示。两者的优先级都是2,结合性为自右向左。但自加或者自减在前置和后置的时候效果是不一样的,这一点要特别引起注意。我们以自加运算符为例:前置自加:int a=3;int b=+a;相当于int a=3;a=a+1;b=a;后置自加:int a=3;int b=a+;相当于int a=3;b=a;a=a+1;即前置自加时,先进

42、行自加运算,再进行赋值运算,而后置时,刚好相反,即先进行赋值运算,再进行自加运算。对于,自减运算符有类似的规律:前置自减:int a=3;int b=-a;相当于int a=3;a=a-1;b=a;后置自减:int a=3;int b=a-;相当于int a=3;b=a;a=a-1;即前置自减时,先进行自减运算,再进行赋值运算,而后置时,刚好相反,即先进行赋值运算,再进行自减运算。下面,我们用一个简单的程序来说明这个特性。 在上面这个程序中,我们定义了6个整型变量a、b、c、d、e、f,并且为a赋初值为1。然后依次进行了多次前置自加和后置自加的运算,以及加法和赋值运算,利用前面的规则,我们不难

43、推测出运行结果如下。 关系运算符 关系运算符可以用来比较两个数值型数据的大小,也可以比较两个字符型数据的大小。关系运算符的运算结果是逻辑值,若为“真”用整数1表示, 若为“假”用整数0表示。关系运算符主要有以下几种:运算符名称优先级结合性=、=、3,因此b的值不会自加。由于整个表达式最终为假,因此会输出b的值,并且b的值不发生变化,依然为3。代码第15句到18句也进行了一个判断的过程,第15句中判断如果+b大于3或者a大于1,因为+b是前置自加,b会先自加1,成为4,再同3进行比较,于是为真;又因为|为短路运算符,在计算完前面的表达式为真以后,将不再计算后面的部分,因此a的值也不会发生变化。最

44、终将输出a的值,并且a的值依然为1。上面程序的编译过程和运行结果如下。赋值运算符。赋值运算符分为三种:基本赋值运算符、算术自反赋值运算符、如+=、-=、*=、/=、%=等,位自反赋值运算符,如|=、=、&=、=等。需要说明的是,算术自反赋值运算符a+=b相当于a=a+b,同理a-=b相当于a=a-b,a*=b相当于a=a*b,a/=b相当于a=a/b,对于位自反运算符同样有a|=b相当于a=a|b、a=b相当于a=ab、a&=b相当于a=a&b、a=b相当于a=ab等。逗号运算符 逗号运算符是双目运算,其运算对象是表达式;运算规则是依次计算前、后表达式的值; 运算结果是后表达式的值。条件运算符

45、 条件运算符是三目运算符,其三个运算对象是表达式(e1?e2:e3); 运算规则是如果e1表达式为“真”,取e2表达式的值,否则取e3表达式的值。下面,我们来练习一个条件运算符的例子。在这个程序中,代码的第9行和第10行分别定义了两个整型变量a和b,并且分别赋值为101和222。代码的第12行中使用了标准输出库中的printf函数将结果输出,所要输出的结果是a和b中最大的值,其中的 (ab?a:b)就是上面的条件运算符,其含义是a大于b吗?如果a大于b就返回a:否则就返回b。这样一个简单的表达式就实现了返回a和b中较大的一个的功能。可以想到,程序的运行结果将如下图所示:由此可见,条件表达式在作

46、非此即彼的条件判断时非常地简洁有效,这一点是后面我们将要谈及的if.else语句所不能及的。长度运算符 sizeof其运算对象可以是任何数据类型或变量;运算对象必须用圆括号括住。位运算符 位运算符是一种对运算对象按二进制位进行操作的运算。位运算有如下特点:(1)位运算不允许只操作其中的某一位,而是对整个数据按二进制位进行运算。 (2)位运算的对象只能是整型数据(包括字符型),运算结果仍是整型数据。 (3)位运算符分为位逻辑运算符、位移位运算符、位自反赋值运算符三种。位逻辑运算符的特点如下。运算符名称优先级结合性按位取反2自右向左&按位与8自左向右按位异或9自左向右|按位或10自左向右位移位运算

47、符的包括以下几个:运算符名称优先级结合性按位右移5自左向右1. 按位与运算 按位与运算符&是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。2. 按位或运算 按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。3. 按位异或运算 按位异或运算符“”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。4. 求反运算 求反运算符为单目运算符,具有右结合性。 其功能是对参与

48、运算的数的各二进位按位求反。5. 左移运算 左移运算符“”是双目运算符。其功能把“ ”左边的运算数的各二进位全部左移若干位,由“”右边的数指定移动的位数,高位丢弃,低位补0。例如: a”是双目运算符。其功能是把“”左边的运算数的各二进位全部右移若干位,“”右边的数指定移动的位数。2.6.2 表达式用运算符将运算对象连接形成的式子就是表达式。表达式具有如下特点:(1)每个表达式都可以按照其中运算符的优先级和运算规则依次对运算对象进行运算,最终获得一个数据,该数据称为表达式的值。(2)表达式值的数据类型就称为表达式的数据类型。表达式按照功能的不同可以分为以下六种。(1)算术表达式 主要实现各种算术

49、运算功能,如加、减、乘、除、取余数、取正、取负等等。(2)关系表达式 判断两个或者多个操作数的大小关系以及等于和不等于的关系,如大于、大于等于、小于、小于等于、等于、不等于等。(3)逻辑表达式 进行逻辑运算,如果逻辑与、逻辑或、逻辑非等。(4)条件表达式 进行条件的判断和运算,真和假。(5)赋值表达式 主要实现赋值功能。(6)逗号表达式 其运算对象是表达式,运算规则是依次计算前、后表达式的值,运算结果是后表达式的值。 表达式类型转换方法表达式计算中数据类型的存在一定的自动转换原则,其原则特点是参加运算的各个数据都转换成数据长度最长的数据类型,然后计算。计算结果值当然也就是数据长度最长的数据类型

50、。下面来看一个自动转换的例子。代码的第9到12行分别定义了四个变量i、f、d、e并赋初值 ,它们的类型分别为整型、单精度浮点型、双精度浮点型、长整型。需要注意的是:要表示单精度浮点数(float)需要在尾部加上f或者F,否则默认将视为双精度浮点型(double)。代码的第14行将结果输出,但使用了“d”进行格式化输出,即将结果视为int型输出,这在编译过程中将会得到warning提示。如下图所示:。从上图中的第二行的提示可知,后面的计算结果是double型的,这正说明了在运算过程中表达式中的数据类型发生了自动转换,全都转换为了double型,从而得到了double型的结果。同时,当运行时得到了一个溢出后的错误结果。我们将上面的代码中%d改成%f ,即得到下面的样子:再次编译将不会出

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论