C∕C++程序设计教程(中)ppt.ppt_第1页
C∕C++程序设计教程(中)ppt.ppt_第2页
C∕C++程序设计教程(中)ppt.ppt_第3页
C∕C++程序设计教程(中)ppt.ppt_第4页
C∕C++程序设计教程(中)ppt.ppt_第5页
已阅读5页,还剩175页未读 继续免费阅读

下载本文档

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

文档简介

,CC+程序设计教程(中),第8章 函数与变量,函数的定义 函数的参数和返回值 函数的声明和调用 函数的递归调用 外部函数与内部函数 变量的作用域和存储类型,8.1 函数,C语言提供的标准库中存放着若干已定义的函数,如常用的printf()、scanf()、fabs()、sqrt()等函数,在使用这些库函数时,需要使用文件包含命令(#include)将带有该函数定义的头文件包含到当前C程序中; 对于标准库函数中没有提供的函数常常需要用户编写自定义函数来实现诸多应用功能。,8.1.1 函数的定义,函数的定义形式有两种:经典C函数定义和标准C函数定义。在Turbo C中使用两种定义形式均可。 经典C中函数定义的一般形式是: 函数类型 函数名(形参表列) 形参说明 声明部分 执行部分 ,8.1.1 函数的定义,标准C又提供了另一种形式的函数定义函数原型定义,即将形参表列和形参说明和并在一起,放在函数名后面的括号中,其一般形式为: 函数类型 函数名(类型 形参1,类型 形参2,类型 形参n) 声明部分 执行部分 其中第一行构成函数头,下面用花括弧括起来的部分构成函数体。,8.1.2 函数的参数和返回值,1 函数的参数 由前述可知,定义函数时的参数为形参,调用函数时的参数为实参。 形参和实参不同: 当函数未被调用时,形参只是形式上的参数,不占内存也无确定值。只有 当函数被调用时,形参才被分配内存单元,接收传递来的实参值;,8.1.2 函数的参数和返回值,2函数的返回值 函数返回值的取得是通过在被调函数中设置return语句得到的, 其格式一般为: return(); return语句的执行过程是:先计算return后括号内表达式的值,再将计算结果返回给主调函数。,8.1.3 函数的声明和调用,1 函数声明 一个函数调用另一个函数必须具备的前提是: 被调函数已存在,也就是说,被调函数的定义已经存在。该被调函数可以是库函数,也可以是用户自定义的函数。 对于库函数,调用前要在主调函数所在的源文件中用#include命令包含相应的头文件(即包含有该库函数的定义的文件);对于自定义函数,要在主调函数中对其进行声明。,8.1.3 函数的声明和调用,2函数调用 函数调用即主调函数通过传递某些信息来使用被调函数的功能。 函数调用的一般格式是: 函数名(实参表列); 其中,圆括弧内实参的个数、出现的顺序必须与函数定义中的形参保持一致,实参类型一般也应与形参表列对应相同,实参之间用逗号隔开。,函数调用过程,函数嵌套调用执行顺序,例8.9,弦截法解方程的思想如图8.5所示。,程序算法N-S流程图如图8.6所示。,图8.6 弦截法解方程N-S图,源程序如下:,#include “math.h“ float f(float x) float y; y=(x-5.0)*x+16.0)*x-80.0; return(y); float xpoint(float x1,float x2) float y; y=(x1*f(x2)-x2*f(x1)/(f(x2)-f(x1); return(y); ,float root(float x1,float x2) float x0,y0,y1; y1=f(x1); dox0=xpoint(x1,x2); y0=f(x0); if (y0*y10) y1=y0;x1=x0; else x2=x0; while(fabs(y0)=1e-6); return(x0); main() float x1,x2,f1,f2,x0; doprintf(“Input x1,x2: “); scanf(“%f,%f“, ,程序运行如图8.7所示。,8.1.4 函数的递归调用,递归调用有直接递归和间接递归两种调用方式,其调用示意图如图8.9所示。,例8.10 计算正整数的阶乘n!。,main() long fac(int n); /*函数声明*/ int n; printf(“Input a integer number: “); scanf(“%d“, ,例8.11 汉诺塔问题,源设计程序如下:,void move_1(char getone,char putone) printf(“n%c%c“,getone,putone); void move_n(int n,char one,char two,char three) if (n=1) move_1(one,three); else move_n(n-1,one,three,two); move_1(one,three); move_n(n-1,two,one,three); main() int m; printf(“nInput the number of diskes: “); scanf(“%d“,递归调用形式使用提示:,在许多情况下,采用递归调用形式有明显的优点。但由于递归调用费时、耗费内存,因此执行效率较低,所以在对性能要求不太高时采用,否则使用迭代或其他算法往往执行效率会更高。,8.1.5 外部函数与内部函数,一个C程序可以包含多个函数,这些函数又可能分布在多个源程序文件中。一般来说,一个函数可被它所在程序中的其他函数所调用,但有时希望某个函数只被本文件中的函数调用,而不被其他文件中的函数调用。C语言中,根据函数的使用范围可将函数分为两种:外部函数和内部函数。,8.1.5 外部函数与内部函数,1外部函数 外部函数可被它所在程序中的其他函数所调用,是程序级的函数。 extern 函数类型 函数名(形参表列) 声明部分 执行部分 在原函数定义的前面加上函数的存储类型,外部函数使用关键字extern来标识。,8.1.5 外部函数与内部函数,2内部函数 内部函数是只能被本源文件中的其他函数调用,而不能被其他源文件中的函数所调用的函数,是文件级的函数。其定义格式为: static 函数类型 函数名(形参表列) 声明部分 执行部分 ,例8.12 多个源程序文件的包含处理,源程序1 /*ch8_12_1.c*/ #include “ ch8_12_2.c “ #include “ ch8_12_3.c “ #include “stdio.h“ main() char ch; while(ch=getchar()!=n) printf(“%c,%c“,ch,next(ch); ,例8.12 多个源程序文件的包含处理,源程序2 /*ch8_12_2.c*/ static char next(char c) /*next()函数定义*/ extern void print(); /* print()函数声明*/ char d; d=c+1; print(); return(d); ,例8.12 多个源程序文件的包含处理,源程序3 /*ch8_12_3.c*/ void print() /* print() 函数定义*/ printf(“_“); ,8.2 变量的作用域和存储类型,使用变量需要“先定义,后使用”。在C语言中,对一个变量进行定义时,不仅要指出其数据类型,还要指出它的另一种属性:存储类型。存储类型指的是数据在内存中存储的方式。 在C语言中,数据的存储方式分为两大类:动态存储和静态存储。根据不同的存储方式,变量可分为自动变量、寄存器变量、静态变量和外部变量。 C语言中变量的一般定义形式是: 存储类型 数据类型 变量名;,8.2.1 变量的作用域, 内部变量:又称为局部变量,它是指定义在函数内部或复合语句内部的变量。 外部变量:又称为全局变量,是定义在函数外部任意位置的变量。 在C语言中,当函数体 内部变量与外部变量同名时,则内部变量的作用域优先,外部变量被屏蔽。,8.2.2 变量的存储类型,C程序运行时所占用的内存空间通常分为3部分,如图8.14所示。,动态存储和静态存储, 动态存储类别:对于动态存储的变量,当执行到定义它的函数或复合语句时被分配存储单元,而当函数或复合语句执行结束后系统 将释放掉所占空间。 静态存储类别:对于静态存储的变量,在源程序编译的时候即被分配内存空间,而且在程序运行期间一直占用固定的存储单元,直到程序运行结束,才会释放掉所占空间。 静态存储只有一种存储方式,即将变量存放在静态存储区。C语言中可以用static(静态)、extern(外部)两个关键字来定义和声明静态存储的变量。,8.2.2 变量的存储类型,内部变量的存储类型 自动类型变量(auto):auto类型的变量存放在内存的动态存储区,它是系统默认的存储类型。例如: auto int a; 寄存器类型变量(register):register类型的变量存放在寄存器中。例如: register int a; 静态变量(static):static类型的变量存放在内存的静态存储区,编译时即被分配内存。,8.2.2 变量的存储类型,2.外部变量的存储类型 外部变量的定义 程序级外部变量的定义方式:程序级外部变量在函数体外定义,且定义时不加任何存储类型声明。例如在函数体外部定义变量: int sum; 文件级外部变量的定义方式:文件级外部变量在函数体外定义,且定义时用static声明。例如在函数体外部定义变量: static int pop;,8.2.2 变量的存储类型, 外部变量的声明 与函数的定义和声明一样,变量的定义与声明也是两个不同的概念。定义变量需要分配存储空间;而声明变量则不需分配存储空间,它用来说明函数中即将要使用该函数外已经定义的变量的性质,又称为引用性声明。定义只有一次,而声明则可以有多次。,8.3 本章小结,C程序是函数的集合,一个较大的C程序可以设计有多个函数,这些函数可以根据需要存放在多个源文件中,但一个函数的源代码只能存放在同一个源文件中。 一个C程序由一个或多个源程序文件组成,每个源程序文件可为多个C程序共享。自定义函数,则须“先定义,后使用”。在定义了函数之后,还要注意正确地调用函数。对于带参函数,在调用时要明确C语言对实参和形参的处理方式以及实参和形参的赋值方向。 在C语言中,变量的属性取决于它的存储类型、数据类型及其定义位置。按照变量作用域的大小,可将变量划分为:程序级、文件级、函数级和复合语句级这4个等级。,8.4 思考练习题,一、思考题 二、选择题 三、填空题 四、编程题 见P195页,第9章 编译预处理,编译预处理的含义 宏定义和宏替换 文件包含 条件编译,9.1编译预处理,C语言提供的编译预处理命令主要有以下三种:宏定义命令、文件包含命令和 条件编译命令。为了与一般C语言语句相区别,预处理命令必须以符号“#”开头,一个预处理命令单独占一行,每行的末尾不得加“;”号,以区别于C语句。,9.2宏定义和宏替换,在语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为宏的标识符称为宏名。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去替换,这称为“宏替换”或“宏展开”。,9.2.1 符号常量的宏定义,用一个指定的标识符来代表一个字符串,其定义的一般形式为: #define 标识符 字符串 这里,#define表示是宏定义命令。 例如: #define PI 3.1415 功能是定义一个符号常量(宏名)PI代替字符串3.1415。,例9.1宏定义的使用,#define NAME “Welcome to use C.“ /* NAME是宏名 */ main() printf(NAME); 程序运行结果: Welcome to use C.,使用宏定义的说明:,(1) 宏名一般用大写字母表示,变量名通常用小写字母表示,但并非是规定。 (2) 宏展开时将宏名替换为字符串,可以是常数,也可以是表达式,预处理程序对它不作任何检查。 (3) 宏定义不是语句,在行末不必加分号,如加上分号则连分号也一起替换。 4)在宏定义和宏替换时,可以使用已经定义的宏名。,例9.3使用已定义的宏定义。,#define A 2 #define B 3 #define S (A+B)*2 /* A,B是已定义的宏名 */ main() printf(“The result is:%dn“,S); 程序运行结果: The result is: 10,9.2.2 带参数的宏定义,语言允许宏带有参数。带参数的宏定义一般形式为: #define 宏名(参数表) 字符串 其中的字符串中含有参数表中所指定的参数。带参数的宏调用的一般形式为: 宏名(实参表);,例9.5 从键盘上输入两个数据,比较大小并输出较大的数,定义宏实现。,#define MAX(x,y) (xy)?x:y main() int a,b,max; printf(“Please Input a ,b: “); scanf(“%d%d“, 程序运行结果: Please Input a ,b: 10 20 Max=20,9.3文件包含,文件包含是指一个源文件可以将另外一个源文件的全部内容包含进来。其命令的一般形式如下所示: #include “文件名“ 或 #include 其中,文件名是被包含文件的文件名,它是一个磁盘文件。,9.4 条件编译,预处理程序提供了条件编译的功能。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。 条件编译命令有以下几种形式。 1.第1种形式 #ifdef 标识符 程序段1 #else 程序段2 #endif,9.4 条件编译,2. 第2种形式 #ifndef 标识符 程序段1 #else 程序段2 #endif 与第一种形式的区别是将“ifdef”改为“ifndef”。,9.4 条件编译,3. 第3种形式 #if 常量表达式 程序段1 #else 程序段2 #endif 功能:如常量表达式的值为真(非0),则对程序段1 进行编译,否则对程序段2进行编译。其中的else部分可以省略。,例9.12 输入一行报文,将报文原码输出,或仅输出相同个数的星号“*”,#define CHANGE 1 /*预置为输出星号*/ #include main() int len,i; char str20; printf(“nPlease input the message: “); gets(str); #if CHANGE /*输出星号*/ for (i=0; istrlen(str); i+) printf(“*“); #else /*输出原文*/ printf(“The message is:%sn“, str); #endif 程序执行结果: Please input the message: Hello * 如果将程序第一行改为: #define CHANGE 0 则在预处理时,对程序段2进行编译处理,将报文原样输出,9.5 本章小结,宏定义是用一个标识符来表示一个字符串,这个字符串可以是常量、变量或表达式。在宏替换时用该字符串代换宏名。宏定义可以带有参数,宏替换时是以实参代换形参,而不是“值传送”。为了避免宏替换时发生错误,宏定义中的字符串应加括号。 文件包含是指一个源文件可以将另一个源文件包含进来,它可用来把多个源文件连接成一个源文件进行编译,生成一个目标文件。使用标准库函数时,要注意将其头文件包含进来。,9.6 思考练习题,一、思考题 二、选择题 三、填空题 四、编程题 见P213页,第10章 指针与应用,指针的基本概念 指针变量和指针运算符 指针和函数参数 指针和数组 指针和函数,10.1 指针的基本概念,1内存地址 计算机硬件系统的内存储器中,拥有大量的存储单元。一般把存储器中的一个字节称为一个内存单元。为了方便管理,必须为每一个存储单元编号,这个编号就是存储单元的地址。 2变量地址 在程序中定义了一个变量,在编译时就会给这个变量分配内存单元,根据变量的类型,分配一定长度的空间。,10.1 指针的基本概念,如果执行程序: main() int a=10, b=20, c; c=a+b; printf(“Sum=%dn“, c); 变量在内存中的地址和值如图9-1所示,10.1 指针的基本概念,3指针和指针变量 (1)指针 指针即地址。变量在内存单元的首地址称为该变量的“指针”。 (2)指针变量 在语言中,允许用一个变量来存放指针,这种变量称为指针变量。 当一个指针变量中存放其它变量的地址时,可以通过该指针变量访问变量。,10.2 指针变量和指针运算符,指针变量是指存放地址的变量,指针变量可以进行某些运算,但其运算的种类是有限的。它只能进行赋值运算、部分算术运算及关系运算。,10.2.1指针变量的定义,在C语言中,规定所有变量在使用前必须先定义后使用,指针变量也不例外,在引用指针变量之前必须先定义。 指针变量的定义形式如下: 类型说明符 *指针变量名;,10.2.2 指针变量的引用和初始化,1指针变量基本运算符 (1) 取地址运算符,例10.1指针变量的使用,main() int a=100, b,*p; p= 程序运行结果: 100, 100 1000,1000,10.2.2 指针变量的引用和初始化,2指针变量的初始化 在定义指针变量的同时给指针变量赋初值,叫做指针变量的初始化。一般形式为: 类型说明符 *指针变量名=初始地址值; 例如: int a; int *p=,10.2.3 指针的运算,在C语言中,指针的运算主要有如下3种: 赋值运算 算术运算 关系运算,10.2.3 指针的运算,1指针的赋值运算 指针变量的赋值运算只能在同一数据类型之间进行,有以下几种形式。 int *p1,*p2,a,s5; int *p1=,10.2.3 指针的运算,2指针的算术运算 指针的算术运算是按地址计算规则进行的,所以指针的算术运算应考虑到指针所指向的数据类型。 (1) 指针与整数的加、减运算 对于指向数组的指针变量,可以加上或减去一个整数n。例如:假设p是指向数组a的指针变量,则p+n、p-n、p+、+p、p-、-p运算都是合法的。,10.2.3 指针的运算,假设指针变量p当前指向数组元素a0,则p+n则指向数组元素an。例如: int a5,*p; p=a; p+; p=a; p=p+2; /* p指向a2,即p的值为&a2 */,10.2.3 指针的运算,3.指针的关系运算 指针之间的关系运算可确定它们所指向的数据对象存储位置的前后关系,所进行的比较是两个指针变量所指向的地址的比较。 通常只有进行关系运算的两个指针指向同一组数组时,方可表示它们所指数组元素之间的关系,比较才有意义。,10.2.3 指针的运算,设p1和p2指向同一数组a,并有p1=则关系运算: p1=p2 结果为假,当p1和p2指向同一数组元素时才为真; p1p2 结果为假,当p1指向的变量在p2指向的变量之后时为真; p1=p2 结果为假,当p1指向的变量在p2指向的变量之后或相同时为真; p1!=p2 结果为真,当p1指向的变量和p2指向的变量位置不同时为真。 此外,指针变量还可以与NULL比较。设p为指针变量且p=NULL,则: p=0 结果为真,表明p是空指针,它不指向任何变量。,10.3 指针和函数参数,指针变量既可以作为函数的形参,也可以作函数的实参。指针变量作实参时,与普通变量一样,是“值传递”,即将指针变量的值传递给被调用函数的形参,对应的形参必须是一个指针变量。 当指针变量作函数的参数时,被调用的函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。,例10.5 分析下面程序的运行结果。,change(int x, int *pm) x=10; *pm=10; main() int n=200,m=200, *p1; p1= 程序的运行结果: n=200, m=10,10.4 指针与数组,在C语言中,指针和数组关系非常密切。访问数组元素,既可以用下标法,也可以用指针法。 用指针访问数组元素 一个数组占用一块连续的内存单元,包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。每个数组元素按其类型不同占有几个连续的内存单元,一个数组元素的地址就是它所占有的内存单元的首地址。,10.4.2 指针与多维数组,多维数组是按行连续存储的,所以也可以使用指针访问多维数组。 1多维数组的地址 设有整型二维数组a34定义如下: int a34= 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11;,10.4.2 指针与多维数组,2.指向多维数组的指针变量 语言允许把一个二维数组分解为多个一维数组来处理,例如二维数组a可以理解成由3个元素组成,分别是a0、a1和a2。a代表a0的地址,a+1则代表a1的地址,不是指向下一个数组元素,而是指向下一行。C语言提供了指向多维数组的指针变量来实现。 设p为指向二维数组行的指针变量,可定义为: int (*p)4;,10.4.3 用指针访问字符串,字符串在内存中占一块连续的地址空间,通常使用字符数组来存取字符串。实际上,在C语言中,可以使用两种方法来表示字符串,一种方法是使用字符数组表示字符串;另一种方法是使用字符指针表示字符串。 引用字符串时,既可以逐个字符引用,也可以整体引用。,例10.15使用字符数组存放一个字符串,然后输出该字符串。,main() char string=“Welcome to study C languages.“; int i=0; while (stringi!= 0) printf(“%c“,stringi+); ,10.4.4 指针数组,一个数组中的每个元素都是指针类型,则该数组称为指针数组。指针数组的每个元素都是指向相同数据类型的指针变量。指针数组定义的一般形式为: 类型说明符 *数组名数组长度; 例如: int *p5; 表示p是一个指针数组,它有5个数组元素,每个元素都是一个指针,指向整型变量。,10.4.5 指向指针的指针,指针可以指向整型变量、字符型变量等,同样,指针也可以指向指针变量。如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。 定义一个指向指针型数据的指针变量的一般形式如下: char *p; 表示指针变量p是指向一个字符指针型变量的指针变量。,10.5指针与函数,一个C程序可由一个主函数和若干个函数构成。主函数调用其他函数,其他函数也可以相互调用。同一个函数可以被一个或多个函数调用任意多次。,10.5.1 函数指针,指针变量不仅可以指向普通变量、字符串和数组,也可以指向函数。一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。 函数指针变量定义的一般形式为: 类型说明符 (*指针变量名)(); 例如: int (*p)(); 定义p为一个指向函数的指针变量,函数返回值为整型。,10.5.2 函数指针作函数参数,函数的参数不仅可以是整型量、字符型量,同样指向函数的指针也可以作为函数的参数。 例10.26 函数sin、cos、tan分别用于计算浮点数的正弦、余弦、正切值,函数 execute则是可完成这些计算的通用函数。,源程序,#include main() double execute (); double (*function3)(); double x,y; int i,n; function0=sin; function1=cos; function2=tan; printf(“输入x:“); scanf(“%lf“, ,double execute(double x, double (*func)() double y; y=(*func)(x); return y; 程序运行结果: 输入x:0.5 0-计算x的正弦,1-计算x的余弦、2-计算x的正切值:请选择输入(0-2):2 计算结果为:0.54630,10.5.3返回指针的函数,返回指针值函数的一般定义形式为: 类型说明符 *函数名(形参表) /* 函数体 */ 例如: int *f(int x,int y) int *p; /*函数体*/ return(p); ,10.5.4 main函数的参数,语言规定main()函数的参数只能有两个,习惯上这两个参数写为argc和argv。第一个形参argc必须是整型变量,第二个形参argv是指向字符串的指针数组。因此main函数的函数头可以写成下列形式: main(int argc,char *argv),例10.28 显示命令行中输入的所有参数,main(int argc,char *argv) int i=1; printf(“the count of parameters is:%dn“,argc); while(argc1) printf(“%sn“,argvi); argc-; i+; ,10.6 本章小结,本章主要学习了指针的含义、指针和地址、指针变量和指针运算符、指针和函数参数、指针和字符串、指针与数组以及指针与函数等内容。通过本章的学习,一定要认识到,指针变量本身就是一种变量,与其它变量一样,系统要为其分配一定的存储单元,但是它只能存放各种类型数据的地址。,指针的数据类型表,10.7 思考练习题,一、思考题 二、选择题 三、填空题 四、编程题 见P424页,第十一章 结构体与共用体,结构体定义、引用 和初始化 结构体数组 结构体指针和链表 共用体定义和引用,本章介绍的结构体和共用体同属构造类型数据,常用于实用程序开发设计。,11.1 结构体 结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体-自定义数据类型 结构体类型定义,struct 结构体名 类型标识符 成员名; 类型标识符 成员名; . ;,成员类型可以是 基本型或构造型,struct是关键字, 不能省略,合法标识符 可省:无名结构体,例 struct student int num; char name20; char sex; int age; float score; char addr30; ;,结构体类型定义描述结构 的组织形式,不分配内存,结构体类型定义的作用域,struct 结构体名 类型标识符 成员名; 类型标识符 成员名; . ; struct 结构体名 变量名表列;,11.2 结构体变量的定义 先定义结构体类型,再定义结构体变量 一般形式:,例 struct student int num; char name20; char sex; int age; float score; char addr30; ; struct student stu1,stu2;,例 #define STUDENT struct student STUDENT int num; char name20; char sex; int age; float score; char addr30; ; STUDENT stu1,stu2;,定义结构体类型的同时定义结构体变量 一般形式:,struct 结构体名 类型标识符 成员名; 类型标识符 成员名; . 变量名表列;,例 struct student int num; char name20; char sex; int age; float score; char addr30; stu1,stu2;,直接定义结构体变量 一般形式:,struct 类型标识符 成员名; 类型标识符 成员名; . 变量名表列;,例 struct int num; char name20; char sex; int age; float score; char addr30; stu1,stu2;,用无名结构体直接定义 变量只能一次,说明 结构体类型与结构体变量概念不同 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体可嵌套 结构体成员名与程序中变量名可相同,不会混淆 结构体类型及变量的作用域与生存期,11.3 结构体变量的引用 引用规则 结构体变量不能整体引用,只能引用变量成员,可以将一个结构体变量赋值给另一个结构体变量 结构体嵌套时逐级引用,成员(分量)运算符 优先级: 1 结合性:从左向右,引用方式: 结构体变量名.成员名,11.4 结构体变量的初始化 形式一:,struct 结构体名 类型标识符 成员名; 类型标识符 成员名; . ; struct 结构体名 结构体变量=初始数据;,例 struct student int num; char name20; char sex; int age; char addr30; ; struct student stu1=112,“Wang Lin”,M,19, “200 Beijing Road”;,形式二:,struct 结构体名 类型标识符 成员名; 类型标识符 成员名; . 结构体变量=初始数据;,例 struct student int num; char name20; char sex; int age; char addr30; stu1=112,“Wang Lin”,M,19, “200 Beijing Road”;,形式三:,struct 类型标识符 成员名; 类型标识符 成员名; . 结构体变量=初始数据;,例 struct int num; char name20; char sex; int age; char addr30; stu1=112,“Wang Lin”,M,19, “200 Beijing Road”;,11.5 结构体数组 结构体数组的定义 三种形式:,形式一: struct student int num; char name20; char sex; int age; ; struct student stu2;,形式二: struct student int num; char name20; char sex; int age; stu2;,形式三: struct int num; char name20; char sex; int age; stu2;,结构体数组初始化,例 struct int num; char name20; char sex; int age; stu =,;,顺序初始化: struct student int num; char name20; char sex; int age; ; struct student stu =100,“Wang Lin”,M,20, 101,“Li Gang”,M,19, 110,“Liu Yan”,F,19;,例 struct student int num; char name20; char sex; int age; stu =,;,结构体数组引用,引用方式: 结构体数组名下标.成员名,例 统计后选人选票,struct person char name20; int count; leader3=“Li”,0,“Zhang”,0,”Wang“,0; main() int i,j; char leader_name20; for(i=1;i=10;i+) scanf(“%s“,leader_name); for(j=0;j3;j+) if(strcmp(leader_name,)=0) leaderj.count+; for(i=0;i3;i+) printf(“%5s:%dn“,,leaderi.count); ,11.6 结构体和指针 指向结构体变量的指针 定义形式:struct 结构体名 *结构体指针名; 例 struct student *p;,使用结构体指针变量引用成员形式,存放结构体变量在内存的起始地址,指向运算符 优先级: 1 结合方向:从左向右,例 指向结构体的指针变量,main() struct student long int num; char name20; char sex; float score; stu_1,*p; p= ,例 int n; int *p= n=10,struct student stu1; stru ct student *p= (*p).num=101,指向结构体数组的指针,例 指向结构体数组的指针,struct student int num; char name20; char sex; int age; stu3=10101,“Li Lin“,M,18, 10102,“Zhang Fun“,M,19, 10104,“Wang Min“,F,20; main() struct student *p; for(p=stu;pnum,p-name,p-sex,p-age); ,用指向结构体的指针作函数参数 用结构体变量的成员作参数-值传递 用指向结构体变量或数组的指针作参数-地址传递 用结构体变量作参数-多值传递,效率低,struct data int a, b, c; ; main() void func(struct data); struct data arg; arg.a=27; arg.b=3; arg.c=arg.a+arg.b; printf(“arg.a=%d arg.b=%d arg.c=%dn“,arg.a,arg.b,arg.c); printf(“Call Func()n“); func(arg); printf(“arg.a=%d arg.b=%d arg.c=%dn“,arg.a,arg.b,arg.c); void func(struct data parm) printf(“parm.a=%d parm.b=%d parm.c=%dn“,parm.a,parm.b,parm.c); printf(“Process.n“); parm.a=18; parm.b=5; parm.c=parm.a*parm.b; printf(“parm.a=%d parm.b=%d parm.c=%dn“,parm.a,parm.b,parm.c); printf(“Return.n“); ,copy,例 用结构体变量作函数参数,struct data int a, b, c; ; main() void func(struct data *parm); struct data arg; arg.a=27; arg.b=3; arg.c=arg.a+arg.b; printf(“arg.a=%d arg.b=%d arg.c=%dn“,arg.a,arg.b,arg.c); printf(“Call Func()n“); func( ,例 用结构体指针变量作函数参数,11.7 动态数据结构 链表 链表的提出 定义形式:数组在内存中占用连续存储的空间。 链表是动态的进行存储分配,链表的各个结点在逻辑上是连续的,但是在内存中存储时不占用连续的空间。 链表的使用能有效的避免存储空间的浪费和数据移动的问题。,链表的基本结构 链表是一种常用的、能够实现动态存储分配的数据结构。 (1)头指针变量head指向链表的首结点。 (2)每个结点一般由2个域组成: 1)数据域存储结点本身的信息。 2)指针域指向后继结点的指针。 (3)尾结点的指针域置为“NULL(空)”,作为链表结束标志。,链表结点的定义,以上定义了一个结构体student类型,student类型数据包括3个数据成员:int类型num、float类型的score和指向另一个student类型数据的指针变量next。,struct student int num; float score; struct student *next; ;,单向链表的访问,输出链表各个结点的数据,void print(struct student *head) struct student *p; p=head; while(p!=NULL) printf(“%d,%6.1fn”,p-num,p-score); p=p-next; ,统计链表的长度,void len_link(struct student *head) int n=0; struct student *p; p=head; while(p!=NULL) n+; p=p-next; return(n); ,动态存储空间的建立和释放,动态存储空间的建立 (1)malloc函数,其函数原型为: 函数原型为: void *malloc(unsigned int size); 其作用是在内存的动态存储区中分配一个长度为size的连 续空间。 (2)sizeof(type)运算符 计算所给数据类型type的字节数,主要用来计算链表中结 点所占动态存储空间的字节数。,动态存储空间的释放 free函数,其函数原型为:void free(void *p); 其作用是释放由p指向的内存区,使这部分内存区能被其他 变量使用。p是调用malloc函数时返回的值。,建立链表 输出链表 查找结点 删除结点 插入结点,链表的基本操作,建立链表 主要步骤:(结点为struct student类型数据结构) (1)先设三个指针变量:head、p1、p2,它们都是用来指向struct student类型数据的。 struct student *head=NULL,*p1,*p2; head:头指针变量,指向链表第一个结点,作函数返回值。 p1:指向新申请的结点。 p2:指向链表的尾结点,用p2-next= p1,实现将新申请的 结点插入到链表尾,使之成为新的尾结点。 (2)malloc函数开辟第一个结点,并使head和p2都指向它。 head=p2=(struct student * )malloc(sizeof(struct student); scanf(“%d%f“, /*读入数据*/,(3) 再用malloc函数开辟另一个结点并使p1指向它,接着输入该结点的数据,并与上一结点相连,且使p2指向新建立的结点。建立新结点: p1=(struct student*)malloc(sizeof(struct student); scanf(“%d%f“, 如图(c)所示:,(a),(b),(c),重复执行第(3)步,可以建立第三个结点,并使第三个结点和第二个结点链接(p2-next=p1;),依次创建后面的结点,直到所有的结点建立完毕。 (4)给末结点的指针域赋值NULL (p2-next=NULL;),例 建立有n个student类型结点的链表,n的值从键盘输入,再输出链表。,#define NULL 0 #define LEN sizeof(struct student) #include struct student /*定义结点*/ int num; float score; struct student *next; ; void main() int n; struct student *head; struct student create(int n); void print(struct student *head); printf(“please input nn“); scanf(“%d“, ,/*create(int n)函数: 创建一个具有头结点的单链表*/ /*形参n值:创建链表的结点数*/ /*返回值:返回单链表的头指针*/ struct student *create(int n) int i; struct student *head=NULL, *p1, *p2; head=p2=(struct student * ) malloc(LEN); /*申请新结点的空间*/ scanf(“%d%f“, ,/* void print(struct student *head)为链表输出函数*/ /*形参head为要输出链表的头指针*/ void print(struct student *head) struct student *p; p=head; while(p!=NULL) printf(“%d,%6.1fn“,p-num,p-score); p=p-next; /*移动指针*/ ,删除结点,主要步骤: 假设在结点类型为student的链表中删除num域为某个值的结点。 设三个指针变量:head、p1、p2,它们都是用来指向struct student类型数据的,head指向链表头,若head=NULL,则链表为空,没有可删除结点。 查找要删除的结点,使p1指向它,p2指向p1的前一结点。 有两种情况:删除首结点和其它结点。,(2)删除其它结点 删除链表的中间结点通过将下一结点地址赋给前一结点地址来实现,即将要删除的p1结点的后继地址,放入前一结点p2的地址域(p2-next=p1-next;),同时释放p1结点。,(1)删除首结点 使p1指向第一个结点,用以下语句实现删除首结点操作。 p1=head; head=p1-next; free(p1);,head,p1,/* delet(struct stude

温馨提示

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

评论

0/150

提交评论