c语言 语言复习

c语言 语言复习

ID:26073731

大小:405.50 KB

页数:86页

时间:2018-11-24

上传者:xinshengwencai
c语言 语言复习_第1页
c语言 语言复习_第2页
c语言 语言复习_第3页
c语言 语言复习_第4页
c语言 语言复习_第5页
资源描述:

《c语言 语言复习》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库

C语言复习C语言概述1.C语言的关键字有哪些?作了关键字就不能做标识符(如变量名、数组名,函数名、结构体类型名)2.C语言的运算符有哪些,掌握常用运算符的优先级、运算对象的个数及结合性。参见附录3.C语言是完全模块化和结构化的程序设计语言。函数是C语言程序的基本单位,一个程序由一个或多个函数组成,其中必须有一个main()函数(也只能有一个),程序从main()开始执行,执行完main()函数结束。4.函数的首部:5.函数体:用花括号括起来,一般包括两部分:声明部分和执行部分。6.C语言的每个语句和数据声明后面必须有一个分号。7.C语言本省没有输入输出语句,由库函数实现。8.了解运行C语言程序的过程,理解“源程序”、“目标程序”、“可执行程序”、“编译”、“连接”和“执行”的概念最简单的C程序设计掌握C语言的9种控制语句(P70页),包括各控制语句的使用方法和语法规范,掌握1.switch语句的用法,理解break和continue的区别并能准确运用。2.注意复合语句的概念和用法,注意在使用if,while,for等控制语句时,一组语句是否加括号构成复合语句对语句执行顺序的影响。3.输入输出由库函数实现,故使用前要#include4.掌握单字符输入输出函数putchar()和getchar()函数的调用方法。5.掌握格式化输入输出函数printf()和scanf()的调用方法。掌握常用的格式说明符的功能和规则。6.printf()中双括号括起来的内容除了%d等格式说明符外,其他字符原样输出,同样,格式化输入函数scanf()中双引号括起来的内容除了%d等格式说明符外,其他字符照原样输入。特别注意在输入数据时格式要和scanf中设定的格式说明符匹配。算法1.什么是算法?什么是数据结构?2.掌握求阶乘、判断闰年和判断素数的算法3.C语言程序的3种基本结构:顺序、选择和4.算法的表示:了解流程图法和N-S图法5.了解结构化程序设计思想。数据类型,运算符和表达式2.了解C语言提供了哪些数据类型(P37),总结我们学过哪些数据类型?3.了解常量和变量的区别4.掌握由宏定义表示的符号常量5.理解变量实质上对应一个内存单元,理解变量名、变量地址和变量值之间的区别。6.变量必须先定义后使用,变量名的命名要符合标识符命名规范并却不能和系统关键字同名。C语言对大小写敏感。掌握变量定义的格式。 7.变量的三要素是:类型,名字和当前值。变量的值通过赋值方式改变,如iAge=20,其中“=”叫做赋值符号,将其右边的数据存入左边变量名所表示的存储空间中。变量在定义的同时赋值叫做初始化。初始化不是在编译阶段完成的,(只有静态存储变量和外部存储变量的初始化是在编译阶段完成的),而是在程序运行时执行本函数是实现的。8.理解整型变量在内存里的存放形式,掌握整型变量的分类,包括每一种整型变量在内存中占字节数和取值范围。9.理解浮点型数据在内存中的存放形式,掌握各类浮点型所占字节数,有效位数。了解浮点型数据的舍入误差10.了解转义字符,特别是”,\,’,ddd,xhh的含义。11.掌握字符型变量在内存中的存储形式,掌握字符型数据和整形数据之间的关系。C语言字符型数据和整型数据在字符型数据的取值范围内通用。即:一个字符型变量,可以赋以一个字符型变量,也可以赋以一个0~255之间的整数;输出时,可以用字符格式输出,也可以以整数格式输出;可以对字符型数据进行算术运算,此时相当于对其ASCII码进行运算。12.理解字符串常量的存储形式,理解“a”和‘a’的区别。13.掌握各类型数据之间的混合运算中的转换原则,明确哪些是自动的必定要进行的转换,那些是不同类型数据混合运算进行的转换。14.掌握算术运算符的优先级和结合性。注意:两个整数参与运算,结果仍为整数,如5/9=0,5/3=1。15.了解强制类型转换运算符的用法。16.掌握自增,自减运算符的用法,理解++j,--j,j++,j--的含义。17.掌握赋值运算符和赋值表达式的用法,注意“=”与“==”的区别,注意赋值时要将等号右边的值转换成等号变量的类型再赋值。18.掌握逗号表达式的求值方法。选择结构程序设计1.掌握各种关系运算符和逻辑运算符的用法,掌握关系表达式和逻辑表达式的值都是逻辑值“真”或者“假”。C语言把整数0作为逻辑假,把任何非0值作为逻辑真。2.不要把关系运算符“==”误用为赋值运算符“=”。比如,如果将判断x是否等于8的关系表达式“x==8”写成“x=8”,那么它永远为真(不管x的原值为多少)。3.要正确书写关系表达式。如果表示“x大于等于5且小于等于20”,在数学上可写成式子:5≤x≤20,但是如果在C语言中写成下面的表达式:5<=x<=20则是错误的。但这种错误是一种语义上的错误,而不是语法上的错误,编译器查不出来,不会报错。但运行是,不论x为何值(比如3或60)表达式的值都是“真”,所以这种错误比较“隐蔽”,不易被发现,希望引起注意。正确的写法是x>=5&&x<=204.混合运算时注意运算符的优先级,从而确定计算的次序。优先级从高到低依次是:!(非)>算术运算符>关系运算符>&&>||>赋值运算符6.掌握单分支选择结构if语句和双分支选择结构if-else语句的使用。注意:1.if和else同属于一个if语句,else不能单独作为语句单独使用,它只是if语句的一部分,与if配对使用。因此程序中不可能没有if而只有else。2.if-else语句在执行时,只能执行与if的分支语句或else的分支语句,不可能同时执行两者。3.if语句的表达式可以是任意类型的C语言的合法表达式,除常见的关系表达式或,也可以是其他类型的数据,如整型、实型、字符型。4.在if和else后面,可以是单条语句,也可以是复合语句。是单条语句是,注意不要忘记写分号“;”;是复合语句要注意用{}括号扩起来。 7.条件运算符的结合性为“从右到左”。比如表达式A>B?A:C>D?C:D,相当于A>B?A:(C>D?C:D)。8.条件表达式的一般形式(表达式1?表达式:表达式3)中“表达式1”、“表达式2”和“表达式3”的类型,可以各不相同。表达式2和表达式3不仅可以是数值表达式,也可以是赋值表达式或函数表达式。比如:x>y?printf(“%d”,x):printf(“%d”,y)8.嵌套if-else语句和switch语句都是用来实现多分支选择结构的,它们的应用环境不同,嵌套if-else语句用于对多条件并列测试,从中取一的情形;switch语句用于但条件测试,从多种结果中选取一种的情形。9.一般情况下用switch语句能解决的问题,用嵌套if-else也一样能解决,反之用嵌套if-else语句能解决的问题用switch语句也能解决,在使用时要根据具体问题灵活运用。10.如果多分支选择结构需要判断的逻辑关系只是是否相等,则最好使用switch语句,switch语句的执行效率高于嵌套if-else语句。11.掌握用switch语句编程,注意switch后面括号里表达式的值只能是整数或字符型,每个case后面的“常量表达式”的值要各不相同。注意break的使用。注意:某些情况下,case语句顺序改变对结果的影响。循环结构程序设计1.掌握while,do-while和for语句在循环结构程序设计中的应用,掌握while,do-while和for三种循环语句的嵌套和互换。2.循环的3个要点:循环变量的初始值,循环条件和循环变量的增量。在使用循环时,一定要仔细分析循环的3个要点,即从什么地方开始、什么情况下结束和反复做什么。3.如果循环体中包含两条或两条以上的语句,则两条语句形成复合语句,需要用{}将循环体括起来。如果去掉{},则只对着第一条语句进行循环,容易出现死循环的状况。所以当循环体只有一条语句是,{}可以省略;如果有多条语句,即复合语句是,一定要加{}。4.while(表达式)语句的后面不需要分号;如果有分号,系统会认为循环没有循环体语句,即为空循环,则不执行任何循环操作。5.注意do-while和while语句的执行过程不同,do-while语句的循环体至少被执行一次。6.do-while语句中while(表达式)语句后面的分号(;)必不可少。7.理解break语句和continue语句的功能和使用方法。注意:如果程序中包含双重循环语句时,如果再内层循环中使用break或continue语句,则只对内层循环起作用。8.掌握for语句的执行过程及编程运用。for语句的3个表达式都可以省略,但是中间的分号不能省略。省略的表达式的功能可以用其他语句去完成。数组1.掌握各种类型的数据的定义形式、在内存中的存储形式,初始化形式及对数组元素的访问。注意:数组名是数组的首地址,是一个地址常量(不能对常量赋值)2.数组必须先定义,后使用。数组的长度必须事先给定,或者根据初始值的个数给定,不允许动态定义。数组元素的下标从0开始标记。3.掌握对数组元素的输入输出方法。注意,不能对数组整体进行输入输出,必须使用循环结构逐个元素进行输入输出。4.注意,对数组元素初始化时,可以对全部元素初始化,也可以对部分元素进行初始化。对部分元素初始化,则其他元素的值自动设为0。 5.特别注意:对静态数组如果不在定义的时候初始化,则编译系统对数组全部元素赋初值为0;对动态数组如果不进行初始化,则其元素的初值不确定。6.掌握对二维数组的定义,在内存中的储存形式,初始化的形式,掌握对二维数组元素的引用和输入输出方法。注意:二维数组元素下标的取值(行下标和列下标都是从0开始编号)。注意:常用双重循环对二维数组的元素逐个进行存取操作。8.掌握字符数组的定义,初始化形式。特别注意对字符数组进行初始化有哪些形式。9.掌握字符数组和字符串的输入输出方法,如puts、gets,scanf和printf函数。注意:对字符数组元素逐个输入输出方法和对字符串进行整体输入输出的方法。整体输入时使用gets()或scanf()函数的差别是:scanf()以回车或空格结束输入,而gets()以回车作为输入结束符。所以,如果想输入带有空格的字符串,应该使用gets()函数。10.熟悉常用的字符串处理库函数,理解各函数的工作原理。注意:要使用这些库函数,需要包含其相关头文件:#include11.本章特别注意掌握数组元素的排序算法,特别是冒泡法。函数1.函数就是对实现某一功能的函数进行封装,使其成为一个函数封装,可以通过参数和返回值与其它函数进行通信。2.C语言程序有一个主函数和若干个其他函数组成。由主函数可以调用其他函数,其他函数也可以互相调用。3.被调用的函数要先声明后调用,但若是定义位于调用前面,可省略声明。为了统一或标准化起见,一般将自定义的所有函数都在程序前面予以声明。4.掌握有参函数与无参函数的定义方法。能够根据题目要求,将实现某种功能的一段程序转换成函数的形式加以定义。5.掌握实参和形参的概念,理解形参为函数内定义的参数,为局部变量,只在函数执行时才有意义。函数执行完毕后,即释放该参数。6.理解参数传递中值传递和地址传递的原理和本质。值传递是单向传递,只能从实参向形参传递,而不能有形参传回实参。实参和形参占有不同的内存单元,即使同名也互不影响。7.掌握函数的调用的方式:函数语句,函数表达式和函数参数的形式。8.掌握数组作函数参数的应用,主要有两种形式:(1)数组元素作为实参使用,该方式与其它类型的普通变量作实参并没有区别,在发生函数调用时,把数组元素的值传递给形参,实现单向值传递;(2)把数组名作为函数的实参和形参使用,要求形参和对应的实参都是必须是类型相同的数组(或者是指相同类型数组的指针变量),并且必须由明确的数组定义。该方式实现的是地址传递,即把实参的地址传递给形参。9.理解函数嵌套调用的运行过程。10.理解递归函数的运行过程,掌握编写递归函数的两个要点:确定递归公式和递归结束的条件。11.理解内部变量(局部变量)和外部变量(全局变量)的定义和各自的作用范围。12.理解变量的存储类型,掌握自动变量(auto)和静态变量(static)的区别。自动变量在动态存储区分配存储单元,其初始值是个不确定的致。函数返回时,系统将放弃这些存储单元,其单元内的数据也随之消失了。静态变量在静态存储区分配存储单元,初始值默认为0,因此函数调用结束后,它的值并不消失,可以保存到下一次函数调用。指针 1.明确指针就是内存的地址,所谓指针变量就是存放变量的首地址的变量称为指针变量。2.掌握指针变量的定义、初始化方法。定义的指针变量一定要初始化,否则它可能只想不确定的存储单元,对其进行操作可能出现运行出错。3.掌握通过指向变量的指针对变量进行存取的方法。4.掌握指向数组的指针的定义和初始化方法。掌握引用数组元素的指针法和下标法。例如:inta[10],*p=a;其中p=a等价于p=&a[0];这对于数组元素a[i],有a[i]=p[i]=*(a+i)=*(p+i).5.根据课本10.8节小节进行复习。6.能够理解有关应用指针变量的程序。结构体1.掌握使用结构体变量来处理“记录”类数据及使用结构体变量类数组来处理多个“记录”类数据。2.掌握在函数中使用结构体数组的方法。3.结构体类型必须先声明(给出一个模板),然后才能定义结构体变量或数组(生成实体,分配存储空间)。掌握结构体变量和数组定义的几种形式。4.如果两个函数都用到一种结构体类型,则对结构体类型的声明要在这两个函数之前。否则如果结构体类型声明在一个函数内部,则另一函数中就不能识别这种类型。5.掌握访问结构体变量的成员的访问方法。如果指针pStr已指向结构体变量stPerson,则以下三种形式等价:stPerson.成员,(*pStr).成员,pStr->成员。5.注意对结构变量和数组元素不能整体输入输入,要访问到成员,对各成员分别输入输出。第九章预处理命令1.预处理命令包含文件包含、宏定义和预编译命令三种。2.掌握文件包含和宏定义的正确形式。3.理解宏定义的本质就是字符串替换。注意掌握带参数宏定义的宏展开的正确形式及其结果。文件1.掌握二进制文件和文本文件的区别。2.掌握以缓冲文件系统方式读写文件的步骤为:(1).定义文件指针,(2).打开文件,(3).读写文件,(4).关闭文件。3.掌握fopen函数和fclose函数的用法。4.掌握文件操作方式及含义。5.掌握fputc,fgetc,fread和fwrite函数的用法,明确其每个参数的含义。本课程要求掌握的经典算法包括:求阶乘算法,判断素数算法、求最小公倍数和最大公约数算法、排序算法、求三个数最大值或最小值算法、将三个数按从大到小顺序输出的算法、大写字母改小写字母算法,计算字符串中单词的个数的算法、统计字符串中第一章第二章C语言概述C语言形式背景 C语言是国际上广泛流行的,很有发展前途的计算机高级语言,既可用来写系统软件,也可用来写应用软件。发展形成过程:机器语言——汇编语言——面向过程语言——面向对象语言。汇编语言:依赖硬件,可读性,可移植性差。面向过程:CBasic,C对底层操作(位,地址操作)面向对象语言VCVBDelphi(面向对象语言:一种结构模拟语言,对消息的接收与发送,具有分装,继承以及多态性,满足人们所见即所得的要求。)C语言发展史B语言的基础上发展起来的,1960,algol60是一种面向问题的语言,不能写系统程序1963,剑桥大学推出CPL,接近硬件,规模大,难以实现1967,剑桥大学推出BCPL,简化了的1970,贝尔实验室B语言,很接近硬件,unix操作系统过于简单,功能有限1972-1973贝尔实验室C精炼接近硬件多次改写1978以后,C可移植性(BCPL还有应用,在欧洲)1983ANSIC1990ISOC1972年由美国DennisRitchie设计,并首次在一台使用UNIX的DECPDP-11的计算机上实现,它是由早期的编程语言BCPL发展演变而来的,至今欧洲还有使用BCPL,MartinRichards改进了BCPL,从而促进KenThompson所设计的B语言的发展,最终导致70年代C的问世。一般使用的是TC,它按照C语言的标准,快速,高效的编译程序。TC提供了一个功能强劲的集成开发环境,按传统方式提供了一个命令行编译程序版本。C语言的特点C语言以其简洁,灵活,表达能力强,产生的目标程序高,可移植性好为基本特点而著称于世,归纳起来有如下几点:1)兼容其他计算机语言的一些优点,其程序结构紧凑,简洁,规整,表达式简炼,灵活,实用,用C写的程序可读性强,编译效率高。(与Pascal比较)2)运算符丰富:34种,支持强制类型转换int(3.45)3)数据结构丰富,具有现代化语言的各种数据结构。Int、double、char、string、union、struct链表、树、堆、指针4)具有结构化的控制语句if、while、for、.switch5)语法限制不太严格,程序设计自由度大6)C语言允许直接访问物理地址,位操作,对硬件直接操作双重性:低级:汇编语言 中级:宏汇编,TC3.0、forth高级:Ada、pascal、cobol、Basic、SmallTalk可视化:VC、Delphi、VB、C#、JAVAC语言是一种结构化程序设计语言,适合大型程序的模块化设计。是一种中间语言。7)生成目标代码高、程序执行效率高。8)移植性好,硬件控制能力高C与其他一些语言比较C、Basic、Pascal、Cobol简单的程序举例例1:问候main(){printf(“hi”)}例2:输出格式{printf(“%d,%s,%f ”,a,b,c);例3:自定义函数swap(intx,inty)可以看出C语言的格式特点:1、由函数组成2、一个函数由两部分组成a首部名+类型属性、参数参数类型b函数体declare+execute3、总是从main()函数开始执行的4、格式自由,一般习惯小写书写,但有规定的语法和功能{a=b;b=c;c=a}可以分多行写,一行写一句5、不使用行号,每条语句后必有分号;作为语句间的分隔符6、C语言本身没有输入输出语句7、注释/*………*/增加程序的欣赏性,可读性,可维护性{}表示程序的结构层次范围可适当使用空格和空行,增加程序的可读性。C程序上机步骤(TC环境)目前使用CTC(TURBOC)MICROSOFTCBORLANDCQUICKCEdit(编辑)?compile(编译)?link(链接)?run(运行)C程序编译一般有解释程序和编译程序两种,理论上讲任何一种编程语言既可编译,又可解释解释程序一次只读一行源程序,并且执行该行源程序所指定的操作BASIC编译程序读进整个程序并将其转换为目标代码(按照计算机能够直接运行的形式而实现对源程序的一种解释,也叫二进制码或机器码)分片编译对于一个比较长且大程序,一次编译时间长,TC允许程序分割成块,对块进行单独编译,再进行链接,形成一个可执行的目标代码文件。上机调试程序 1、打开写字板。2、输入源代码,进行剪切,复制等操作,这样容易写,速度快。3、保存为后缀为*.c的文件。4、打开TC环境,打开刚才写的文件*.c。(F3是快捷方式)5、编译(F9)调试,修改。6、执行(CTRL+F9)C程序设计要求1、程序思想对遇到的一些问题要善于思考,能否用C程序实现,形成思想,编写下简单的算法,再上机调试,以后对其不断地扩充,增加其功能,将问题扩大化,使所写程序的功能实用化,通用化,最后市场化。2、程序风格任何人都有自己的程序编写习惯,一般的程序编写都有一定的风格,希望编写程序时能遵循一些约定俗成的习惯:1、区分大小写2、缩格写3、分块写不同的程序块功能块之间有间隔4、文档备份使这些成为习惯,对程序的以后维护,思想的承前启后有一个清楚的设计思路。3、程序维护所写的程序,设计思想,要有一个比较完整的备份文档,记录一些算法,思路,程序的关键步骤以及程序最终要求等。第二章程序的灵魂—算法一个程序包括以下两个方面的内容:1、对数据的描述----数据结构(DataStructer)数据类型,数据的组织形式详细的参考《数据结构》2、对操作的描述----算法(algorithm)操作步骤著名计算机科学家沃思提出一个公式:程序=数据结构+算法再加上程序设计方法和语言环境,可以这样表示:程序=算法+数据结构+程序设计方法+语言工具环境算法是解决“做什么”和“怎么做”的问题。2.1算法的概念广义的说,为解决一个问题而采取的方法和步骤,就称为算法。解决一个问题,可以有不同的方法和步骤,一般的说,希望采用简单的和运算步骤少的方法。不仅要保证算法正确,还要考虑算法的质量,选择合适的算法。计算机算法可分为两大类别:数值运算算法和非数值运算算法。1)数值运算 求解数值解2)非数值运算事务管理类计算机在非数值运算方面的应用远远超过了在数值运算方面的应用。算法的概念由若干条指令组成的有限序列,必须满足以下性质1输入性有零个或多个输入2输出性至少有一个输出3有穷性每一条指令的执行次数必须是有限的4确定性每一条指令的含义必须明确,无二义性(岐义)5可行性每条指令应在有限的时间内完成2.2算法,过程,程序的区别可以想到许多称为算法的计算过程,但一个算法并不等于一个计算机程序,只是类似方法,过程和程序1)算法和过程的区别算法经过有限次计算执行后必会终止,过程可以有穷的,也可以无穷的2)算法和程序的区别程序用某种机器语言书写的一个计算过程算法并一定表现为一个计算机程序,它可以采用多种语言和方式来描述。算法优化2.3、简单的算法举例例1.5!例2.score>80例3.平闰年判断例4.分数计算例5.素数判断#include#includemain(){intn,i,r;scanf("%d",&n);for(i=2;i0)dobeginm:=n;n=r;r:=mmodn;end;end;附:类Pascal语言1、基本语句1)赋值语句   变量名:=表达式;2)条件语句1if条件 then语句组2 if……then……else……3)循环语句1while条件 do语句组2 repeat语句组 until条件3 for循环变量:=初值 [downto]to终值 do语句组4)选择语句(分支语句)1 case条件1: 语句组1; 条件2: 语句组2;条件i: 语句组i; else: 语句组n+1;end;2case表达式 of  常量1:语句组1;  常量i: 语句组i;  常量n: 语句组n;otherwise语句组n+1;end;5)过程或函数调用call过程名(参数表);变量:=函数名(参数表);允许嵌套和递归调用6)错误处理   error(字符串)7)跳出循环   exit8)读写语句read(变量表);write(变量表);各变量中间用逗号隔开9)注释形式{字符串}附加相应的注释2、除过程或函数中的参数,变量说明省略   3、所有算法用以下过程或函数形式表示procedure 过程名(参数表)function函数名(参数表);类型名begin语句组     end;例 最大分因子 (辗转相除法)procedureEUCLID(n,m:integer;varr:integer);beginr:=mmodn;while(r≠0)dobeginm:=n;n=r;r:=mmodn;end;end;{EUCLID} 第三章数据类型、运算符与表达式3.1、C的数据类型对数据的描述,数据结构是数据的组织形式。程序设计时应当考虑算法和数据结构,选择最佳的算法和数据结构,以达到最优化的解和计算效率。C的数据结构是数据类型的形式出现的。数据类型:1、基本类型整型字符型实型(单精度、双精度)枚举型2、构造类型数组类型结构体类型共用体类型3、指针类型4、空类型数据分为:常量C、变量V可以通过以上的数据类型构造更复杂的数据结构。如:表,树,栈,堆、图主要介绍基本数据类型。3.2常量与变量3.2.1常量常量:值不发生改变的量(字面/直接常量)#definePRICE30#definePI3.1415926#definero206265(其它语言中定义常量的方法如:constheight=72.260在高级程序设计语言中,定义常量用const)符号常量名大写1、含义清楚PRICE、PI、RO、E;起到见名知义的作用,有一定的含义。2、在需要改变一个常量能做到“一改全改”HDDY—>ECGI(考虑软件的升级时使用);这些要求在软件工程学里有体现。3.2.2变量变量:其值可以改变的量有一个名字,占一定的存储单元a---?变量名(符号地址) ?变量值存储单元标识符:用来标识变量名,符号常量名,函数名,数组名,类型名,文件名的有效字符序列。变量命名规则:字母,数字,下划线,且第一个是字符,字母或下划线,区分大小写的。要求:对所有用到的变量做强制定义,“先定义,后使用”的原则。1、保证程序中变量名使用正确。Debug(编译)时,会发现未定义。2、每一个变量被指定为一个确定类型,编译时就能为其分配相应的存储单元。3、检查变量运算的合法性。A%B3.3、整型数据3.3.1整常数(三种表示方法)1.十进制123,0.4562.八进制以o开头o123,o4563.十六进制以ox开头3.3.2整型变量1、整型数据在内存中的存放形式二进制形式存放数值补码;正数的补码和其原码的形式相同负数的补码:绝对值按位取反加12、分类基本类型int+修饰符1、基本整型int2、短整型shortint(简写为short)3、长整型longint(简写为long)无符号型:unsigned+1/2/3short低运算自左至右结合 算术运算符优先级++---(单目取负)*,/,%+-;结合性左结合性自左至右右结合性自右至左例例:10+’a’+I*f-d/e1、10+97=1072、double,运算I*f3、运算相加,双精度(107.00)结果为double4、e,double转d/e5、相减3强制类型转换转换成所需的类型例一般形式:(类型名)(表达式)例c=(int)(12.56);4自增自减使变量自动增1或减1++I,--I;I++,I--;例注意:1、自增、自减只能用于变量2、++,--的结合性是自右至左的,例5问题的说明(表达式使用中)1、处理许多问题,求值调用顺序(函数调用)避免岐义性(自加,自减)2、运算符结合(考虑结合性)i++j;3、其他3.9赋值运算符1、赋值运算符=2、类型转换(类型不一致)1.实?整,舍弃小数2.整?单,双精度数值不变,以浮点数存储 3.double?float截取前7位,要保证不能溢出4.字符?整型字符1字节,整型2字节,放入低8位里,a无符号处理:或unsignedchar赋值:高8位补0b带符号:若字符最高位为0,则整型高8位补0,若字符最高位为1,则高8位全补1,符号扩展5.int,short,long?char低8位给char6.int?long7.unsignedint?longint高位补03、复合的赋值运算符+=;-=;*=;%=;1、简化程序2、提高编译效率4、赋值表达式将一个变量和一个表达式连接起来的式子<变量><赋值运算符><表达式>例result=1*2*3*4*53.10逗号运算符和逗号表达式顺序求值运算符表达式1,表达式2,表达式3……表达式n返回值:表达式n的值例区分函数中的逗号。第四章顺序程序设计4.1C语句概述C语句用来向计算机系统发出操作指令。一条语句编译后产生若干条机器指令。C语句:1、控制语句控制作用,9种(条件控制)iffor、while、continue、breakswitchgotoreturn2、函数调用一个函数由数据定义和执行语句组成C程序源程序1源程序2源程序3.。。。。。。源程序n 预处理命令全局变量声明函数函数首部函数体局部变量声明执行语句3、表达式语句a=3;4、空语句{},里面什么也不写。5、复合语句-分程序{……}4.2赋值语句赋值表达式+;1、“=”是运算符2、表达式与语句4.3数据输入输出的概念及其实现(1)输入输出以计算机主机为主体而言的(2)C语句本身不提供输入输出语句,操作由函数实现输入:计算机—>外部(显示器、打印机、磁盘)输出:外部?计算机putcharputsprintf(3)使用C库函数时要用#include包括进用户源文件。#include允许printf和scanf可不用#include命令4.4字符数据4.4.1、putchar(字符输出)向终端输出一个字符调用方式intputchar(intch)在stdio.h中putchar宏把ch的字符写到标准输出端中去,在功能上等于putc(ch,stdout),由于在调用时字符参数被转换成整型量,所以用字符变量作为putchar()的参量,用ferror()来确定是否出现了错误。例1、putchar(c);4.4.2、getchar(字符输入)从终端输入一个字符getchar();调用方式intgetchar(void)getchar()的函数原型在stdio.h中。宏getchar()从标准输入端中返回下一个字符,该字符作为无符号字符读取,并转换为一个整型量,在读到文件结束标志时返回EOFgetchar()函数的作用相当于getc(stdin)例2、 4.5格式输入输出4.5.1printf1、一般格式printf(格式控制,输出表列);(1)格式控制双引号括起来的字符串,转换控制字符串①格式说明以%开始②普通字符(2)输出表列输出的数据,也可以是表达式printf(r1,r2,r3……rn);2、格式字符不同类型数据,用不同的格式字符(1)d:十进制整数①%d②%md例1、(2)o八进制整数例1、(3)x十六进制整数例(4)uunsigned型数据,十进制形式输出例(5)c输出一个字符例(6)s输出一个字符串①%s②%ms③%-ms④%m.ns⑤%-m.ns(7)f实数以小数形式输出①%f②%m.nf③%-m.nf(8)e指数形式输出实数①%e②%m.ne③%-m.ne(9)g输出实数,自动选f或e(占位数少的那种)使用格式符说明格式字符说明 d,i以带符号的十进制形式输出整数,(正数不输出符号)o以八进制无符号形式输出整数,(不输出符号前导符0)x,X以十六进制无符号形式输出整数,(不输出符号前导符0x)用x时则输出十六进制的a~f时以小写形式输出用X时则以大写字母输出。u以无符号十进制形式输出整数c以字符形式输出,只输出一个字符s输出字符串f以小数形式输出单,双精度数,隐含输出6位小数e,E以指数形式输出实数,如用E,则输出时,指数以大写E表示。g,G选用%f或%e格式中输出宽度较短的一种格式,不输出无意义的0,用G时,若以指数形式输出,则指数以大写表示。①除x,e,g外,一律用小写字母②可以使用转义字符③介绍9种在%后作为格式符号④输出%,用两个表4.2printf的附加格式说明字符字符说明l用于长整型数,可加在格式符d,o,x,u前面m(代表一个正整数)数据最小宽度n(代表一个正整数)对实数,表示输出n位小数对字符串,表示截取的字符个数-输出的数字或字符在域内向左靠。4.5.2scanf(格式输入)1、一般形式scanf(格式控制,地址列表);①格式控制,同printf;②地址列表;地址,变量地址,字符串的首地址例&地址运算符。2、格式说明以%开始,经一个格式符结束,中间可以附加字符说明:①对unsigned型变量,可用%u,%d,%x,%o②可指定输入数据所占列数③在%后有*,表示跳过他所指定的列数。④输入时不能规定精度。3、作用scanf应注意的问题①格式控制,变量地址,不是变量名②格式控制中除说明外还有其他字符,则输入时应输入与这些字符相同的字符③用%c输入,空格、转义字符将作为人交叉输入④输入数据时,遇以下字符认为结束:a空格 b按指定的宽度c非法输入例4.6程序举例1.扩充功能(思考,作为下一节课的预习)①判断三边能否构成一个三角形。②判断形状2.扩充①判断是否是字母形式不是的话,给出错误信息②是否是大写形式用到的函数intisalpha(intch)intisupper(intch)3.扩充①改掉b^2-4ac>0的条件,加入判断语句。②考虑虚根的形式③考虑a的值可能用到的函数intisxdigit(intch)判断是否是空格intisspace(intch)判断是否是标点,字符或空格。intispunct(intch)判断是否是可打印字符intislower(intch)小写字母intisgraph(intch)除空格以外的任何可打印字符intisdigit(intch)0…9intiscntrl(intch)0到Ox1F之间,或Ox1Fintisascii(intch)0~Ox7Fintisalpha(intch)字母intisalnum(intch)字母或数字所有的原型在ctype.h中。例1、for(I=0;I<128;I++){printf(“%o“,i);if((I%5)==0)printf(“ ”);}第五章选择结构程序设计5.1关系运算符和关系表达式关系运算符在逻辑运算中比较简单的一种,关系运算实际上就是比较运算,将两个值进行比较,判断其比较的结果是否符合给定的条件。 前面已介绍了选择结构的一部分,在C语句中选择结构是用if语句实现的(if表达式1语句1else语句2)逻辑运算比较运算5.1.1运算符及基优先次序6种运算符①<、>、<=、>=②==,!=2)关系运算符低于算术运算符3)赋值运算符低于关系运算符5.1.2关系表达式用关系运算符将表达式连接起来的式子返回真、假(true、false)C没有逻辑型数据(logical)5.2逻辑运算符和逻辑表达式用逻辑运算符将关系表达式或逻辑量连接起来的式子。5.2.1运算符优先次序①&&与(and)②||或(or)③!非(not)优先级!>&&>||运算符的优先级优先级!(非)高算术运算符关系运算符&&、||赋值运算符低表5-1逻辑运算的真值表ab!a!ba&&ba||bTTFFTTTFFTFTFFTTFFFTTFFT5.2.2逻辑表达式其值为真或假(0、1)只有两个值表达式自左至右求解:左结合性并不是判断和执行所有的运算。例①a&&b||c②a||b||c 例:求闰年①%4不能被100除②能被400整除((year%4==0)&&year%100!=0)||year%400==0)不能确定其优先级的,则加几个括号括起来,优先级考虑,避免出现逻辑错误。5.3if语句用来判断给定条件是否满足,根据结果执行其中的语句1、if语句例1、2、if表达式1else表达式2例2、3、if表达式1语句1else表达式2语句2else语句n说明:①表达式为逻辑或关系表达式②每个else前有分号③内嵌语句块{}例1、例2、5.3.2if语句嵌套(用case,switch代替)if()if()elseelseif()else配对关系要加{}配对,当if与else数目不一致时例1、5.3.3条件运算符表达式1?表达式2:表达式3;说明:①执行顺序②优先赋值运算③自右至左结合④不能取代一般的if语句⑤表达式可以是不同的类型例:5.4switch语句多分支选择语句一般形式:switch(表达式) {case常量表达式1:语句1case常量表达式2:语句2……case常量表达式I:语句I……default:语句n+1}说明:①switch表达式为任何类型②满足条件则执行哪个case条件,否则执行default③case可以互不相同④与顺序无关的⑤要终止的话,使用break语句⑥多个case语句可以共用一组执行语句。5.5程序举例例1、例2、第六章循环控制6.1概述许多问题需要用到循环控制①goto……if②while③do……while④for6.2goto语句以及用goto语句构成循环goto:无条件转向一般形式:goto语句标号用途:①与if构成循环②跳出循环体。例:6.3while语句while:实现当型循环一般形式:while(表达式)语句例:注意:①复合语句用{}②趋于结束的语句,否则陷于死循环。 6.4do……while循环先执行循环体,再判断条件是否成立。一般形式:do{语句块;}while(表达式);例:6.5for循环for循环是循环中最为灵活的,它的一般形式:for(表达式1;表达式2;表达式3)可以这样来理解:for(变量赋初值;循环条件;循环变量增(减)值)①表达式1,表达式2,表达式3可省但必须给定初始值,条件,以及退出循环。②表达式可为任意类型6.6循环的嵌套三种循环可以互相嵌套。例1:6.7几种循环的比较①可以互相代替②while,do循环,while后,循环条件,应有结束循环的语句。③whiledo,应先初始化④break跳出循环。例:6.8break和continue语句6.81.break语句break;6.8.2continue语句continue;break和continue的区别break结束整个循环过程continue结束本次循环例:6.9程序举例例1、例2、第七章数组 有序数据的集合,统一的数组名和下标,唯一确定数组中元素。(与其他高级语言差不多)7.1一维数组的定义和引用7.1.1定义类型说明符数组名[常量表达式]intclass[4];表示数组名为class,有4个元素说明:①遵循标识符命名规则②[],不能用()③数组长度?常量表达式,即不支持动态数组。④不能是变量,不能动态的定义。可以是常量和符号常量例:7.1.2一维数组的引用先定义,后使用。一般形式:数组名[下标名]只能逐个引用数组元素而不能引用整个数组,下标可以是整型常量或整型表达式。例:7.1.3一维数组的初始化初始化方法①定义的同时初始化例②部分初始化例③全部赋值为0例④给全部值赋初值,可以不指定数组长度。例1)依次赋值inta[5]={1,2,3,4,5}2)部分赋值inta[10]={1,2,3,4,5}/*只对前面5个赋值。*/3)全部赋值为0inta[10]={0,0,0,0,0,0,0,0,0,0,0,0}不能写成inta[5]={0*5}4)赋值时不给定数组长度inta[]={1,2,3,4,5}系统自动定义数组的长度,若定义的数组长度与提供值的个数不同,则数组长度不能省略的。7.1.4程序举例例1、FibonacciMain(){ intI;intf[20]={1,1}For(I=2;I<20;I++)F[I]=f[I-2]+f[I-1]For(I=0;I<20;I++){if(I%5==0)printf(“ ”);printf(“%12d”,f[I]);}}①对于一个一维数组,整个个数组所占字节大小可由下式计算总字节数=类型长度*数组长度②所有数组都以0作为其第一个元素的下标值。③在C语句中,不对数组作边界检查的,这要求程序员自己作边界检查。④一维数组实际上是具有相同类型的信息表。7.2二维数组的定义和引用7.2.1二维数组的定义一般形式类型说明符数组名[常量表达式][常量表达式]intclass[4][30]数组的元素是按行逐个存放的。第一维的下标变化最慢,最右边的下标变化最快。定义:不能inta[3,5];二维数组看作是一种特殊的一维数组,它的元素又是一维数组。例:#include#includemain(){inta[3][4],I,j;for(I=0;I<3;I++){for(j=0;j<4;j++){a[I][j]=I*4+j+1;printf(“%d”,a[I][j]);}printf(“ ”);}}二维数组是以行-列矩阵形式来存储的,前面的行,后面的列,这意味着汉按照内存的实际存储顺序存取元素时,最后也比最左边的下标变化要快的。7.2.2二维数组的引用数组名[下标][下标]例:inta[3][4];最大的一个数组元素表示:a[2][3],因时它是从0开始表示的,不以引用a[3][4],这样超出数组的范围。7.2.3二维数组的初始化①分行给二维数组赋初值②将所有数据写在一个{}内,按数组排列顺序赋值。③对部分数据初始化 ④全部赋值,第一维可以不指定。①inta[2][3]={{},{}};按行赋值,直观,第一行是第一个花括弧②inta[2][3]={1,2,3,4,5,6}数列排列,排完第一行的所有列后再进行下一行。这样好对少量数据还可以,对于大量数据则容易遗漏,不易检查。③inta[3][4]={{1},{5},{9}}只第一列赋值,其余的元素自动为0,能这样,也可以对各行中的某一元素赋值;inta[3][4]={{1},{0,5},{0,0,5}}inta[3][4]={{1},{},{0,0,5}}④全部赋值,可不指定第一维的长度,但第二维不可省略。Inta[3][4]={1,2,3}Inta[][4]={1,2,3}7.2.4程序举例举例1)求矩阵的转置a[I][j]=b[j][I]2)求矩阵的最大值,最小值a[I][j]>min;a[I][j]#defineMax100#defineLen80chartext[Max][Len];main(){registerI,j,k;clrscr();for(I=0;Imain(){charstr[80];strcpy(str,”thisisaexample”);slrscr();puts(str);}2.gets(字符数组)作用:从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。在stdio.h中,从标准输入设备中读取字符串并把它们放到str(串)指向的字符数组中去,它读取字符数组直到遇到换行符或读到EOFEOF和换行符不进入字符串,它们被转换这空字符并作为字符串的结束符。调用成功则返回str,否则返回指针。Gets读取的字符个数没有限制,注意保证str所指向的数组应足够大。3.strcat(字符数组1,字符数组2)连接两个字符串。把str2连接到str1中去,并以空(NULL)结束str1,原来作为str1结尾的空结束符被str2的第一个字符覆盖了,而str2未被修改。没有边界检查,所以str1要足够大。调用成功返回合并后字符串的指针。Char*strcat(char*str1,char*str2);string.h例:#includemain(){chardest[50];charstr1=”computer”,*str2=”Personal”,*blank=””;strcat(dest,str2);strcat(dest,blank); strcat(dest,str1);printf(“%s ”,dest);}4.strcpy(字符数组1,字符数组2)把字符串复制到字符数组中去把str2的内容复制到str1中,str2必须是一个指向(null)结尾的字符串的指针,若str1,str2重叠,函数的行为是非法的。函数返回str1的指针。Char*strcpy(char*str1,char*str2)string.h#includemain(){chardest[50];char*source=”1233456789”;strcpy(dest,source);printf(“%s ”,dest);}说明:1)str1必须足够大,以便容纳被复制的字符串2)复制时连同字符串后面的‘’一起复制到str1中。3)str1必须是数组形式,str2可是字符数组名,也可是一个字符串常量。4)不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组。类似的函数:stpcpystpcpychar*stpcpy(char*dest,char*source)string.h拷贝字符串*source到dest,直接拷贝到终结空字节符为止。返回dest+strlen(source)的值。例#includemain(){char*src=”test”;chardest[20];stpcpy(dest,src);printf(“%s ”,dest);getch();}5.strcmp(字符数串1,字符数串2)比较两个字符串返回值是:0,正,负整数。1、strcmp,stricmp,strcmpintstrcmp(char*str1,char*str2);intstricmp(char*str1,char*str2);intstrcmpi(char*str1,char*str2);都用于比较两个字符串,比较的方法是从第一个字符开始,按字符顺序逐个进行比较,直到对应的字符不相同或达到串尾为止。 返回值含义<0str10str1>str2strcmp与stricmp,strcmpi的区别是只有strcmp在比较时区分大小写,另外的不区分大小写的。Stricmp与strcmpi比较,strcmpi是宏,该宏把对函数strcmpi的调用转变为对stricmp的调用。例:#includemain(){chars[50];printf(“ enterpassword:”);gets(s);while(strcmp(s,”test”){printf(“ invalidpassword,retryagain? ”);printf(“enterpassword”);gets(s);}printf(“ok”);}6.strlen(字符数组1,字符数组2)测试字符串长度的函数unsignedstrlen(char*str)string.h用来计算以空(null)结束的字符串长度,并且返回字符串的长度,null不计算在内,也即实际长度,也可直接测定字符串的长度。Charstr[10]={“china”};Printf(“%d”,strlen(str));Strlen(“china”);7.strlwr(字符数组1,字符数组2)转换为小写字母char*strlwr(char*str)string.h把str所指向的字符串都变为小写字母8.strupr(字符数组1,字符数组2)转换为大写字母。char*strupr(char*str)string.h把str所指向的字符串都变为小写字母7.3.7字符数组应用举例例:1)查找字符串(strstr)2)插入字符在指定的位置,3)删除字符指定的位置或指定的字符。 第八章函数8.1概述一个大程序分为若干个小模块,每一个模块可以实现一个特定的功能,用于程序实现的功能。C语言中,子程序是由函数组成的。例:函数1)库函数2)自定义函数1)有参函数2)无参函数8.2函数定义的一般形式,1、无参函数的定义形式类型标识符函数名(){声明语句}2、有参函数的定义形式类型标识符函数名(参数列表){声明语句}3、空函数{}主要用于程序的扩展,便于程序的升级4、对形参的声明的传统方式例8.3函数的参数和函数的值8.3.1形式参数和实际参数主调函数与被调函数有数据传递关系,即有参例:形参与实参的说明①形参定义时,并不占用内存中的存储单元(调用时才分配)②实参可以是常量,变量,也可是表达式,但要求有确定的值。③指定形参类型(在被定义的函数)④实参与形参的类型应相同或赋值兼容。,声明 ⑤实参是值传递,属于单向传递8.3.2函数的返回值有时希望通过函数调用使主调函数能得到一个确定的值。①return返回return作用1)它能立即从所在的函数中退出,即返回到调用它的程序中去。2)它能返回函数值,将函数值赋给调用的表达式,当然,也有没有返回值的。A、函数返回有两种方法可以终止函数的执行,并返回到它的调用语句执行到函数的最后一条语句。B、return可以有一个以上的return语句。②函数值类型在定义时指定。③以函数类型为准。除void外,所有函数的一个返回值,由return指定,没有return就返回0.三种类型函数,除void①单纯计算:专门对一系列参数作运算,并将结果返回。Math.h中函数。?纯函数②返回操作数,并且返回一个表明操作成功与否的简单值。文件操作write(),EOF③无明确的返回值。单纯的一个过程,并且不产生数值。Srand()?rand()返回非整型值:缺省为int,当返回不同类型数据时,使用以下步骤:①必须给函数以明确的数据类型定义符②函数的类型必须在它被调用前作明确的说明。例:④无返回值⑤不带回,明确表示,用void例:8.4函数的调用8.4.1函数调用的一般形式函数名(实参列表)各参数用逗号隔开。(无参)括号不能省略,实参对应8.4.2函数调用的方式三种函数调用方式1、函数语句类似一个过程,完成一个特定的操作例: 2、函数表达式出现在表达式中,返回一个确定的值参与计算。例:3、函数参数作为函数调用的参数例:赋值调用和赋地址调用通常可以用两种方式来给函数传递参数①赋值调用把实参的值复制给形参,而函数中形参的改变对调用它的实参没有影响。②赋地址调用把实参的地址复制给形参,在函数中,该地址用来访问在调用程序中的实参,这意味着,对形参的改变会影响调用程序中的实参。除个别外,C语言通常是用赋值调用的方法来传递参数,这意味着通常不能改变调用该函数的变量。例:#includemain(){intt=10;printf(“%d,%d”,sqrt(t),t);}sqrt(intx){x=x*x;return(x);}本例中,sqr()的参数值10被复制给形参x,当执行到x=x*x;时,只改变局部变量x,用来调用sqr()的变量仍是10赋值调用的过程可以理解为:①在堆栈中分配局部变量给形参将实参值赋给形参。8.4.3对被调用函数的声明和函数原型调用条件①已经存在的函数(标准库函数,用户自定义函数)光有这个还不够。②使用库函数要用#include语句。③自定义函数,主调函数内在声明。例:函数原型函数声明,合法性检查一般形式:①函数类型函数名(参数1,参数2)②函数类型函数名(参数类型1参数名1,参数类型2参数名2) 例:传统老版本C中,对形参的类型声明是放在函数定义的第2行,即不在第1行的括号内指定形参的类型,而在括号外单独指定。现代风格把类型和变量名都放在函数名后面的参数表中,用圆括号括起来,类似函数原型说明,只是还包括了参数名。floatfune(int.x,floaty)charstr(c,s){charc,s;printf(“%f“,y/(float)x);{函数体}}函数原型:(functionprototype)返回非整型量的函数都必须在使用前加以说明,TC中将此概念扩展,既进一步说明函数的参数个数与类型,这一扩展定义称为函数原型。函数原型能使C编译程序提供更强的类型检查,类似Turbopaud等语言提供的检查。函数原型的一般形式:类型函数名(参数类型1,参数类型2,…参数类型n);其中,类型就是函数要返回值的类型。参数类型就是每个参数的类型。Floatfunc(int,float)使用函数不仅可以帮助找出错误,同时不允许被调用函数有不匹配的参数,或者错误的参数数量,从而确定你的程序正确运行。大型程序中,或几个编程中为同一项目工作,使用函数可避免很多错误说明:①旧版C不采用原型,而只声明函数名和函数类型,不包括参数类型和个数②无声明,第一次遇到函数形式作为声明③子函数在主调函数之前,可不必加以声明。④外部函数声明不必再声明。例:8.5函数的嵌套调用C语言的函数定义都是互相平行的,独立的,即定义函数时,不能包含另一函数,不能嵌套定义函数,但可以嵌套调用函数。执行过程a?b?c例:8.6函数的递调用在调用一个函数的过程中又出现了直接或间接地调用本身有时被称为循环定义,即用其自身来定义自己的过程。对于计算机语言来说,若要实现递归则函数必须能够调用自己。简单的例子,阶乘factr(),与他的非递归等价的迭代方法fact()factr(intn)fact(intn){intanswer;{intt,answer; if(n==1)return1;for(t=0;t<=n;t++)answer=factr(n-1)*n;answer=answer*(t);returnanswer;returnanswer;}}当函数调用它自己时,新的局部变量和参数就会要堆栈中分配存储单元,同时函数代码以新变量重新开始执行。大多递归程序并不能明显地减少代码或变量存储大小,或许执行效率慢(因为增加函数的调用次数),造成栈超限,(每次调用,新拷贝,减少空间):优点:实现比同类型的迭代更简单明了的算法。(人工智能,快速分类)有一个if语句控制(或增加调试语句)。例1:例2:8.7数组作为函数参数数组作为函数参数与变量用法相同,数组名也可作实参和形参,传递的是整个数组。1、数组元素作函数实参单向传递,由于实参可以是表达式,数组元素可以是表达式的组成部分,因此数组元素可以作为函数的参数,与用变量作实参一样,是单向传递?值传递。例:2、数组元素作函数实参可用数组名作为函数参数,此时实参与形参都应用数组名(或用指针变量)例:说明:①用数组名作参数,两边都要定义(主调与被调)②类型一致(形参与实参要一致)③形参不做大小检查,只传递首地址。(形参数组不指定大小),根据需要可以另设一个参数。④作实参,起始地址给形参。3、用多维数组名用函数参数形参可以省略指定大小,只省一维。例:inta[4][3]等价于inta[][3]不能全省,内存中存放是一行一行的顺序存放的。8.8局部变量和全局变量8.8.1局部变量函数内部定义的变量,只在本函数内有效,外面则无效。例:说明:①在main中定义的只能在其中有效,主函数也不能使用其他函数中的变量 ②不同函数可以使用相同的变量名,代表不同的对象,互不干扰。③形参也是局部变量,只在自己定义中有效④可以在复合语句中定义变量,只在这个复合语句中有效。例:8.8.2全局变量(全程变量)函数外定义的变量,可以为本文件或其他文件中所共用,从定义开始到程序结束都有效例:说明:①增加了函数间数据联系的渠道不成文规定,将全局变量的第一个字母用大写表示。②不在必要时不使用全局变量1)一直占用内存单元,不是按需分配2)通用性差,执行时依赖其所在的外部变量3)清晰性,全局变量名多③同一源文件中,外部变量与局部变量同名的话,则在局部变量作用域内,外部变量不起作用。8.9变量的存储类别8.9.1动态存储方式与静态存储方式变量值的存在时间(生存期)静态存储方式:程序运行期间分配固定的存储空间的方式动态存储方式:程序运行期间根据需要进行动态的分配存储空间的方式。存储空间1.程序区2.静态存储区3.动态存储区静态:全局变量动态:①形参②自动变量auto③数调用的现场保护和返回地址C语言变量和函数的两个属性①数据类型②存储类别:静态动态a.自动:autob.静态:staticc.寄存器:registerd.外部:extern8.9.2auto变量动态,调用时分配存储空间,结束释放如不专门声明为static存储类别,都是动态地分配存储空间的,数据存放在动态存储区内,函数形参及变量都属此类,调用时系统会给他们分配存储空间,调用完毕自动释放空间。用关键字auto作存储类别的声明autointa intaautointb,(=intb;)可省略8.9.3用static声明局部变量调用结束后保留原值静态变量在其所在的函数或文件中是永久变量,不同于全局变量,因为他们在函数或文件外是未知的,但他们在函数调用之间可以保存其值。1、静态局部变量局部变量前加静态变量说明符,编译程序为该变量建立永久存储单元,静态局部变量是一中在两次函数调用之间仍然保持其值的局部变量。静态局部变量与全局变量的根本区别在于局部变量只在它被说明的函数和复合语句中是有效的。static说明:①静态存储,在静态存储区内分配存储单元,运行期间不释放②编译时赋初值.运行时就有值.③自动赋值为0,或空字符.不赋值的话④其他函数不能引用例1使用条件:①需要保留函数上一次调用结束时的值.②初始化后,变量只被引用而不改变其值.例:1、求n!intfac(intn){staticintf=1;f=f*n;returnf;}main(){intI;for(I=1;I<=5;I++)printf(“%d!-%d ”,I,fac(i);}静态存储变量要多占内存,降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是多少?Main(){do{count(10);}while(!kbhit());printf(“countcalled%dtimes”,count(1));}count(intI);{staticintc=0;if(i)returnc; elesc++:return0;}程序说明:staticintc=0;由于c被说明为静态局部变量,它的地址将c赋初值0,在main()中,以后都不再对c赋初值。有时需要了解在程序运行中某一个函数被调用了多少次,可以用一个全局变量来实现,而更好的是让函数自己跟踪调用次数的信息,如count(),在上面例子中,若count()调用时,参数为0,则c=1;否则函数返回其被调用次数,在程序开发中,统计函数被调用的次数是很有用的。8.9.4register变量使用频繁,放在CPU中的寄存器中,需要时直接从寄存器中取出参与运算,用register作声明,只能用于整型和字符型变量例1说明:①只有局部自动变量和形式参数可以作为寄存器变量.(它属于自动产生型变量)②不能任意定义多个寄存器变量.(数目不限)③局部静态变量不能定义为寄存器变量registerstaticinta,b,c;例:计算一个以整数为底的指数幂meint_pwr(intm,registerinte);{registerinttemp;temp=1;for(;e;e--)temp*=m;returntemp;}说明:e,temp为寄存器变量,都用于循环中,在实际应用中,寄存器变量只用在同一个变量名频繁出现的地方。8.9.5用extern声明外部变量(扩展外部变量的作用域)一个文件中定义外部变量,另一文件中用extern对其作外部变量声明1、在一个文件内声明外部变量如果一个外部变量不在文件的开头定义,其有效范围只限于从定义处到文件终了,若在定义前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作外部变量声明,表示该变量是一个已经定义的外部变量。例:intmax(intx,inty)main(){intz;{externA,B;z=x>y?x:y;printf(“%d”,max(A,B));“return(z);intA=13,B=-8;}结果13; 2、在多文件的程序中声明外部变量C由多个源程序文件组成,例:若在一个程序中包含两个文件,在两个文件中都要用到同一个外部变量num,不能分别定义一个外部变量num,否则出现重复定义的错误。正确的方法是:在任一个文件中定义外部变量num,而在另一个文件中用exern对num作外部变量声明。Externnum;8.9.6用static声明外部变量有些外部变量只限于被本文件使用,可在定义外部变量时加一个static声明用static声明外部变量例:file1.cfile2.cstaticintA;externintA;main()func(intn);{……}{……A=A*n;……}用static不声明变量的作用有2个①对全局变量用static声明,则为该变量分配的空间在整个程序执行期间始终存在。②全局变量用static声明,则该变量的作用域只限于本文件模块。8.9.7关于变量的声明和定义声明:定义函数的声明是函数的原型,函数{声明部分+执行语句}函数的定义是函数的本身声明:放在声明部分声明包括定义,但并非所有的声明都是定义①定义性声明→建立存储空间②应用性声明声明可多次8.9.8存储类别小结对一个数据定义,要指定两种属性;数据类型和存储类别,分别使用关键字autostaticregister可以用extern声明已定义的外部变量从不同角度归纳:一个变量的性质可从两个方面分析,一是从变量的作用域,一是变量的存在时间的长短,即生存期。⒈作用域作用域:如果一个变量在某个文件或函数范围内是有效的。在此作用域内可以引用该变量,又称其是“可见的”变量的可见性局部变量{自动变量(动态局部变量,离开则消失)静态局部变量(离开值仍保留) 寄存器变量(离开函数,值就消失)(形参)(形参可以定义为自动变量或寄存器变量)全局变量静态外部变量(只限本地文件引用)外部变量(非静态局部变量,允许其他文件引用)⒉生存期变量在某时刻存在的,称为此变量的生存期。动态存储自动变量(本地有效)函数寄存器变量(本地有效)函数形参静态存储静态局部变量(函数内有效)静态外部变量(本文件内有效)外部变量(其他文件可引用)⒊存放位置内存区静态存储区静态局部变量静态外部变量(函数外部)外部变量(可为其他文件引用)动态存储区:自动变量和形参4.作用域和生存期8.10内部函数和外部函数本质上是全局的。8.10.1内部函数(静态函数)只能被本文件中其他函数调用static类型标识符函数名(形参表)staticintfun(inta,intb)适合模块化编写。8.10.2外部函数①定义时冠以extern②在需调用此函数的文件中,用extern声明所用的函数是外部函数例8.11如何运行一个多文件的程序1、TC环境①先后输入并编辑4个文件②在编译状态,建立一个项目文件,只包含文件名③存盘,扩展名为*.prj④F9⑤Ctrl+F92、include命令。8.12在建立C语言函数时,应该记住几个重要的问题,它们影响函数的效率和实用性。1、参数和通用函数通用函数是适用于各种场合,或许还为许多不同的编程者所共用的函数,典型特征,不该使通用函数建立在全局变量的基础上,函数需要的所有信息应由它的参数来传递。个别情况下,(无法满足这一个条件),也该使用静态(static)变量 参数保证通用外,还使程序代码可读,并且能避免了由于内在的因素引起的错误。2、效率函数是组成C语言的模块,除个别不程序外,它几乎是编写所有程序的关键,在某些特定的引用中,宁愿放弃函数,采用直接插入语句来代替。直接插入语句(in_linecode)与函数的作用相同,但不调用函数,仅在运行速度很关键的情况才采用代替函数调用。直接插入比函数调用快①一个“call”结构要花一定的执行时间②所传递的参数要放置到堆栈中。例:main(){intx;for(x=1;x<11;++x)printf(“%d”,x*x);}main(){intx;for(x=1;x<11;++x)printf(sqr(x));}sqr(intx){return(x*x);}第九章预处理命令加入预处理命令,改进程序设计环境,提高编程效率。可以使用预处理和具有预处理功能预处理功能1、宏定义2、文件包含3、条件编译以#开头TC可包含多种预处理指令,这些指令并不真正属于TC语言的内容,它们用来扩展C语言程序的编程环境。预处理指令:#define#error#include#if#else#elseif#elif #ifdef#endif#ifndef#undef#line#pragma#define9.1宏定义宏指令#define用来定义一个标识符和一个字符串,在程序中每次遇到该标识符时就用所定义的字符串,这个标识符叫做宏替换名,替换过程叫宏替换。9.1.1不带参数的宏定义用一个指定的标识符来代表一个字符串,一般形式:#define标识符字符宏名:宏展开#define宏定义展开例:#defineTRUE1#defineFALSE0说明:①习惯大写字母②减少程序书写③宏定义,简单的转换④不是C语句,不必在行末加分号⑤有效范围在本程序结束⑥可以用#undef命令来终止宏定义的作用域⑦可以引用已定义的宏名,可以层层置换⑧用双括号括起来的字符串内字符,即宏名同也不置换⑨宏定义是专用名词,只替换,不分配内存空间9.1.2带参数的宏定义参数替换,它的一般形式:#define宏名(参数表)字符串字符串包含括弧中所指定的参数例:#defineMIN(a,b)(a#include“文件名”例:说明:①1个#include只能包含一个文件②多层包含,要注意顺序③包含嵌套④可用尖括号或双引号⑤被包含文件与包含文件是同一文件9.3条件编译有选择地编译程序中的某些部分,广泛用于商业软件中,为一个程序提供各种版本(学习版,专业版,企业版)#if#else#elif#endif所有行参与编译,但有时希望满足一条件才执行,指定编译条件一般形式:1、#ifdef标识符程序段[#else程序段]#endif2、#ifndef标识符程序段[#else程序段]#endif3、#if标识符程序段#else程序段#endif#elif 含义:elseif建立多重编译操作选择后跟一个常量表达式一般格式#if表达式语句段#elif表达式i语句i#elif表达式n语句段n#endif#ifmax>100#ifserial_versionintport=198;#elifintport=200#endif#elsecharout_buffer[100];#endif#undef用于删除事先定义了的宏定义#undef宏名主要是用来使宏替换名只限定在需要使用它们的程序段中,#line用来改变TC预定义的宏替换名_line_和_FILE_的内容存放当前编译的行号存放当前编译的文件名#line行号[“文件名”]#pragma使得编译程序发生器发出各种命令给编译程序#pragma名字名字即所调用pragma的名字,定义两类warn和inlinewarn:使TC越过警告信息的选择项#pragmawarn设置–>选择项inline告诉TC在程序中包含一段汇编语言#definelen10#undefinedlen#line100行数从100开始,out:#line语句后的第三项。main(){printf(“%d ”,_line_); }预定义的宏替换名59ANSI_LINE__FILE__DATE__TIME__STDC_TC_CDECL__COMPACT__HUGE__LARGE__LARGE__MEDIUM__MSDOS__PASCAL__SMALL__TINY__TURBOC__DATE_月/日/年形式的字符串,它是源文件编译为目标文件时的日期_TIME_小时:分钟:秒形式字符串,源文件编译转为目标文件时的时间_STDC_存放十进制常数1,由说明使用的环境工具程序是标准工具程序,若不是1,则工具程序一定是与标准不同的。_CDECL_如果使用了标准C调用协议,即pascal选择项没有使用时,由使用_CDECL_否则这个项就没有定义。对于编译中定义的存储模式,只能是6选1:tiny,small,compact,medium,large,huge当使用MSDOS调用协议时,宏MSDOSP被定义为1当使用Pascal调用协议编译文件时,定义Pascal,否则没有定义。_TURBOC_存有所使用TC的版本号,它是一个16进制常数,左边就是主要修订版号,右两位是辅助车,202代表版本2.02。第10章指针指针是C语言中的一个重要的概念,也是其一个重要特色,正确地运用指针可以:①有效地表示复杂的数据结构②动态地分配内存③方便地使用字符串④有效而方便地使用数组⑤函数调用返回多个值⑥直接处理内存地址还可以修改函数中被调用的参量,提高某些程序的效率。指针的概念复杂,使用灵活,需要使用者多思考,比较,上机调试,在实践中掌握。10.1地址和指针的概念 为了弄清什么是指针,必须弄清数据在内存中是如何存储的,又是如何读取的,如果在程序中定义了一个变量,在编译时就给这个变量分配内存单元,系统根据程序中定义的变量类型,分配一定长度的空间,内存区的每一个字节有一个编号,即“地址”。区别:内存单元的地址与内存单元的内容程序中一般通过变量名来对内存单元进行存取操作(其实程序通过编译以后自己将变量名转换为地址,对变量值的存取都是通过地址进行)。直接访问:按变量地址存取变量值间接访问:将变量的地址存放在另一个变量中,定义一个存放地址的变量指向:通过地址来体现。由于通过地址能找到所需的变量单元,可以说地址指向该变量单元,将其形象地称为“指针”一个变量的地址称为该变量的“指针”若有一个变量专门用来存放另一个变量的地址,由称它为“指针变量”指针变量的值(指针变量中存放的值)是指针(地址)指针是地址把指针仅看伯是内存中的一个地址,多数情况下这个地址是内存中另外一下变量的位置,如果V1包含了V2,则V1可以说成是指向V21000 例:         直接访问,间接访问示意图   直接访问           间接访问   将3送到变量中     将3送到变量I_pointer所指向的单元指向:通过地址来体现的。I_pointer的值为2000,是变量I的地址。这样I_pointer与I之间有联系了。由于通过地址能找到所需的变量单元,地址指向该变量单元,将地址形象化地称为指针,即通过它能找到以它为地址的内存单元。10.2变量的指针和指向变量的指针变量变量的指针就是变量的地址。 存放变量地址的变量就是指针变量,用来指向另一个变量*用来表示指向P代表指针变量。*P代表所指向的变量 ,即*P也是代表一个变量。例 I=3;*p=3;将3赋给p所指向的变量。10.2.1定义一个指针变量C语言规定“先定义,后使用”,指定其类型,并按此分配内存单元(int2,float4),指针变量不同于整型变量和其他类型的变量。它是用来专门存放地址的,必须定义为“指针类型”。例:inti,j;int*p1,p2;基类型:任何有效的C语言数据类型。 变量名表示指针变量名指针基本类型定义了指针可以指向的变量的类型,从技术上讲,任何类型的指针都可以指向内存中任何位置,但所有的指针的算术运算仅按他们的基本类型进行。必须指定基类型我们知道,整型数据和实型数据在内存中所占字节数是不相同的,(int2,float4),对于指针的移动运算(加,减),若有p+1,1代表什么,若p指向int,那么p+1表示使地址值加2个字节,由指向下一个元素值了。一个指针变量只能指向同一个类型的变量。指针变量的基类型:用来指定该指针变量可以指向的变量的类型,定义指针变量的一般形式:基类型  *指针变量名一个指针说明包括:基类型,符号*,变量名。指向:使指针变量指向另一个变量。Pointer_1=&I;注意:①指针变量前面的*,表示该变量的类型为指针型变量。(p是指针变量名,*p是p指向的变量。)②在定义指针变量时必须指定基类型。10.2.2指针变量的引用指针运算符有专门的运算符,*,&;1、&是一目运算符,仅表示返回这个操作数的内存地址。(一目运算符只要一个操作数) m=&count,将变量count的地址赋给m;这个地址是这个变量(count)在计算机内部的地址,它没有对变量count的值作任何修改。 &操作也可以认为是返回变量的地址。进一步理解…100…   假设count在内存中位置是2000,而它的值是100,执行后  m=2000   2、*运算符表示返回这个地址中变量的值例 若m包含了变更count的内存地址,则q=*m 将count的值赋给q;此时q=100,(因为在地址2000中的值是100)这个地址恰好是m所存地址。*运算符可以理解为q接受了在地址m中的值。指针变量必须保证它指向正确的数量类型。当说明一个指针是整型数时,编译程序就认为他可以指向一个整型变量的任何地址,因为C允许用户指定任何地址给一个指针变量。指针变量中只能存放地址,不要将一个整型量赋给一个指针变量。例:int*p;p=100;①如果执行了pointer_1=&a,语句&*pointer_1变量a的地址。②*&a含义即&a所指向的变量③(*pointer_1)++相当于a++例:例:以下程序只给出警告信息,得不到结果。Main()本意想将x的值给y;{floatx,y;p是整型,仅将2字节的内容给yint*p;而不是4字节的内容给yp=&x;y=*p;}例2:10-1通过指针变量访问整型变量  intp1=&a;①定义整型变量,整型指针变量,无确定内容。②p=&a;指向a;③*p即变量a;&*p与*&a1、&*p若定义p=&a&,*的优先级相同,根据右结合性,先执行*p,即变量a,再执行&运算,即取得变量a的地址,&a即&*p与&a相同。有p2=&*p1p2=&a;(给地址) 若原来p2=&b的话,执行后则也指向a了。 2、*&P先运算&,得到a的地址,再*运算,即&a所指向的变量。*&a与*p1的作用是一样的。(都是变量a).3、指针表达式含有指针的表达式与其他表达式具有相同的规则,简要介绍一直指针的特殊性。①指针赋值指针可以用赋值语句的右边将它的值赋给另一个指针。Main(){intx,*p1,*p2;p1=&x;p2=p1;printf(“%p”,p2);}结果为FFD2,X的16进制的地址将以%p的printf格式被显示。不是x的值。②指针的算术运算指针只有+,-两种运算。设p1是一个指向整型量指针,目前值是2000,高这个整型量有2个字节长,则p1++;表示p1现在的内容是2002,而不是2001,p1每增加一次,它指向下一个整型数,这同样适用于减法。 P――(1998)指针每加一次,它就指向它的基类型的下一个元素的内存位置,每减一次,就指向前一个元素的内存位置。在字符型指针情况下,它们的增减才只有一个字节。其他所有指针都按照它所指向的数据类型的字节长度增减,更一般地说,所有指针的算术运算都是根据指针的具体类型来计算的。因此指针总是指向基本类型的相应元素。Char*ch=3000;Int*I=3000;对于指针的加减,不只限于+1或-1,也可以将一个整数加到这个指针上,或从这个指针中减去一个整数。例:  p1+=9从目前位置移到它下面的第9个元素。除加减外,指针不允许有其他的运算,不能做乘法,除法运算,位运算,不允许将两个指针相加减(大部分情况下)指针通常是以动态分配形式来确定的,其在内存中的位置是随机的,即不是一个确定的值。③指针比较 在关系表达式中,允许将两个指针进行比较。if(p1==p2)printf(“lower ”);TC中,比较常用于两个或两个以上的指针都指向一个公共对象时。10.2.3指针变量作为函数参数函数的参数不但可以是基本类型,也可以是指针类型,它的作用是将一个变量的地址传递到另一个函数中为了使函数中改变了的变量值能被main函数所用,应用指针变量作为函数参数,不能采取把要改变的值的变量作为函数参数的办法。通过函数调用得到n个要改变的值,可以:①在主调函数中设n个变量,用n个指针变量指向他们。②然后将指针变量作实参,将n个变量的地址传递给所调用函数的形参。③通过形参指针变量,改变该n个变量的值。④主调函数就可以使用这些改变了的变量。例:swap(int*p1,int*p2){inttemp;tmep=*p1;*p1=*p2;*p2=temp;}main(){inta,b;int*pt1,*pt2;scanf(“%d,%d”,&a,&b);pt1=&a;pt2=&b;swap(pt1,pt2);printf(“%d,%d”,a,b)}I5,9;O9,5;说明:swap是自定义的函数,起交换作用,参数p1,p2是指针运行①main,输入a,b(5,9)②将a,b地址给pt1,pt2,使其指向a,b;③执行交换函数。 Pt1,pt2是指针变量,函数调用时,将实参变量的值给形参变量。采用的是值传递的方式,结合后p1的值为&a,p2的值为&b此时p1,pt1都指向a④输出a,b的值。(9,5)已交换了的。考虑①temp定义为int*temp;②或交换函数swap(),不用指针形式使用的话,值传递给形参,即执行后形参改变了,但实参没有改变(即这种方式是单向传递,或值传递方式)形参的改变无法传给实参。10.3数组的指针和指向数组的指针变量一个变量有地址,一个数组包含若干个元素,每个数组元素在内存中占用存储单元,对应着相应的地址,指针变量既然可以指向变量当然也可以指向数组和数组元素,(把数组的起始地址或某一元素的地址放到一个指针变量中)所谓数组的指针就是指数组的起始地址。指针变量既然可以指向变量,当然也可以指向数组和数组元素。数组的指针:指数组的起始地址,数组元素数组元素的指针是数组元素的地址。引用数组元素可以用下标法,也可用指针法,即通过指向数组元素的指针找到所需的元素,使用指针法能使目标程序质量高(占内存少,运行速度快)10.3.1指向数组元素的指针定义一个指向数组元素的指针,与指向变量的指针变量相同。 Inta[10];Int*p;P=&a[0];C语言规定数组名代表数组的首地址,也就是第0号元素的地址。等价于p=a;注意:类型要一致,如果数组是int型,则指针变量也应指向int型p=a;a不代表整个数组,它的作用是把a数组的首地址赋级指针变量p,而不是把数组a的各元素的值赋给p赋初值int*p=&a[0];int*p=a;10.3.2通过指针引用数组元素按C规定,如果指针变量p已指向数组中的一个元素,则p+1指向同一个数组中的下一个元素,(不是让p的值简单地加1)p+1所代表的地址实际上是p+1*dp+1*d一个数组元素所占字节数 int2;float4;char1;假设p为指针变量,并已给定一个地址,使之指向某一个数组元素。*p=1;表示对p当前所指的数组元素赋于一个值(值为1)p=&a;①a代表数组的首地址,a+I也是地址,计算方法也是p+1*d例:a+9即&a[9],指向a[9];②*(p+5)或*(a+5)就是a[5];即*(p+5)=*(a+5)=a[5];实际上对数组元素a[I]就是处理成*(a+I),即按首地址加上相对位移量得到要找的元素的地址,然后找出该单元中的内容。例:数组a首地址1000,整型a[3]的地址1000+3*2=1006a[3]=1006a[5]的地址1006+(5-3)*2=1010从1006地址所标志的整型单元取出元素的值,即a[3]的值。[]变址运算符③引用数组的指针变量也可以带下标的。P[I]与*(p+I)等价引用一个元素,可以用1)下标法用a[I];2)指针法如*(a+I)或*(p+I)a数组名,p是指向数组的指针变量,初值p=a;如果p=&a[0];则①p+i和a+i就是a[I]的地址指向数组中第I个元素,②*(p+i)或*a+i)是p+i或a+i所指向的数组元素。③[]是变址运算符即将a[i]按a+i计算地址,然后找出此地址单元的值。④指向数组元素的指针变量也可以带下标。例:p[i]*(p+i)使用指针变量注意的问题①指针变量可以实现使本身的值改变p++自加②指针变量的当前值例:p=ain(p++)重新定位out(p++)③用指针可指向当前的数组元素,实际上p指针变量可指向数组以后的存储单元。定义了a[10],引用最后指针所指向a[10],得不出想要的结果。④注意指针变量的运算有(p=a)1)p++使p指向下一个元素a[1],执行*p,则取出a[1]的值。 2)*p++=*(p++),先得到p指向变量的值(*p),再把p+1给p(p增1)3)*(p++)先取出值,再加1,若p=a;则输出a[0];4)*(++p)先加1,再取出值,若p=a;则输出a[1];5)(*p)++p指向元素的值加1,即a[0]++,a[0]=a[0]+16)如果p当前指向a数组中第I个元素,则A*(p--)=a[I--]先对p进行*运算,再使p自减。B*(++p)=a[++I]先使p自加,再作*运算C*(--p)=a[--I]先使p自减,再作*运算例:输出数组假设整型数组a[10],已经初始化了,输出方法1)下标法printf(“%d”,a[I]);2)用指针变量指向数组元素for(p=a;pmax)max=*p;elseif(*px[k])k=j;if(x[j]>x[k])k=j;if(k!=I)if(k!=I){t=x[I];x[I]=x[k];x[k]=t;}{t=*(x+I);*(x+I)=*(x+k);*(x+k)=t}}}}}10.3.4指向多维数组的指针和指针变量指针可指向一维,也可以指向多维,在概念和使用上,多维数组指针要复杂一些。1、多维数组的地址性质从二维数组角度来看,a代表整个二维数组的首地址,即第0行的首地址,那么,a+I代表第I行的首地址。如果a的首地址为2000,则 a+1的首地址2000+2*30=2060,因此a=1是a[1]的地址。A[0],a[1],a[2]既然是一维数组名,而C又规定了数组名代表数组的首地址。因此,a[0]代表a[0][0]的地址。&a[0][0]a[1]代表a[1][0]的地址。&a[1][0]考虑第0行第1列元素的地址表示。用a[0]+1,此时1代表2个字节。设a[0]的地址值是2000,a[0]+1则是2002,不是2060.。前面已知,a[0]与*(a+0)等价。A[I]=*(a+I).因此,a[0]+1与*(a+0)+1等价。&a[0][1]。a[1]+2与*(a+1)+2等价。&a[1][2]。不能写成把*(a+1)+2写成*(a+1+2),变成*(a+3)=a[3].进一步分析,欲得到一个a[0][1]的值,用地址法怎么表示。既然a[0][1]和*(a+0)+1是a[0][1]的地址。那么*(a[0]+1)就是a[0][1]的值。同理*(*(a+0)+1)或*(*a+1)也是a[0][1]的值。*(*(a+i)+j)或*(a[I]+j)也是a[i][j]的值。这说明,只要记住*(a+I)和a[I]是等价的。二维数组中,a[I][j],a+1是地址(代表首地址),*(a+1)=a[1]是一维数组名,是一个地址。二维数组名a是指向行的,因此,a+1中1代表一行中全部元素所占字节数。一维数组名是指向列元素的,a[0]+1中的1代表一个元素所占字节数。在行指针前面加一个*,就转换成列指针了。在列指针前面加一个&,就成为行指针了。A[0]0行0列的列指针,加&a[0],由于a[0]与*(a+0)等价,因此&a[0]与&*a等价,也就是与a等价,指向0行。不要把&a[I]简单地理解为a[I]单元的物理地址,因为并不存在a[I]这样一个变量,它只是一种地址的计算方法,能得到第I行的首地址。&a[I]和a[I]的值是一样的,但含义不同。&a[I]或a+I指向行a[I]或*(a+I)指向列。当下标j=0,&a[I]和a[I](a[I]+j)的值相等,即有相同的地址。*(a+I)只是a[I]的另一种表示形式,不能简单地认为是a+I所指单元中的内容。对一维数组a+I所指是一个数组元素的存储单元,有具体值。对二维数组a+I所指是行,而不是具体的存储单元。二维数组中,a+I=a[I]=*(a+I)=&a[I]=&a[I][0]它们的地址值是相等的。例:二维a[4][10]intclass[4][30]={{},{},{},{}};class是数组名,4行30列,每一列是一维数组,包含30个元素。 2、指向多维数组的指针变量了解上面的概念后,可用指针变量指向多维数组及其元素。①指向数组元素的指针变量例:用指针输出数组元素main(){inta[3][4]={};int*p;for(p=a;p*,就变成声明函数了。(这个函数返回值是指向整型变量的指针)p=max将函数max的入口地址赋给指针变量p;这里函数名代表函数的入口地址,类似数组。这时p就是指向函数的max的指针变量,也就是说p和max都指向函数的开头。 调用*p就是调用函数max;p是指向入口,不能是指向某一条指令。不能用*(p+1)表示下一条指令。C=(*p)(a,b)函数调用,p=max;C=max(a,b);这就是用指针形式来实现函数的调用。说明:①指向函数的指针变量的一般形式定义为:数据类型(*指针变量名)();int(*p)();②函数调用可以通过函数名调用,也可以通过函数指针调用用指向函数的指针变量调用③(*p)()表示定义一个指向函数的指针变量。不是固定的指向哪一个函数,而表示定义了这样一个指针变量,用来存放函数的入口地址。程序中指导哪个函数的地址给它,它就指向哪一个函数。在同一个程序中,一个指针变量可先后指向不同的函数。④在给函数指针变量赋值时,只需给出函数名而不必给出参数p=max;只给地址,不⑤用函数指针变量调用函数时,只需将(*p)代替函数名即可⑥对指向函数的指针变量,像p+n,p++等运算是无意义的。10.5.2用指向函数的指针变量作函数参数函数指针变量常用的用途之一是把指针作为参数传递到其他函数。指向函数的指针也可作为参数,以便实现函数地址的传递,也就是说将函数名传递给形参。原理:有一个函数(sub)它有两个形参(a,b)定义a和b为指向函数的指针变量,在调用sub时,实参用两个函数名f1和f2给形参传递函数地址,这样在函数sub中就可以调用f1,f2函数了。例:sub(int(*x1)(int),int(*x2)(int,int)){inta,b,I=1,j=2;a=(*x1)(i);//调用b=(*x2)(I,j);定义x1,x2为函数指针变量,x1指向的函数有一个参数,x2有2个。I,j是f1,f2所要求的参数。形参:x2,x1不调用时并给内存单元,(没有分配)也不指向任何函数。调用时把实参f1,f2的入口地址传给形参x1,x2,使x1,x2指向函数f1,f2.这是时就可以调用函数了。此时(*x1)(i)相当于f1(i)(*x2)(I,j)相当于f2(I,j)主调函数调用不同函数,比较方便,主函数不要修改,直接改变被调用的参数。10.6返回指针值的函数函数也可以带回指针型的数据,即地址,可以返回整型,字符型,实型。 其一般形式为:类型名*函数名(参数表)int*a(intx,inty)漏写括号的那种。例1:int*fun(intx,inty)fun是函数名,调用它后能得到一个指向整型数据的指针(地址)。A先与()结合,是函数形式,再与*结合,指针型函数。Int表示返回的指针指向整型变量。例:floatsearch(float(*p)[4],intn){float*pt;形参,指向包含4个元素的一维数组的指针变量pt=*(p+n);returnpt;}p+n指向数组,第n行。*(P+n)指向第n行第0列元素,行控制转化为列控制了。Pt指向实型变量(不是指向一维数组)。Main调用,search,将score的首地址给p,m是要找的序号,调用后,得到一个地址给p,(指向一个学生的第0门课程。)主函数中,*(p+I)表示成绩。查找不及格floatsearch(float(*p)[4]){intI;float*pt;pt=*(p+1);for(I=0;I<4;I++)if(*(*p+I)<60){pt=*p;break;}returnpt;}p是指针变量,指向一维数组,pt为指向实型变量的指针。从实参传给形参p的是score+I,它是score第I行的首地址,search中,pt=*(p+1),把pt指向本行末。区分有无不及格有:pt指向本行第0列元素无:pt指向本行末(即下一行第0列元素)。将pt返回main函数。在main中,把pt(返回值)给p,判断p是否等于*(score+I),等,表示有不及格,则输出。若无不及格,p的值是*(score+I+1),下一行的开头。Main(){float*search(float(*pointer)[4]);floatp; intI,j;for(I=0;I=3;I++){p=search(score+I);if(p==*(score+I)){printf(“No.%dscore:”,I);for(j=0;j<4;j++)printf(“%5.2f”,*(p+j));printf(“ ”);}}}float*search(float(*pointer)[4]);{intI;float*pt;pt=*(pointer+1);for(I=0;I<4;I++)if(*(*pointer+I)<60){pt=*pointer;break;}returnpt;}例:process调用,实现,max,min,add;main(){intmax(int,int);调用process函数,除了将a,b作为实参给x,y,intmin(int,int);还将函数的入口地址传递给funintadd(int,int);inta=10,b=20;从调用中可以看到,process函数一点也没有动,process(a,b,max);只是改变调用参数,增加了函数使用的灵活性process(a,b,min);.可以编写一个通用函数来实现各种专用的功能process(a,b,add);}process(intx,inty,(*fun)(int,int))注意:{intresult;作为实参的函数,在主调函数中用result=(*fun)(x,y);函数原型声明printf(“%d ”,result);(因为后面不加括号和参数,系统无法}判断是函数还是变量名)max(intx,inty)对于函数调用的话可以不加声明,后面{加括号和形参,事先声明,按照函数处理。return((x>y)?x:y);}min(intx,inty) {return((x*name[j])k=j;{k=I;这样只比较他们指向字符串中的第一个for(j=I+1;j0)字符串比较k=j;if(k!=I)k串最小。 {temp=name[I];name[I]=name[k];name[k]=temp;}}}*(name+I++)表示先求*(name+I)的值,即name[I]然后使I++,输出时,按字符串形式输出p地址开始的字符串。例:display_arr(int*q[]);将一个指针数组传递给一个函数,可以采用与其他{intI;类型的数组同样的方法,即可用不带下标的指针for(I=0;I<10;I++)数组名,直接访问函数。printf(“%d”,*q[I]);接受x数组。}q是指向整型指针数组,必须说明参数q是作为一个整型指针的数组。指针数组常用于指向出错信息的指针。例:error(intnum){staticchar*err[]={“can’topenfile ”;“readerror ”;“writeerror ”}printf(“%s”,err[num]);打印出传递给函数的出错代号的下标}所指向的出错信息后面讲到的argv(命令行参数,在main中),就是一个字符型指针数组。10.7.2指向指针的指针即:指向指针数据的指针变量。例:name指针数组,每一个元素是一个指针型数据,其值为地址,它本身的第一个元素都有相应的地址。Name代表指针的首地址。Name+I是name[I]的地址。就是指向指针型数据的指针可以设置一个指针变量p,它指向指针数组的元素。即为指向指针型的指针变量。定义:char**p;右结合性,*(*p),*p是指针变量,*在*p前加,表示p是指向一个字符指针变量的,*p就是p所指向的另一个指针变量。p=name+2;printf(“%o”,*p)地址 printf(“%s”,*p)字符串值指针数组是一个指向指针的指针,指针数组的概念比较直观,因为下标使得它的含义十分明确。定义一个指向指针数据的指针变量char**p;例:一个指针型指针是一种多重间接取数的形式,或者可以看作是一个指针链,区别:单重多重间接取值一般的指针的值是某个变量的地址,地址的内容是变量的值。在指我针型指针中,第1个指针的值是第2个指针的地址,第2个指针是这个变量的地址,而这个地址的内容是这个变量的值。多重间址根据需要还可以进一步延伸,但很少有必要使用比指针型指针更多重数的情况,理论上是可以延伸到更多的重,但过多的话会给计算带来困难,概念上容易错误,也难以理解,一般很少有超过二级的。为了访问由指针型指针所指向的指针中地址的变量内容,需要二次操作。例:#includemain(){intx,*p,**q;p指向整型的指针x=10;q指向整型的指针型指针p=&x;q=&p;printf(“%d”,**q);结果为10例:main(){char*name[]={““};p指向指针的指针变量char**p;第一次循环:p=name+I;使p指向name[0],intI;*p是name[0]的值,即第1个字符串的起始地址。for(I=0;I<5;I++){p=name+I;printf(“%s ”,*p);}}指针数组也可指向整型或实型数据例:inta[5]={1,3,4,5,6}; int*num[5];int**p;for(I=0;I<5;I++)num[I]=&a[I];求a[2]中的数据5,使p=num+2;输出**p;注意:*p是p间接指向的对象的地址num[2];**p是p间接指向的对象的值,即*num[2],即510.7.3指针数组作main函数的形参指针数组的一个重要应用是作为main函数的形参,一般main(),括号里没有参数,也有有参数的形式:main(argc,argv)main是由系统调用的。实参是和命令一起给出的,也就是在一个命令行中包括命令名和需要传给main函数的参数。命令行的一般形式为:命令行参数1参数2参数3……参数n命令名和各参数之间用空格分隔,参数1是main所在的文件名。main(argc,argv)在运行程序时,有进需要将必要的参数传给主函数,例,DOS命令(copy,del),Del文件名这个文件名就是要向主函数传递的命令行参数。Main的函数原型Main(intargc,char*argv[])Argc,argv是用来接收命令行参数的,它们是只有main()才能拥有的参数。Argc保存命令行的参数个数,是个整型量,至少是1,因为至少程序名就是第一个参数。Argv指向字符指针数组的指针,这个数组的每个元素都指向命令行实参。所有命令行实参都是字符串,任何数字都必须要由程序转变为适当的格式。例:#include保存为name,编译main(intargc,char*argv[])OSSHELL命令,执行{if(argc!=2)C>namexgr{printf(“youforgottotypeyourname ”);显示的是exit(0);helloxgr}printf(“hello%s”,argv[1]);}命令行实参必须由空格或制表格分隔,逗号,分号不能被认为分隔符。注意:说明argv char*argv[]可变长度这样可以由argv[]引导访问各个实参,例,argv[0]指向第一个字符串,通常是程序名,argv[1]是第1个实参。如果运行程序时输入的命令不正确,则程序通过命令行参数发出适当的说明。若要访问字符串中命令中的单个字符,就要为argv增加第2个下标。例:显示所有的实参,一次显示一个字符#includemain(intargc,char*argv[]){intI,j,t;for(t=0;t0)Printf(“%s%c”,*++argv,(argc>1)?’‘:’ ’);}main函数中的形参不一定用argc,argv,可以是任意的,这样只不过是人们的习惯。10.8有关指针的数据类型和指针运算的小结。前面已经用了有关指针的数据类型和指针的运算,有一个系统和完整的概念,现作一个小结。10.8.1有关指针的数据类型的小结表10-210.8.2指针运算小结①指针变量加(减)一个整数 p++p+=I地址+内存单元所占字节数②指针变量赋值将一个变量地址赋给一个指针变量不能p=100;p=&a;p=array;p=&arr[I];p=max;p1=p2;③指针变量可以有空值,即不指向任何变量p=NULL是整数0,它使p的存储单元所有二进制为0,即p指向地址为0的单元。(先定义#defineNULL0)p=NULL是有值的,不等于无值,无法预料的值,一般要初始化与NULL比较(if(p==NULL)④两个指针变量可以相减例:p1=&a[1];p2=&a[4]p2-p1=4-1=3⑤两个指针变量比较指针变量指向同一个数组的元素则可比较,指向前面的元素的指针变量小于指向后面元素的指针变量。P1main(){intx=10,*p;p=x;指针的内容是地址,不是具体的值。printf(“%d”,*p);}③未恢复到原来的地址p=a;形式即指针的越界特别注意指针的偏移问题。为了使函数中改变了的值能被main所引用,不能采用把要改变的值的变量作为参数的方法,而应用指针变量作为函数参数,在函数执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值的变化保留了下来,实现:通过函数调用使变量的值发生了变化,在主调函数中使用改变了的值。C语言中实参变量和形参变量之间的数据传递是单向的值传递方式,指针变量作函数参数也要遵循这一规则。调用函数不可能改变实参指针变量的值,但可以改变实参指针变量所指变量的值。函数调用可以(只可以)得到一个返回值,而运用指针变量作参数,可以得到多个变化了的值,不用指针难以实现这一点。#includeexchange(int*q1,int*q2,int*q3){if(*q1<*q2)swap(q1,q2);if(*q2<*q3)swap(q2,q3);if(*q3<*q1)swap(q3,q1);}main(){inta,b,c,*p1,*p2,*p3;scanfp1=&a;p2=&b;p3=&c;exchange(p1,p2,p3);printf(); }10.8.5指针初始化一个指针被说明后,在没有被赋值以前,它是不确定的,没有赋值就使用的话,可能破坏程序,甚至崩溃系统。习惯上,人们将不指向任何地方的指针赋零,表示对它什么也不指,这样也不能保证不会出问题,也可能有破坏作用。由于零指针被认为是未被使用过的,可以用来做很多程序,这要比其他方法更有效,方便,例:可以用零指针来标记指针数组的末端。当访问到值为零时,表示到达最后一个元素上。例:查找姓名search(char*p[],char*name){registerintt;for(t=0;p[t];++t)if(!strcmp(p[t],name)returnt;return–1;没有找到。}#includechar*p=”string”main(){registerintt;printf(p);for(t=strlen(p)-1;t>-1;t--)printf(“%c”,p[t]);}在函数中,for直到发现一个匹配的或零指针为止,由于数组的末尾为零,汉执行到这个条件时便结束。在C语言中,常要将字符串初始化,字符串说明格式:char*p=”string”;这里p不是数组,因为TC遇到此种情况时,自动地对字符进行初始化,所有C编译程序在编译过程中将建立一个字符串表,它将程序中所用到的字符串的内容保存起来。这里将string的地址给p.例:第11章结构体与共用体将不同类型的数据组合成一个有机的整体,以便于引用,这些组合在一个整体中的数据是互相联系的,这样的一种数据结构为结构体相当于其它语言中的记录例:structstudent{intnum;charname[]; }声明一个结构体类型的一般形式:struct结构体名{成员表列}结构体名:用作结构体类型的标识,又称结构体标记,各成员对应类型声明:类型名成员员成员表列:域表,每一个成员也称结构体中的一个域成员命名规则与变量名命名相同。11.2定义结构体类型变量的方法前面只是定义了一个结构体类型,相当于一个模型,但其中并无数据,也不分配内存单元,要使用结构体,应当定义结构体类型的变量,并存放具体的数据1、先声明结构体类型,再定义变量名若前已定义了一个结构体类型,可以用它来定义变量,例:structstudentstu1,stu2;定义了结构体变量后,系统会为其分配内存单元。结构体不仅要求指定变量为结构体类型,而且要求指定为某一特定的结构体类型,如果程序规模大,往往将结构体类型的声明集中放到一个文件中,(*.h),引用时用include。2、在声明类型的同时定义变量一般形式:struct结构体名{成员表列;}变量名表列;例:3、直接定义结构体类型变量一般形式:struct{成员表列;}变量名表列;例:说明:①类型与变量是不同的概念只能对变量赋值,存取或运算,不能对一个类型赋值,存取或运算。②对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量③成员也可以是一个结构体变量。Structperson{structdate;} ④成员名可以程序中的变量名相同,二者不代表同一对象。11.3结构体变量的引用引用规则①不能将一个结构体变量作为一个整体进行输入和输出,只能逐个成员。引用结构体变量中的成员的方式为:结构体变量名.成员名。是成员(分量)运算符,优先级最高。②成员中有结构体类型,则使用多级成员运算符例:person.birthday.year,只能对最低的成员进行赋值或存取以及运算。③对结构体变量的成员可以像普通变量一样进行种运算(根据其类型)person.age++;④可以引用结构体变量成员的地址,也可以引用结构体变量的地址scanf(“%d”,&p.num);printf(“%d”,&p);结构体变量的地址主要用于作函数参数,传递结构体的地址。11.4结构体变量的初始化对结构体变量可以在定义时指定初始值。例:直接赋值方式p={109,”dyd”,’m’}structstu{}11.5结构体数组每个元素都是结构体类型的数据与其它的数组类似11.5.1定义结构体数组和定义结构体变量的方法相仿,只需说明其为数组即可。Struct{}class[4];11.5.2结构体数组的初始化与数组类似结构体数组初始化的一般形式是在定义数组的后面加上={初值表列}11.5.3应用举例例1、11.6指向结构体类型的指针一个结构体变量的指针就是该变量所占据的内存段的起始地址,可以设一个指针变量,用来指向一个结构体变量,此时指针变量的值就是结构体就是变量的起始地址,指针变量也可以是指向结构体数组中的元素。 11.6.1指向结构体变量的指针。例1:在C语言中,为了方便和直观,可以把(*p).num用p?num代替。三种形式:①结构体变量名。成员名②(*p)。成员名③p?成员名?指向运算符p?n得到指向结构体变量中的成员n的值p?n++得到p指向结构体变量中成员n的值,用完该值后使n+1++p?n得到p指向结构体变量中成员n的值,使之先加111.6.2指向结构体数组的指针例:可以使用指向数组或数组元素的指针和指针变量,同样,对结构体数组及其元素也可以用指针或指针变量来指向。11.6.3用结构体变量和指向结构体作函数参数将一个结构体就是的值传递给另一个函数①用结构体变量的成员作参数例:值传递方式,类型保持一致②用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址给形参。例1、例2、③用结构体变量作实参值传递,形参与实参必须是同类型结构体变量。调用时形参也占内存。11.8共用体11.8.1共用体的概念几种不同类型的变量存放到同一段内存单元中,使用覆盖技术,几个变量互相覆盖,这种使几个不同的变量共占同一段内存的结构叫共用体定义一般形式:union[共用体](这个可省){成员表列;}变量表列;例:11.8.2共用体变量的引用方式只能引用共用体变量中的成员例:不能只引用共用体变量11.8.3共用体类型数据的特点使用共用体类型数据时应注意以下一些特点①同一个内存可以用来存放几种不同类型的成员,但在每一瞬时,只能存放其中的一种。②共用体变量中起作用的成员是最后一次存放的成员。 ③不能用体变量的地址和他的各成员的地址都是同一地址。④不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对他初始化。⑤不能把共用体变量名作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针。⑥共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。11.9枚举类型枚举类型是ANSIC新标准增加的,如果一个变量只有几种可能的值,可以定义为枚举类型。声明用enum开头,例颜色,月份。Enumweekday{1,2,3,4,5,6,7}也可以直接定义枚举变量。Enum{1,2,3,4,5,6,7}例:说明①对枚举类型按常量处理,故称枚举常量例:不能赋值RED=0;②枚举元素作为常量,它们是有值的。例:按定义时的顺序使它的值为0,1,2,3,4③枚举值可以用来做判断比较例:④一个整数不能直接赋给一个枚举变量。例:要进行强制类型转换11.10用typedef定义类型可以用typedef声明新的类型名来代替已有的类型名typedefintinteger可以声明结构体类型例:归纳:声明一个新的类型名的方法①先按定义变量的方法写出定义体intI;②将变量名换成新类型名I?count③在最前面加typedeftypedefintcount;④然后用新的类型名去定义变量countn例:习惯上常把用typedef声明的类型名用大写表示,以便以系统提供的类型标识符相区别。说明:①用typedef可以声明各种类型名,但不以定义变量。 例:typedefintarr[10];arra,b,c,d;②用typedef只是对已经存在的类型增加一个类型名,而没有创造新类型。无非是另起一个名称而已。例:③typedef与#define有相似之处,例:typedef是在编译时处理的,#define预编译时处理的,④当不同源文件用到同一类型数据时,常用typedef声明一些数据类型,把它们单独放一到一个文件中,然后在需要用到他们的文件用#include命令包含进来。⑤使用typedef有利于程序的通用与移埴。

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
关闭