零点起飞学LinuxC之C语言进阶.pptx_第1页
零点起飞学LinuxC之C语言进阶.pptx_第2页
零点起飞学LinuxC之C语言进阶.pptx_第3页
零点起飞学LinuxC之C语言进阶.pptx_第4页
零点起飞学LinuxC之C语言进阶.pptx_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

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

文档简介

第3章 C语言进阶,在前面的章节中我们已经学习了C语言的基础知识。本章中,我们要学习的是C语言的进阶部分,会学习一些高级的特性,主要包括指针、函数、结构体、共用体以及枚举。这些都是C语言学习过程中的难点。我们将对这部分内容进行详细讲解。通过本章的学习,读者可以基本掌握指针、函数、结构体等的定义和使用方法,进而设计编写相关的应用程序。,3.1 指针,指针是C语言的一大重要特点,通过指针可以表示各种数据结构,方便地引用数组和字符串,像汇编语言一样处理内存地址。这也就造就了C语言有很高的执行效率,使得注重效率的程序员特别钟情于C语言,运用指针编程也是语言最主要的风格之一。,3.1.1 指针的概念,指针是C语言的重要特点,语言中,允许使用一个变量来存放指针,这种变量称为指针变量。指针是一个地址,它不仅可以是变量的地址,也可以是其它数据结构的地址,如数组或函数的首地址。这样我们就可以通过访问指针变量,取得数组或函数的首地址,进而找到该数组或函数。这样一来,凡是出现数组或函数的地方都可以用指针变量来表示,只要给指针变量赋予数组或函数的首地址即可。,1指针变量的定义,指针变量的定义方式同普通变量的定义方式类似,如下所示: 数据类型符 *指针变量名; 【实例3-1】下面定义两个指针变量,分别用来保存指向整型变量和浮点型变量的指针。 int *p1; /* 定义了指针变量p1,用来保存指向int型变量的指针 */ double *p2; /* 定义了指针变量p2,用来保存double型变量的指针 */ 对于上面定义的指针变量p1,它的类型为int *,即指向整型变量的指针;该指针所指向的类型为int型;由于指针尚未初始化,所以它的值暂时无法确定;在32位计算机里,该指针占据4个字节的长度。 一次定义多个指针变量时,每个指针变量前都要有*运算符。 【实例3-2】下面一次定义两个指针变量。 int *p1, *p2; 如果某个变量前没有*运算符,则定义的是普通变量。 【实例3-3】下面定义一个指针变量和一个整型变量。 int *p1, p2; 上面定义了一个指针变量p1和一个整型变量p2。,2&运算符和*运算符,&运算符用来对一个变量进行操作,它会取得该变量所在的内存地址;*运算符用来对一个指针进行操作,它会取得该指针指向的内存中的内容。 【实例3-4】下面给出一段程序,来说明地址运算符和指针运算符的使用方法。example4.c 程序的运行结果为: m=1,*pm=1 m=2,*pm=2,3指针的运算,指针中保存的是内存的地址,它是一个无符号的整数。因此,我们可以对指针做一些数学运算。C语言允许对指针进行加法和减法运算。虽然对指针进行乘法、除法等运算看起来是合理的但是这是C语言所不允许的。同时,C语言不允许两个指针进行加法运算。指针的运算会根据数据类型的不同而不同。假设p是一个整型指针,当前值为BFD5CAC0,那么p+运算后,内存地址值要加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 #include 03 int main() 04 05 void *p; /* 定义void型指针变量 */ 06 p+; 07 return 0; 08 变量p为void型指针,无法确定递增的字节数。此时可以对其进行强制类型转换,使其指向某种类型的变量。,5指针的类型转换,在通常情况下,正确的赋值运算左右两边的变量类型是一致的,如下所示: char c = A; char *p = 这里将前面定义的指向字符型的指针pc,通过强制类型转换赋给了指向整型的指针变量pi。,6指向指针的指针,指向指针的指针即为一个指针指向的内容仍然为一个指针。无论是指针变量还是指向指针的指针变量,他们在内存中和普通的变量是一样的,都占有一定的存储空间,也就是说有自己的内存地址。关于指向指针的指针的内存映射参照图。 图中,整型变量i的地址是,6指向指针的指针,【实例3-9】下面定义一个指向指针的指针变量。 int *pp; pp为指向指针的指针变量,即二级指针变量,它的最终目标变量为整型变量。使用二级指针访问数据,相当于汇编语言或机器语言的双重间接寻址。 【实例3-10】下面给出几条赋值语句,然后逐一对其进行分析。 int x, y; int *p; int *pp; p = ,3.1.2 指针与数组的互操作,相对数组来说,数组名中存放的是数组数据在内存中存放区域的首地址。而指针变量是用于存放地址。因此指针变量就可以用来存放数组,同样的使用指针也可以引用数组或数组元素。 假设我们定义一个数组和一个指针变量,将数组的首地址传递给指针变量,即用一个指针变量指向了这个数组。,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)和*(a+n)表示数组的元素an。,3.1.2 指针与数组的互操作,【实例3-12】下面给出一个应用实例,使用选择排序算法对一个整型数组进行递增排序。example12.c 上面的程序,输出结果为: Please input 10 integers: 5 6 1 7 3 8 2 9 4 10 The result is: 1 2 3 4 5 6 7 8 9 10 可以看到,输入的10个整数从小到大进行了排序。 【实例3-13】下面编写一个程序,通过指向指针的指针变量来访问一个二维数组元素,并输出所有元素的最大值及其位置。example13.c,3.1.2 指针与数组的互操作,编译运行上面的程序,输出结果为: Row 1: 2 1 3 2 Row 2: 6 2 9 5 Row 3: 1 2 6 8 Max: 9 (2,3) 可以看到,数组元素的最大值为9,位于第2行第3列。,3.1.3 指针数组,指针数组同普通数组并没有太大的差别。指针数组用来保存指针即数组的元素均为指针,如下所示: char *week=“Monday“, “Tuesday“, “Wednesday“, “Thursday“, “Friday“, “Saturday“, “Sunday“; 利用指针数组来处理多维数组可以使多维数组降低维数,方便数组元素的操作。,3.1.3 指针数组,【实例3-14】已知一个整型的二维数组,编写一个程序求数组每行的最大数据元素以及整个数组的最大元素。example14.c 上面的程序,输出结果为: Line1: 3 Line2: 6 Line3: 9 Max: 9 从上面的例子我们可以看到,指针与数组相结合,可以使数组元素的引用形式更加多样、操作方法更加灵活。指针也可以指向函数、结构体等,这部分内容将在后面进行介绍。,3.2 函数,C语言有一个很大的改进之处就是使用了函数。函数可以减少程序编写过程中代码的重复编写,提高了代码的重复利用率。要使用函数只需要通过简单的调用即可,这就可以使得程序更加容易阅读。要成为一名优秀的程序员,必须很好地掌握函数的编写和和使用方法。本节就集中讨论与函数有关的内容。,3.2.1 函数的定义与声明,函数在使用之前需要有对应函数的定义,定义个函数的格式为: 返回值类型符 函数名(形式参数列表) 定义部分; 执行语句部分; 这里说明如下几点: (1)函数名称是对函数的标识,一个程序中的多个函数不能重名; (2)返回值类型符是对函数返回值的类型说明,函数的返回值由return语句返回。 return语句的格式为: return 表达式; 或 return (表达式); 表达式的值为函数的返回值,也可以理解为函数的值。执行完return语句后,不管后面是否还有执行语句,程序都将结束函数并返回。,3.2.1 函数的定义与声明,(3)形式参数类似于函数体部分的变量,但形式参数不能在定义的同时进行初始化。只有函数被调用后,才会传递具体的值给形式参数。形式参数列表的格式为: 数据类型符1 形式参数名1, 数据类型符2 形式参数名2, ., 数据类型符n 形式参数名n (4)花括弧之间是函数体,即函数的实现部分。C语言中的函数体一般分为两个部分:定义部分和执行语句部分,前者主要用于变量等的定义,后者则用来实现函数的功能和逻辑。 (5)函数的形式参数和返回值都可以为void,即形式参数或返回值为空。void可以省略不写,但为了程序的可读性和严谨性,最好不要省略,尤其是返回值。,3.2.1 函数的定义与声明,编译程序编译一个C源文件时,采取从前向后的顺序进行。如果函数定义在前,那么编译程序处理完函数定义部分之后,自然就知道了函数接受什么样的参数,返回什么样的值等。这样,编译程序就可以检查后续代码中对函数的调用是否正确。 反之,编译程序遇到一个函数的调用,但尚未编译该函数的定义,对该函数一无所知,那么编译器就会报错。这种情况下,可以采用函数的声明,将函数的申明部分放在函数的调用之前。函数声明的格式为: 返回值类型符 函数名(形式参数列表); 函数声明的目的就是告诉编译器该函数的参数类型、个数、以及返回值等信息。这里需要注意的是函数声明在句尾有一个分号,而且函数声明过程中形式参数可以只写数据类型符,如: int max(int a, int a); 可以省略为: int max(int, int);,3.2.2 函数的调用与参数传递,主函数(main())是C语言程序最先开始执行的函数,当主函数中所有语句执行完毕后,整个程序结束。主函数之外的其他函数都是在执行主函数的过程中,通过函数调用得以执行。在一个函数中使用另一个函数的功能就称为调用。被调用函数在执行完成后返回调用处继续执行后面的语句。 函数调用的一般格式为: 函数名(实际参数列表) 在调用一个函数时,必须使用具有实际值的量作为函数的参数,这种参数称为实际参数,简称实参。在函数调用过程中,实际参数表中的参数必须与被调用函数的形式参数表中的参数一一对应,即参数的类型、个数、以及顺序等。实际参数可以是常量、变量或表达式。,3.2.2 函数的调用与参数传递,【实例3-15】下面给出一段程序,来说明函数定义、声明、以及调用的方法。example15.c 函数参数传递是调用函数和被调用函数在调用发生时进行通信的方法。基本的参数传递机制有两种:值传递和地址传递。 值传递过程中,被调用函数的形式参数作为被调用函数的局部变量来处理,即在堆栈中开辟了内存空间以存放由调用函数传递进来的实际参数的值。函数体中实际操作的是实际参数的一个副本,这样被调用函数中的任何操作都不会影响到实参变量的值。实例3-15中使用的即为值传递。 地址传递过程中,被调用函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但此时存放的是由调用函数放进来的实参变量的地址。这样被调用函数对形式参数的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问调用函数中的实参变量。正因为如此,被调用函数对形式参数所做的任何操作都将影响调用函数中的实参变量。 严格地讲,C语言中只有值传递,但可以通过指针变相地进行地址传递。,3.2.2 函数的调用与参数传递,【实例3-16】下面编写一个函数,通过指针来进行地址的传递。example16.c 上面的程序,输出结果为: i = 2 j = 1 上面的程序中,我们通过指针的方式实现了地址传递,但这种地址传递的方式其实还是C语言本身具有的值传递,只不过这里传递的是地址值。,3.2.3 变量的作用域,变量在使用过程中是有确定的作用范围的。变量在程序中的有效范围就称为变量的作用域。作用域是从代码空间的角度定义的。定义的方式不同,作用域也是不相同。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 */ 函数内部定义的变量,和其他函数内部定义的变量之间是没有关系的,他们都只能被当前函数的语句使用。如上面程序中的整型变量i,虽然在两个函数中都有定义,但他们分配的是不同的内存单元,互不干扰。 C语言中,还允许在函数内部的复合语句中定义局部变量,这里不做介绍。,2全局变量,对应局部变量的是全局变量。全局变量定义在所有函数之外。它的作用域是整个源程序,所有的函数均可以访问全局变量。 【实例3-18】下面给出一段程序,来说明全局变量的作用域。 int x, y; /* 定义全局变量x和y */ void func() int main() /* int y; */ /* 定义局部变量y */ 上面的程序中,整型变量x和y都是在函数外部定义的全局变量。函数func和main中都可以直接使用x和y。但这里需要注意的是:在同一个源文件中,允许全局变量和局部变量同名,在局部变量的作用域内,全局变量不起作用。假如上面的main函数中定义了局部变量y,则它将屏蔽外部定义的全局变量y。,2全局变量,全局变量的定义可以放在源文件中的任意位置,如果试图在全局变量定义前使用它,需要对其进行声明。声明全局变量的格式为: extern 数据类型符 全局变量名; 使用全局变量可以减少函数调用过程中实际参数和形式参数之间数据传递带来的时间消耗。但同时也带来了一些问题: 全局变量破坏了函数的封装性。函数一般是通过形式参数和返回值进行输入输出,函数内部的实现相对独立。但如果在函数中使用了全局变量,那么函数体内的语句就可以绕过函数参数和返回值进行存取操作。这破坏了函数的独立性,使函数对全局变量产生了依赖,同时也降低了函数的可移植性。 全局变量使函数代码的可读性降低。由于全局变量被多个函数使用,函数执行过程中全局变量的值随时可能发生变化,这对于程序的调试非常不利。 因此,全局变量应根据需要慎重使用,尤其是在多线程编程中,最好不要使用全局变量。,3.2.4 变量的存储类型,变量在内存中的存储类型可以分为静态存储和动态存储。静态存储是指在变量定义时就分配存储单元并且一直保持到整个程序结束。例如全局变量即属于静态存储方式。动态存储方式则是在程序执行过程中动态分配的,即在使用它时候分配,使用完毕立即释放。例如函数的形式参数即属于动态存储方式。 我们把由于变量存储方式不同而产生的特性称为变量的生存期,生存期表示了变量存在的时间。生存期和作用域是从时间和空间两个不同的角度来描述变量的特性,这两者之间既有联系,又有区别。一个变量究竟属于哪一种存储方式,并不能仅从其作用域来判断,还应有明确的存储类型说明。所以,定义一个变量的完整形式应为: 存储类型说明符 数据类型符 变量名; C语言中,存储类型说明符有4种:auto(自动变量)、extern(外部变量)、static(静态变量)和register(寄存器变量)。其中外部变量和静态变量属于静态存储方式,而自动变量和寄存器变量则属于动态存储方式。下面进行详细介绍。,1自动变量,自动变量是语言程序中使用最广泛的一种类型。定义一个自动变量时使用关键字auto,如下所示: auto int i; auto关键字是可以省略的,因此上面的语句可以简写为: int i;,2外部变量,外部变量是在函数外部定义的全局变量,它的作用域是从变量的定义开始,到程序文件结束。若外部变量的定义在后,使用在前,或者引用其他源文件中的外部变量,必须使用extern对其进行外部声明。,3静态变量,静态变量分为静态局部变量和静态全局变量。在局部变量前面加关键字static进行定义或声明,该变量就称为静态局部变量。静态局部变量的特点是它位于程序的静态存储区,在程序的整个运行过程中,它自始至终占用被分配的存储空间。也就是说,静态局部变量在函数调用结束后,它的值仍然存在,并可能会影响函数的下一次调用。 如果希望当前源文件中的全局变量不能被其他源文件使用,可以在全局变量的定义前加上关键字static,这样的全局变量称为静态全局变量。,3静态变量,【实例3-19】下面编写一个程序,比较普通变量和静态变量之间的差异。example19.c 上面程序运行的结果为: Fisrt call func(): m = 1 n = 1 Second call func(): m = 1 n = 2,4寄存器变量,寄存器变量是为了提高访问速度而存放在寄存器中的变量。寄存器变量使用register定义,如下所示: register int i; 只有自动局部变量可以定义为寄存器变量,全局变量和静态变量都不能定义为寄存器变量。另外,CPU中寄存器的容量也是非常有限的,所以不允许定义太多的寄存器变量。 在程序设计过程中,其实没有必要定义寄存器变量。因为一般的编译程序都会进行优化处理,自动识别那些使用频繁的变量,并将其转为寄存器变量。,3.2.5 外部函数和内部函数,当一个程序由多个源文件组成时候,就可以通过将函数定义为外部函数或者内部函数来指定函数可以被使用的范围。,1外部函数,外部函数即为可以在文件之外被使用的函数。外部函数使用extern关键字定义,例如: extern int add(int a,int b) return a+b; 如果在定义函数时省略了关键字extern,则默认为外部函数。,1外部函数,【实例3-20】下面给出一个调用外部函数的实例。 源文件f1.c中的代码为: extern void func(); /* 函数声明 */ int main() func(); return 0; 源文件f2.c中的代码为: extern void func() /* 函数定义 */ printf(“Hello World !n“); 程序执行结果为: Hello World ! 上面的程序中,源文件f1.c中的main函数调用了源文件f2.c中定义的外部函数func。,2内部函数,同外部函数对应的,如果一个函数需要只在文件中可以被调用,那么就可以将其定义为内部函数。内部函数使用static关键字定义。 【实例3-21】下面使用static关键字定义一个内部函数,对两个参数进行求和。 static int add(int a,int b) return a+b; 不同的文件中可以定义相同名称的内部函数,它们之间互不影响。和静态全局变量一样,使用内部函数有利于增强源文件的独立性和可移植性。,3.2.6 函数的递归,要学习函数的递归,栈这个数据结构是我们必须了解的。栈在每个程序运行时都存在,它由系统自动维护。栈有一个特性就是按照“先进后出”的原则来存储数据最先进栈的数据位于栈底,最后进栈的数据位于栈顶,在读取数据时从栈顶开始弹出。 当一个函数调用另一个函数时,系统会首先将调用函数的实参和返回地址压入到栈中,并将栈指针向下移动。调用函数将实参压入栈后,被调用函数就以自变量的形式建立形参,并将这些自变量也压入到栈中,栈指针随之继续向下移动。此外,被调用函数内部的其他自变量也会被压入到栈中。 当被调用函数准备返回时,系统会弹出栈中所有的自变量,此时栈指针将移动到被调用函数刚开始执行时的位置。接下来,被调用函数返回,系统从栈中弹出返回地址和实参,调用函数开始继续执行。当调用函数继续执行时,栈指针回到调用前的位置。 接下来开始讨论函数的递归。所谓递归,就是函数自己调用自己,或在自己调用的下一级函数中调用自己。函数的递归之所以能实现,就是因为函数在每次调用时都在栈中有形参和局部变量的拷贝,他们与函数的其他调用过程无关。,3.2.6 函数的递归,【实例3-22】下面给出一个函数递归的实例。example22.c 上面的程序,输出结果为: 1 2 3 4 5 Done! 采用递归的方法解决实际问题时,必须满足一定的条件: 可以把要解决的问题转化为一个新的问题,而新问题的解决方法与原问题相同,只是所处理的对象有规律地递增或递减; 要有递归结束的条件,即在适当的地方结束递归调用,否则将进入死循环。,3.2.6 函数的递归,【实例3-23】下面使用递归的方法来求n!的值。example23.c 上面的程序,输出结果为: Input n (0) : -5 Error! Input n (0) : 5 5! = 120 函数的递归调用在解决某些问题时可以使程序简洁明了,但由于递归调用过程中要不断进行压栈、出栈等操作,这就增加了很多额外的系统开销,因此一般情况下函数的递归调用都会降低程序的运行效率。,3.2.7 函数指针变量,保存着函数首地址的指针变量,就称为函数指针变量,即指向函数的指针。 函数指针变量的定义格式为: 函数的返回值类型 (*函数指针变量名)(函数的形式参数) 例如: void (*p)(int x); 定义完成后,通过函数指针变量就可以调用它所指向的函数了。 【实例3-24】下面编写一个程序,通过函数指针来调用函数。example24.c 上面的程序,输出结果为: 6 6 在上面的程序中,赋值语句p = ,3.2.7 函数指针变量,使用函数指针类型可以定义相应的函数指针变量。 【实例3-25】下面编写一个程序,将函数指针作为函数的参数来使用。example25.c 上面的程序,输出结果为: 2 + 3 = 5 2 - 3 = -1 可以看到,fun函数通过传入的函数指针来分别调用add和sub两个函数。,3.3 结构体、共用体和枚举,在我们前面学习的数据类型(如字符型、整型数组和指针等)只能描述某一方面的属性。而现实世界中的事物往往具有多方面的属性。因此C语言就提供了用户可以自定义的数据类型。他们分别是结构体、共用体和枚举。下面我们就来详细学习他们。,3.3.1 结构体,结构体就是由基本的数据类型构成的各种变量的组合。结构体中可以使用前面学习的各种数据类型,因此在编程中应用比较广泛。,1结构体类型的定义,结构体在定义时需要为其中的每一个成员定义成员名及成员的数据类型,一般的形式如下: struct 结构体名 数据类型符 成员1; 数据类型符 成员2; 数据类型符 成员n; ; 组成结构体的每个数据项称为结构体的成员,它可以为基本数据类型、数组或指针类型,也可以为结构体。由于不同的成员分别描述事物不同方面的特性,因此成员之间不能重名。 【实例3-26】下面定义一个结构体,用来保存学生的基本信息,包括学号、姓名、性别、年龄、以及家庭住址等。,2结构体变量的定义,01 struct student 02 03 int id; /* 学号 */ 04 char name20; /* 姓名 */ 05 char sex; /* 性别 */ 06 unsigned int age; /* 年龄 */ 07 char address100; /* 家庭住址 */ 08 ;,2结构体变量的定义,结构体变量的定义方式有三种,下面分别进行介绍: (1)先定义结构体,然后像定义基本数据类型变量一样,定义结构体类型的变量,如下所示: struct student a; (2)在定义结构体的同时定义结构体变量,适用于定义局部使用的结构体变量,如下所示: struct student int id; char name20; char sex; unsigned int age; char address100; a;,2结构体变量的定义,(3)直接定义结构体变量,即在定义结构体的同时定义结构体变量,但不给出结构体名,如下所示: struct int id; char name20; char sex; unsigned int age; char address100; a; 注意:结构体变量名与数组名的含义不同,它不是指向结构体的地址,因此结构体变量第一个成员的首地址应该为:&结构变量名。,3结构体变量的初始化,同定义普通变量类似的,在定义一个结构体变量后需要将其初始化,一般的形式如下: struct 结构体名 结构体变量名 = 初始数据表; 初始数据表中的数据项都为常量,数据项之间使用逗号来分隔,它们和结构体变量中的成员应一一对应。 【实例3-27】下面对前面定义的结构体进行初始化。 01 struct student a = 02 1, 03 “Wang Ming“, 04 M, 05 23, 06 “001 Jian Guo Road“ 07 ;,4指向结构体的指针,同指向指针的指针类似,指针同样可以指向一个结构体变量。指向结构体变量的指针称为结构体指针,结构体指针定义的一般形式为: struct 结构体名 *结构体指针名 【实例3-28】下面定义一个指向结构体的指针。 struct student *p; 和结构体变量的定义对应,结构体指针还有另外两种定义形式,这里不再介绍了。,5结构体变量成员的引用,引用结构体变量成员的一般形式为: 结构体变量名.成员名 【实例3-29】下面直接引用结构体变量的成员。 a.id 结构体变量成员也可以通过结构体指针来引用: (*结构体指针变量).成员名 或 结构体指针变量-成员名 【实例3-30】下面通过结构体指针来引用结构体的成员。 (*p).id p-id,5结构体变量成员的引用,【实例3-31】下面给出一个实例,来演示结构体变量成员的引用方式。example31.c 上面的程序,输出结果为: ID Name Sex Score 001 Jim M 98.0 001 Jim M 98.0 001 Jim M 98.0,6嵌套结构体,嵌套结构体类似于多维数组,即结构体中的成员同样为一个结构体。 【实例3-32】下面重新定义一个保存学生信息的结构体,其中的家庭住址要包含更多的信息。 01 struct student 02 int id; /* 学号 */ 03 char name20; /* 姓名 */ 04 char sex; /* 性别 */ 05 unsigned int age; /* 年龄 */ 06 struct address address; /* 家庭住址 */ 07 ; 其中,成员address为另一个结构体,如下所示: struct address char city40; char address200; unsigned long zipcode; char tel11; ; 引用嵌套结构体的成员时,需要将各层结构体变量名逐一列出,如下所示: 结构体变量名.嵌套结构体变量名.结构体成员名 例如要给student结构体中成员address中的成员zipcode赋值,可以写为: student.address.zipcode = 200000;,7应用实例,【实例3-33】下面给出了一个的应用实例。对班级中的学生按成绩进行排序,并输出排序后的学号、成绩、以及全班的平均成绩。example33.c 上面的程序,输出结果为: Please input ID and Score : 1 83 2 58 3 69 4 72 5 96 ID Score - 5 96 1 83 4 72 3 69 2 58 Average score = 75 可以看到,5个学生按其成绩进行由高到低进行了排序,并给出了平均成绩。,3.3.2 共用体,共用体又称为联合体,它是由不同类型的数据构成的。它存储时候使用了覆盖技术,使得在某一时间点只能存储某一成员的信息。结构体占用的内存空间是由包含的数据类型决定的。,1共用体类型的定义,共用体类型的定义同结构体定义类似,其一般形式为: union 共用体名 数据类型符 成

温馨提示

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

评论

0/150

提交评论