零点起飞学LinuxC之C语言进阶.pptx
《零点起飞学LinuxC之C语言进阶.pptx》由会员分享,可在线阅读,更多相关《零点起飞学LinuxC之C语言进阶.pptx(66页珍藏版)》请在三一办公上搜索。
1、第3章 C语言进阶,在前面的章节中我们已经学习了C语言的基础知识。本章中,我们要学习的是C语言的进阶部分,会学习一些高级的特性,主要包括指针、函数、结构体、共用体以及枚举。这些都是C语言学习过程中的难点。我们将对这部分内容进行详细讲解。通过本章的学习,读者可以基本掌握指针、函数、结构体等的定义和使用方法,进而设计编写相关的应用程序。,3.1 指针,指针是C语言的一大重要特点,通过指针可以表示各种数据结构,方便地引用数组和字符串,像汇编语言一样处理内存地址。这也就造就了C语言有很高的执行效率,使得注重效率的程序员特别钟情于C语言,运用指针编程也是语言最主要的风格之一。,3.1.1 指针的概念,指
2、针是C语言的重要特点,语言中,允许使用一个变量来存放指针,这种变量称为指针变量。指针是一个地址,它不仅可以是变量的地址,也可以是其它数据结构的地址,如数组或函数的首地址。这样我们就可以通过访问指针变量,取得数组或函数的首地址,进而找到该数组或函数。这样一来,凡是出现数组或函数的地方都可以用指针变量来表示,只要给指针变量赋予数组或函数的首地址即可。,1指针变量的定义,指针变量的定义方式同普通变量的定义方式类似,如下所示:数据类型符*指针变量名;【实例3-1】下面定义两个指针变量,分别用来保存指向整型变量和浮点型变量的指针。int*p1;/*定义了指针变量p1,用来保存指向int型变量的指针*/d
3、ouble*p2;/*定义了指针变量p2,用来保存double型变量的指针*/对于上面定义的指针变量p1,它的类型为int*,即指向整型变量的指针;该指针所指向的类型为int型;由于指针尚未初始化,所以它的值暂时无法确定;在32位计算机里,该指针占据4个字节的长度。一次定义多个指针变量时,每个指针变量前都要有*运算符。【实例3-2】下面一次定义两个指针变量。int*p1,*p2;如果某个变量前没有*运算符,则定义的是普通变量。【实例3-3】下面定义一个指针变量和一个整型变量。int*p1,p2;上面定义了一个指针变量p1和一个整型变量p2。,2&运算符和*运算符,&运算符用来对一个变量进行操作
4、,它会取得该变量所在的内存地址;*运算符用来对一个指针进行操作,它会取得该指针指向的内存中的内容。【实例3-4】下面给出一段程序,来说明地址运算符和指针运算符的使用方法。example4.c程序的运行结果为:m=1,*pm=1m=2,*pm=2,3指针的运算,指针中保存的是内存的地址,它是一个无符号的整数。因此,我们可以对指针做一些数学运算。C语言允许对指针进行加法和减法运算。虽然对指针进行乘法、除法等运算看起来是合理的但是这是C语言所不允许的。同时,C语言不允许两个指针进行加法运算。指针的运算会根据数据类型的不同而不同。假设p是一个整型指针,当前值为BFD5CAC0,那么p+运算后,内存地址
5、值要加4个字节,即p的指变为了BFD5CAC4,p每递增一次,就将指向下一个整数,递减也是一样。,3指针的运算,【实例3-5】下面首先定义指针变量并指向数组元素,然后对指针进行运算。int a5=1,2,3,4,5;int*p1=07,4void指针类型,C语言中可以将一个指针定义为void型。该类型的指针可以转换为任意类型的指针,例如:void*p;上面的定义中,p仍然是一个指针变量,有自己的内存空间,占用4个字节,但是没有指定它指向哪种类型的变量。在这种情况下,不能对指针变量进行运算,否则会导致编译错误。【实例3-7】下面对void型指针变量进行运算。01#include 02#inclu
6、de 03int main()0405 void*p;/*定义void型指针变量*/06 p+;07 return 0;08变量p为void型指针,无法确定递增的字节数。此时可以对其进行强制类型转换,使其指向某种类型的变量。,5指针的类型转换,在通常情况下,正确的赋值运算左右两边的变量类型是一致的,如下所示:char c=A;char*p=这里将前面定义的指向字符型的指针pc,通过强制类型转换赋给了指向整型的指针变量pi。,6指向指针的指针,指向指针的指针即为一个指针指向的内容仍然为一个指针。无论是指针变量还是指向指针的指针变量,他们在内存中和普通的变量是一样的,都占有一定的存储空间,也就是说
7、有自己的内存地址。关于指向指针的指针的内存映射参照图。图中,整型变量i的地址是,6指向指针的指针,【实例3-9】下面定义一个指向指针的指针变量。int*pp;pp为指向指针的指针变量,即二级指针变量,它的最终目标变量为整型变量。使用二级指针访问数据,相当于汇编语言或机器语言的双重间接寻址。【实例3-10】下面给出几条赋值语句,然后逐一对其进行分析。int x,y;int*p;int*pp;p=,3.1.2 指针与数组的互操作,相对数组来说,数组名中存放的是数组数据在内存中存放区域的首地址。而指针变量是用于存放地址。因此指针变量就可以用来存放数组,同样的使用指针也可以引用数组或数组元素。假设我们
8、定义一个数组和一个指针变量,将数组的首地址传递给指针变量,即用一个指针变量指向了这个数组。,3.1.2 指针与数组的互操作,【实例3-11】下面定义一个数组和一个指针变量,然后使用指针变量来引用数组元素。int a10;int*p;p=a;/*将数组的首地址传递给指针变量*/p=/*将数组元素a0的地址传递给指针变量*/a是数组的首地址,&a0是数组元素a0的地址,由于a0的地址就是数组的首地址,所以两条赋值语句是等效的,其作用是使指针变量p指向数组a。这样,对数组元素的引用既可以使用前面介绍过的下标法,也可以使用指针的表示方法,如:p+n与a+n表示数组元素an的地址,即&an;*(p+n)
9、和*(a+n)表示数组的元素an。,3.1.2 指针与数组的互操作,【实例3-12】下面给出一个应用实例,使用选择排序算法对一个整型数组进行递增排序。example12.c上面的程序,输出结果为:Please input 10 integers:5 6 1 7 3 8 2 9 4 10The result is:1 2 3 4 5 6 7 8 9 10可以看到,输入的10个整数从小到大进行了排序。【实例3-13】下面编写一个程序,通过指向指针的指针变量来访问一个二维数组元素,并输出所有元素的最大值及其位置。example13.c,3.1.2 指针与数组的互操作,编译运行上面的程序,输出结果为:
10、Row 1:2 1 3 2Row 2:6 2 9 5Row 3:1 2 6 8Max:9(2,3)可以看到,数组元素的最大值为9,位于第2行第3列。,3.1.3 指针数组,指针数组同普通数组并没有太大的差别。指针数组用来保存指针即数组的元素均为指针,如下所示:char*week=Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday;利用指针数组来处理多维数组可以使多维数组降低维数,方便数组元素的操作。,3.1.3 指针数组,【实例3-14】已知一个整型的二维数组,编写一个程序求数组每行的最大数据元素以及整个数组的最大元素。exampl
11、e14.c上面的程序,输出结果为:Line1:3Line2:6Line3:9Max:9从上面的例子我们可以看到,指针与数组相结合,可以使数组元素的引用形式更加多样、操作方法更加灵活。指针也可以指向函数、结构体等,这部分内容将在后面进行介绍。,3.2 函数,C语言有一个很大的改进之处就是使用了函数。函数可以减少程序编写过程中代码的重复编写,提高了代码的重复利用率。要使用函数只需要通过简单的调用即可,这就可以使得程序更加容易阅读。要成为一名优秀的程序员,必须很好地掌握函数的编写和和使用方法。本节就集中讨论与函数有关的内容。,3.2.1 函数的定义与声明,函数在使用之前需要有对应函数的定义,定义个函
12、数的格式为:返回值类型符 函数名(形式参数列表)定义部分;执行语句部分;这里说明如下几点:(1)函数名称是对函数的标识,一个程序中的多个函数不能重名;(2)返回值类型符是对函数返回值的类型说明,函数的返回值由return语句返回。return语句的格式为:return 表达式;或return(表达式);表达式的值为函数的返回值,也可以理解为函数的值。执行完return语句后,不管后面是否还有执行语句,程序都将结束函数并返回。,3.2.1 函数的定义与声明,(3)形式参数类似于函数体部分的变量,但形式参数不能在定义的同时进行初始化。只有函数被调用后,才会传递具体的值给形式参数。形式参数列表的格式
13、为:数据类型符1 形式参数名1,数据类型符2 形式参数名2,.,数据类型符n 形式参数名n(4)花括弧之间是函数体,即函数的实现部分。C语言中的函数体一般分为两个部分:定义部分和执行语句部分,前者主要用于变量等的定义,后者则用来实现函数的功能和逻辑。(5)函数的形式参数和返回值都可以为void,即形式参数或返回值为空。void可以省略不写,但为了程序的可读性和严谨性,最好不要省略,尤其是返回值。,3.2.1 函数的定义与声明,编译程序编译一个C源文件时,采取从前向后的顺序进行。如果函数定义在前,那么编译程序处理完函数定义部分之后,自然就知道了函数接受什么样的参数,返回什么样的值等。这样,编译程
14、序就可以检查后续代码中对函数的调用是否正确。反之,编译程序遇到一个函数的调用,但尚未编译该函数的定义,对该函数一无所知,那么编译器就会报错。这种情况下,可以采用函数的声明,将函数的申明部分放在函数的调用之前。函数声明的格式为:返回值类型符 函数名(形式参数列表);函数声明的目的就是告诉编译器该函数的参数类型、个数、以及返回值等信息。这里需要注意的是函数声明在句尾有一个分号,而且函数声明过程中形式参数可以只写数据类型符,如:int max(int a,int a);可以省略为:int max(int,int);,3.2.2 函数的调用与参数传递,主函数(main())是C语言程序最先开始执行的函
15、数,当主函数中所有语句执行完毕后,整个程序结束。主函数之外的其他函数都是在执行主函数的过程中,通过函数调用得以执行。在一个函数中使用另一个函数的功能就称为调用。被调用函数在执行完成后返回调用处继续执行后面的语句。函数调用的一般格式为:函数名(实际参数列表)在调用一个函数时,必须使用具有实际值的量作为函数的参数,这种参数称为实际参数,简称实参。在函数调用过程中,实际参数表中的参数必须与被调用函数的形式参数表中的参数一一对应,即参数的类型、个数、以及顺序等。实际参数可以是常量、变量或表达式。,3.2.2 函数的调用与参数传递,【实例3-15】下面给出一段程序,来说明函数定义、声明、以及调用的方法。
16、example15.c函数参数传递是调用函数和被调用函数在调用发生时进行通信的方法。基本的参数传递机制有两种:值传递和地址传递。值传递过程中,被调用函数的形式参数作为被调用函数的局部变量来处理,即在堆栈中开辟了内存空间以存放由调用函数传递进来的实际参数的值。函数体中实际操作的是实际参数的一个副本,这样被调用函数中的任何操作都不会影响到实参变量的值。实例3-15中使用的即为值传递。地址传递过程中,被调用函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但此时存放的是由调用函数放进来的实参变量的地址。这样被调用函数对形式参数的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问调用函数中的
17、实参变量。正因为如此,被调用函数对形式参数所做的任何操作都将影响调用函数中的实参变量。严格地讲,C语言中只有值传递,但可以通过指针变相地进行地址传递。,3.2.2 函数的调用与参数传递,【实例3-16】下面编写一个函数,通过指针来进行地址的传递。example16.c上面的程序,输出结果为:i=2j=1上面的程序中,我们通过指针的方式实现了地址传递,但这种地址传递的方式其实还是C语言本身具有的值传递,只不过这里传递的是地址值。,3.2.3 变量的作用域,变量在使用过程中是有确定的作用范围的。变量在程序中的有效范围就称为变量的作用域。作用域是从代码空间的角度定义的。定义的方式不同,作用域也是不相
18、同。C语言中,变量的作用域可分为局部变量和全局变量。下面我们就来学习他们。,1局部变量,顾名思义,局部变量就是存在于局部的变量。这里的局部就是指函数体,局部变量只在函数被调用期间才分配内存单元,调用结束便立即释放。因此,局部变量只存在于函数调用的过程中,函数调用完毕即不复存在。,1局部变量,【实例3-17】下面给出一段程序,来说明局部变量的作用域。int func(int a,int b)/*局部变量包括a、b、i*/int i;/*定义局部变量i*/int main()/*局部变量包括i、j*/int i,j;/*定义局部变量i、j*/函数内部定义的变量,和其他函数内部定义的变量之间是没有关
19、系的,他们都只能被当前函数的语句使用。如上面程序中的整型变量i,虽然在两个函数中都有定义,但他们分配的是不同的内存单元,互不干扰。C语言中,还允许在函数内部的复合语句中定义局部变量,这里不做介绍。,2全局变量,对应局部变量的是全局变量。全局变量定义在所有函数之外。它的作用域是整个源程序,所有的函数均可以访问全局变量。【实例3-18】下面给出一段程序,来说明全局变量的作用域。int x,y;/*定义全局变量x和y*/void func()int main()/*int y;*/*定义局部变量y*/上面的程序中,整型变量x和y都是在函数外部定义的全局变量。函数func和main中都可以直接使用x和
20、y。但这里需要注意的是:在同一个源文件中,允许全局变量和局部变量同名,在局部变量的作用域内,全局变量不起作用。假如上面的main函数中定义了局部变量y,则它将屏蔽外部定义的全局变量y。,2全局变量,全局变量的定义可以放在源文件中的任意位置,如果试图在全局变量定义前使用它,需要对其进行声明。声明全局变量的格式为:extern 数据类型符 全局变量名;使用全局变量可以减少函数调用过程中实际参数和形式参数之间数据传递带来的时间消耗。但同时也带来了一些问题:全局变量破坏了函数的封装性。函数一般是通过形式参数和返回值进行输入输出,函数内部的实现相对独立。但如果在函数中使用了全局变量,那么函数体内的语句就
21、可以绕过函数参数和返回值进行存取操作。这破坏了函数的独立性,使函数对全局变量产生了依赖,同时也降低了函数的可移植性。全局变量使函数代码的可读性降低。由于全局变量被多个函数使用,函数执行过程中全局变量的值随时可能发生变化,这对于程序的调试非常不利。因此,全局变量应根据需要慎重使用,尤其是在多线程编程中,最好不要使用全局变量。,3.2.4 变量的存储类型,变量在内存中的存储类型可以分为静态存储和动态存储。静态存储是指在变量定义时就分配存储单元并且一直保持到整个程序结束。例如全局变量即属于静态存储方式。动态存储方式则是在程序执行过程中动态分配的,即在使用它时候分配,使用完毕立即释放。例如函数的形式参
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 零点 起飞 LinuxC 语言 进阶
链接地址:https://www.31ppt.com/p-6613786.html