C语言程序设计实用教程第10章.ppt

上传人:max****ui 文档编号:8315057 上传时间:2020-03-28 格式:PPT 页数:67 大小:240.16KB
返回 下载 相关 举报
C语言程序设计实用教程第10章.ppt_第1页
第1页 / 共67页
C语言程序设计实用教程第10章.ppt_第2页
第2页 / 共67页
C语言程序设计实用教程第10章.ppt_第3页
第3页 / 共67页
点击查看更多>>
资源描述
第十章结构体与共用体 10 1结构体类型与结构体变量的定义10 2结构变量的初始化与引用10 3结构体数组10 4指向结构体类型数据的指针10 5结构体和函数10 6单链表10 7共用体10 8枚举类型10 9定义已有类型的别名 教学提示前6章介绍了五种基本数据类型和指针类型 还介绍了一种构造类型 数组 它是用基本数据类型构造出来的具有相同类型变量的集合 当要处理那些具有不同类型 而又相互关联的一组数据时 数组就显得力不从心 本章将介绍另外几种构造类型 结构体 共用体和枚举 它们可以是不同类型变量的集合 其中最重要的是结构体类型 它可以方便地处理像 记录 链表 这样的静态和动态数据结构 教学目标掌握结构体类型 结构体变量 结构体数组 结构体指针的定义和引用方法 掌握结构体变量 结构体数组和结构体指针变量在函数间的传递规则 能够用结构体进行链表的简单操作 了解共用体及枚举类型的概念 定义和引用 学会已有类型的别名定义方法 概述 在一些复杂的数据结构中 有时需要将不同类型的数据集合成一个有机的整体 如 一个学生的情况纪录单可能包括学号 姓名 性别 年龄 成绩 家庭地址等数据项 这样的整体 C语言中称为 结构体 数据结构 简称 结构体 structure 结构体是一种较为复杂而又非常灵活的构造型的数据类型 一个结构体类型的数据可以由若干个称为成员 或域 的成分组成 不同的结构体类型其成员不同 对于一个具体的结构体而言 其成员的数量是固定的 这一点与数组相同 但该结构体中各成员的数据类型可以不同 这是结构体与数组的重要区别 10 1结构体类型与结构体变量的定义 10 1 1结构体类型定义结构体类型定义的一般形式 struct结构体名 数据类型数据项1 数据类型数据项2 数据类型数据项 其中struct是关键字 结构体成员表列也称域表 每个成员也称结构体中的一个域 对每个成员都应进行类型说明 例如 structstudent intnum charname 20 charsex intage floatscore 对结构体类型定义的说明 1结构体类型定义是由程序员根据设计需要自行定义的 因此结构体类型可以有多种 每种结构体类型都可以有自己的结构体名以及包含不同数目的成员 2若定义了一个结构体类型 那仅仅是定义类型而已 而不分配内存单元 例如上面已经定义了的structstudent结构体类型 structstudent可以用来定义一个该类型的变量 并不意味着它的那些成员被分配了内存空间 3成员名可以与程序中的变量名相同 两者不代表同一对象 例如 程序中可以另定义变量num 它与structstudent中的num是两回事 互不干扰 4结构体成员类型可以是整型 实型 字符型 数组 指针等基本类型或构造类型 还可以是已定义过的结构体类型 structdate intyear intmonth intday structstudent intnum charname 20 charsex structdatebirthday floatscore 4 练习 定义一个学生成绩结构类型 由学号和三门成绩共4项组成 10 1 2结构体变量定义 结构体类型的定义只是指出了该结构的组成情况 表明存在有此种类型的结构模型 该结构体类型中不能存放具体的数据 系统也不会为它分配实际的存贮单元 为了能在程序中使用结构体类型的数据 应在定义了某种结构体类型以后 再定义该结构体类型的变量 以便在结构体类型的变量中存放具体的数据 结构体变量的定义有三种形式 结构体变量定义1 1 先声明结构体类型 再定义结构体类型的变量 structstudent intnum charname 20 charsex intage floatscore 4 structstudentst1 st2 结构体变量定义2 2 在声明结构体类型的同时定义结构体类型的变量 structstudent intnum charname 20 charsex intage floatscore 4 st1 st2 结构体变量定义3 3 直接定义结构体类型变量 struct intnum charname 20 charsex intage floatscore 4 st1 st2 在关键字struct后省略了结构体名 不提倡使用这种形式 可用sizeof来计算一个结构体类型数据的长度如 sizeof structstudent 或sizeof st1 有关结构体变量的说明 1 结构体类型与结构体变量是两个不同的概念 其区别如同int类型与int型变量的区别一样 2 结构体类型中的成员名 可以与程序中的变量同名 它们代表不同的对象 互不干扰 3 定义了结构体变量后 系统会为之分配内存单元 如上例中的st1 st2在内存中各占37个字节 可用sizeof来计算一个结构体类型数据的长度 如 sizeof structstudent 或sizeof st1 练习2定义一个学生信息结构类型 由学号 姓名 性别和生日共4项组成 其中生日由日期结构类型构成 10 2结构变量的初始化与引用 初始化就是在定义变量的同时给变量赋初值 例如 structstudent intnum charname 8 sex structdate intyear month day birthday floatscore 4 st1 101 Xu F 1975 9 12 83 5 88 75 5 90 在对结构体变量进行初始化时 系统是按每个成员在结构体中的顺序一一对应赋初值的 若只对部分成员进行初始化 则只能给前面的若干成员赋值 而不允许跳过前面的成员给后面的成员赋值 未赋值部分均为0值 结构体变量的引用 1 结构体变量整体引用如果要将结构体变量整体引用则往往只限于将一个结构体变量直接赋值给另一个具有相同类型的结构体变量 structstudent intnum charname 8 sex structdate intyear month day birthday floatscore 4 st1 101 Xu F 1975 9 12 83 5 88 75 5 90 structstudentst2 st2 st1 程序执行后变量st2中各成员的值都完全与st1各成员的值相等 2 结构体变量成员引用对结构体成员的引用方式为 结构体变量名 成员名其中 为结构体成员运算符 它的优先级处于所有运算符优先级的最高级别 例如 st1 num表示st1变量中的num成员 可以对它赋值st1 num 1001 这时st1 num就相当于一个整型数 结构体变量引用规则说明 1结构体变量整体不能直接用来输入输出 如 scanf d s c d f 但可逐个全部或部分输入输出 如 scanf d c f st1 num st1 sex st1 score 2 2若成员本身又是一个结构体类型 则必须逐层使用成员名定位 找到最底层的成员 例如在结构体变量st1中对成员year的引用方式为 st1 birthday year 3若结构体中的成员是字符型数组时 则可将其看作是 字符串变量 而直接引用 例如 对st1中name的引用可写成 st1 name 4若结构体中的成员是数值型数组时 则对该数组成员的引用 应该为对该数组元素的引用 例如 对st1中score数组元素的引用可写成 st1 score 0 st1 score 1 st1 score 2 st1 score 3 Wrong 我们可以将结构体中变量的每个成员当作是同类型的普通变量 对它进行同类变量所允许的任何操作 例如成员变量st1 name是字符串 可以对它进行字符串变量所允许的任何操作 包括输入 输出 同样对于成员中的数组元素也可按同类型的数组元素进行操作 如 scanf s st1 name 对结构体成员name赋值 for i 0 i 4 i scanf f floatf for i 0 i 4 i 在TC中的赋值语句 scanf f 例写程序给结构体变量赋初值 structstudent intnum charname 20 sex intage floatscore main structstudentst printf pleaseinputdata n scanf d s c d f 10 3结构体数组 结构体数组是同类型结构体变量的集合 1 结构体数组的定义和初始化structstudent intnum charname 20 charsex intage floatscore sta 3 1001 LiLi m 20 75 0 1002 fangfang m 21 86 0 1003 yuanyuan f 19 91 0 2 结构体数组的输入和输出对结构体数组数据的输入或输出可利用for循环结构 例如inti for i 0 i 2 i scanf d s c d f 这是给数组sta 3 的元素赋值操作 例1 求3个学生的平均成绩 main structstudent intnum charname 20 charsex intage floatscore st 3 inti floataverage 0 for i 0 i 3 i printf nnum scanf d 10 4指向结构体类型数据的指针 1 定义和初始化定义指向结构体类型的数据指针的方法跟定义指向简单类型变量的指针方法相同 只不过数据类型的声明部分用在程序中已定义的结构体数据类型来替代 如 structstudent intnum charname 20 floatscore structstudent p stu 跟任何其他类型的指针一样 要使用定义好的指针变量 在使用前应对它赋值 也就是使它确切地表示某一个变量的地址 例如有上面的定义 可对p进行如下赋值 p 如果已经定义了结构体数组变量 那么也可以用结构体数组名对同类型的结构体指针赋值 例如 structstudentst 5 p p st 指针p是指向structstudent类型的数据 它只能表示一个该结构体类型数据的地址 而不能指向一元素中的某个成员 如下面的两个赋值语句都是错误的 p wrong 2用结构体指针引用结构体成员 在引入指向结构体变量的指针的概念后 原来引用变量成员的方式可以变为以下形式 指针变量名 成员名等价于结构体变量名 成员名在C语言中为了使用方便和直观 p num可以改用p num来代替 称为指向运算符 因此 下面引用结构体成员的几种方式完全等价 结构体变量名 成员名 如stu num 结构体指针名 成员名 p num 结构体指针名 成员名 结构体变量名 成员名 更地道 只可用在表示变量名含义的变量的后面 而 只可用在表示地址含义的变量的后面 3指向结构体数组的指针 例10 3定义一个结构体数组并赋初值 用指针法输出这些数据 structstudent intnum charname 10 charsex main structstudentst 3 101 Xu M 102 Yan F 103 Ling F structstudent p printf NoNameSex n for p st pnum p name p sex 10 5结构体与函数 10 5 1用数据复制方式传递结构体变量10 5 2用地址复制方式传递结构体变量10 5 3结构体数组在函数间的传递10 5 4结构体数据作为函数返回值 10 5 1用数据复制方式传递结构体变量 把一个结构体变量作为普通变量来处理 例如两个相同的结构体变量之间可以赋值 可以把一个结构体变量作为一个参数以复制方式传递给被调函数 函数也可以返回一个结构体类型的值 例3用数据复制方式传递结构体变量 include stdio h structstudent intnum charname 10 charsex voiddisplay structstudents printf NoNameSex n printf 5d 7s c n s num s name s sex main structstudentst 101 Xu M display st 有关数据复制方式传递数据时应注意以下两点 1 调用时实参与被调用函数定义中的形参都是结构体变量名 2 形参和实参代表两个不同的结构体变量 其结构类型相同 但运行时不同存储空间 因此 调用函数的形参不能修改实参变量的值 10 5 2用地址复制方式传递结构体变量 采用地址复制方式传递结构体变量时 实参是体变量的首地址 形参是与实参有相同结构类型的指针 该指针用来接收传递的结构体变量的首地址 用地址复制方式来传递结构体变量是常用的传递方式 它可以提高运行效率 例4给出年 月 日 计算出它是该年的第几天 要求采用地址复制方式 include stdio h structdate intyear month day intdays structdate s staticmonth 0 31 28 31 30 31 30 31 31 30 31 30 31 inti sum s day for i 1 imonth i sum month i if s month 2 10 5 3结构体数组在函数间的传递 函数间不仅可以传递一般的结构体变量 还可以传递结构体数组 在传递结构体数组时 实参是数组名 即结构体数组的首地址 形参是可以是数组名或者指针 它接收传递过来的数组首地址 使它指向实参所表示的结构体数组 例5结构体数组在函数间的传递 include stdio h structstudent intnum charname 10 charsex voidshow structstudent st structstudent p printf NoNameSex n for p st pnum p name p sex main structstudentst 3 101 Xu M 102 Yan F 103 Ling F show st 10 5 4结构体数据作为函数返回值 函数的返回值不仅可以是一个简单变量 也可以是一个结构体变量 结构体指针变量 例6函数的返回值是一个结构体变量 include stdio h structstudent intnum charname 10 charsex structstudentread structstudentp printf nnum scanf d voiddisplay structstudents printf NoNameSex n printf 5d 7s 3c n s num s name s sex voidmain structstudentst st read display st 注意 这段程序在TC环境下运行出错 必须要在BC或者VC环境下运行才正确 例7函数的返回值是一个结构体指针变量 include stdio h structstudent intnum charname 10 charsex structstudent read structstudentp inti returnp i voiddisplay structstudents printf NoNameSex n printf 5d 5s 5c n s num s name s sex voidmain structstudentst 3 101 Xu M 102 Yan F 103 Ling F structstudent p p read st 0 display p 10 6单链表 10 6 1单链表的概述10 6 2单链表10 6 3建立链表10 6 4输出链表10 6 5插入结点10 6 6删除结点 10 6 1单链表的概述 C语言程序为批量的数据集合向操作系统申请存储空间时一般有三种模式 一 用数组 用数组存放数据时 通过数据类型定义 数组在程序编译期间就申请到了所要求的存储空间 因此必须事先定义好固定的长度 并且连续存放 对于那些数组元素不确定的数组 在定义时就得用可能的最多元素的个数来定义 实际应用中可能会造成大的浪费 静态存储分配方式 二 利用C语言提供的动态内存分配函数 在需要使用到某一批数据前分配相应数量的存储空间块 该存储块由一个指针来标识 这个操作过程是在程序运行中完成的 这是一种半动态的存储分配方式 三 用链表 C语言中引入的一种重要的数据结构 链表是完全动态地进行存储分配的一种结构 它能随时随地根据需要开辟内存单元 链表中的各元素在内存中可以不连续存放 通过指针把它们串连成一个整体 并且被串连的数据个数和顺序关系可以按需改变 因此能方便迅速的插入 删除数据项 常用的内存管理函数有以下三个 1 分配内存空间函数malloc调用形式 类型说明符 malloc size 功能 在内存的动态存储区中分配一块长度为 size 字节的连续区域 函数的返回值为该区域的首地址 常用的内存管理函数 2 分配内存空间函数calloc调用形式 类型说明符 calloc n size 功能 在内存动态存储区中分配n块长度为 size 字节的连续区域 函数的返回值为该区域的首地址 3 释放内存空间函数free调用形式 free void ptr 功能 释放ptr所指向的一块内存空间 ptr是一个任意类型的指针变量 它指向被释放区域的首地址 被释放区应是由malloc或calloc函数所分配的区域 10 6 2单链表 链表有单链表 双链表和循环链表之分 本章重点介绍其中的一种 最简单也是最常用的链表 单链表有关单链表的基本概念链表是一种链式结构 各元素在内存中可以不是连续存放的 链表中的元素又称为结点 结点必定是结构体变量 它包含两个方面的数据 一为用户要用到的实际数据 图8 6中的A B C D 二为一个表示下一结点的首地址的指针变量 图8 6结点中不加阴影的部分 单链表一般设有一个头指针变量 用来存放第一个结点的地址 图8 6中用head表示 单链表中尾结点的指针指向NULL 表示空地址 使用链表前首先要定义好该链表的结点类型 链表的结点类型是一个结构体类型 该结构体除了包括用户要用的实际数据成员变量外 还包括一个指向自身类型的指针变量 往往用next给该指针变量命名 顾名思义 next表示下一个结点的地址的意思 通常也称这种结构体类型为自引用结构 单链表的结点的结构体类型定义的一般形式为 struct结构体名 结构体其他成员表列 数据域 struct结构体名指针变量名 地址域 例 一个学生链表的结点的结构体类型定义如下 structst intnum floatscore structst next 定义了结点的类型后就可以用它来定义结点变量或指向该类型数据的指针变量了 比如 structststu p p可以用如下语句赋值 p 其中 指针变量next是structst类型中的一个成员 是指向自身结构体类型的指针变量 10 6 3建立链表 建立链表是指在程序执行的过程中从无到有的创建一个链表 意味着反复创建一个一个的结点 并给这些结点建立起前后相连的关系 直到最后一个结点为止 在C程序中用循环结构实现 反复 创建结点的过程 创建每个结点的过程可分为三步 第一步考虑新结点空间的申请 第二步考虑给新申请到的结点的成员赋值 第三步考虑如何把新结点插入到链表已经建好的部分 根据第三步提出的问题 创建单链表的方式可分为三种 第一种方式是新结点总是插到链表已建好部分的表头前 第二种方式是新结点总是接在链表已建好部分的表尾 第三种方式是按结点中某个成员的顺序规则创建一个有序的链表 例如现在要建立一个学生信息链表 该链表的结点类型定义如下 structnode intnum floatscore structnode next 该结点类型名称为structnode 它包含两个数据域成员 num 学号 和score 分数 和一个地址域成员 next 下面给出了用三种方法创建学生信息表的三个函数 三个函数的共同点是 它们都是用循环结构实现创建过程 并约定当输入某个学生的学号为0时 结束循环即结束创建链表 用头插入法建立链表 即新结点总是插在最前面 structnode create1 structnode head NULL p floatf while 1 p structnode malloc sizeof structnode 申请新结点空间 scanf d 返回链表头指针 10 6 4输出链表 输出链表各结点的值只要知道链表头结点的地址 也就是知道head头指针的值 然后设一个指针p指向第一个结点 输出该结点的数据域数据后使p的指向后移一个结点 继续输出数据并重设p指针 直到p指向空地址为止 使指针p后移的操作可用语句 p p next 实现 因为当前p指向的结点的地址成员p next存储的正是p的后继结点的地址 voidprint structnode head structnode p p head printf Informationoflistasfollows n while p NULL printf d 1f n p num p score p p next 使指针p指向下一结点 printf Finishedprinting n 10 6 5插入结点 插入结点的操作是在链表已经创建成功的情况下进行的 插入结点的函数的参数应包含 结点将要插入的链表的头指针 要插入结点的学号和分数 在指定的学号之后插入该结点 首先要在链表中查找有没有指定的学号 有则在其后插入 没有则在链表的最后面插入 structnode insert structnode head intid intnum floatscore 按指定的学号id之后插入结点 structnode p s p structnode malloc sizeof structnode p num num p score score 参数值赋给结点数据域成员 s head 找插入位置 while s 10 6 6删除结点 删除结点的操作是在链表已经创建成功的情况下进行的 删除结点的函数的参数应包含 结点将要删除的链表的头指针 要删除结点的学号 首先要在链表中查找有没有要删除的学号 有则删除 没有则不用删除 查找链表中具有某特定学号的学生的结点信息并删除它 假设链表头指针用head表示 structnode delnode structnode head intnum structnode p head q if head NULL 空链表不能执行删除操作 printf illegaloperation n returnNULL if head num num 将要被删除的结点是头结点 head p next free p returnhead for q head q next NULL q q next 从第二个结点开始寻找将要被删除的结点 p q next 说明q指向的结点在前 p指向的结点在后 if p num num 找到了 q next p next 删除p指向的结点 使脱离链表 free p 释放p指向的空间 returnhead printf Notfound n 没找到要删除的结点 returnhead 其他链表结构 10 7共用体 共用体的概念与结构体定义相似 但其成员共同占用一段内存 空间分配为其成员中最长的 采用覆盖技术 其成员互相覆盖 这样的数据结构称为 共用体 或称 联合体 显然 对于一个共用体变量 内存中某时刻只存放着其中的一种成员 10 7 1共用体类型和共用体变量的定义 定义方式跟结构体相似 只是在结构体定义中的关键字 struct 用联合关键字 union 来代替 例如 uniondata inti floatf charc 6 共用体变量的定义 先定义类型 再定义变量在定义类型的同时定义变量10 7 2共用体变量的引用跟结构体引用成员的方式相似 共用体体也使用引用符 和指针引用符 来应用变量成员 共用体变量的定义由该类型我们可以像定义结构体变量那样定义联合型变量 指向联合型变量的指针或联合型数组 如 uniondataa b c uniondata pu 需要注意的是 联合体成员每一时刻只有一个起作用 该成员是最近一次对联合体存放的成员 变量不可在定义时初始化 例9 输入一个unsignedlong型整数 写一个函数将这个整数的前两字节与后两个字节进行交换 主函数main 进行验证 uniondata unsignedlongn intb 2 unsignedlongswapbit unsignedlongk uniondatad intt d n k t d b 0 d b 0 d b 1 d b 1 t returnd n main unsignedlongn printf Inputdata scanf lx 10 8枚举类型 实际应用中 有些变量的取值被限定在一个有限的范围内 如代表星期几的变量 只可能是星期日 星期六 性别只可能是男性或女性 逻辑量只能是真或假 有时颜色只要取红黄兰白黑五种 等等 为此 语言提供了一种称为 枚举 的类型 在 枚举 类型的定义中一一列举出所有可能的取值 被说明为该 枚举 类型的变量取值不能超过定义的范围 1 枚举类型的定义枚举类型定义的一般形式enum枚举名 枚举符表列 例 enumBoolean false true enumDay sun mon tue wed thu fri sat enumColor red yellow blue white black enumSex male female 其中枚举符也称为枚举元素 是用户定义的标识符 这些标识符并不自动地代表什么含义 例如 不因为写成sun 就自动代表星期日 2 枚举变量的定义如同结构和联合一样 可先定义枚举类型再定义该类型的变量 也可在定义枚举类型的同时定义该类型的变量 enum枚举名 枚举符表列 enum枚举名变量表 或enum枚举名 枚举符表列 变量表 或enum 枚举符表列 变量表 例 enumDay sun mon tuewed thu fri sat enumDaya b c 或enumDay sun mon tuewed thu fri sat a b c 3 枚举类型变量的赋值和使用 枚举元素是常量 不是变量 不能在程序中用赋值语句再对它赋值 例如 不能对上述枚举Day的元素再作以下赋值 sun 0 mon 1 sun mon 枚举元素作为常量 本身由系统定义了一个表示其序号的数值 从0开始顺序定义为0 1 2 例如 在上述枚举Day中 sun值为0 mon值为1 sat值为6 枚举元素可赋值给变量 如 a sat 则a变量值为1 可以改变枚举元素的值 可在定义时指定 如 enumDay sun 7 mon 1 tuewed thu fri sat 定义sun为7 mon为1 以后顺序加1 sat为6 只能把枚举元素赋给枚举变量 不能把枚举元素相当的数值直接赋给枚举变量 如 正确a sat 错误a 6 如一定要把数值赋给枚举变量 则必须用强制类型转换 如 a enumDay 6 这相当于a sat 枚举值可以应用关系运算 如 if a mon if a sat 10 9定义已有类型的别名 除了可直接使用 提供的标准类型 int char float double 和自定义的类型 结构 共用 枚举 外 也可使用typedef定义已有类型的别名 该别名与标准类型名一样 可用来定义相应的变量 格式 typedef原类型名新类型名用typedef标识符可以定义新的类型名来代替已有的类型名 习惯上新的类型名用大写字母表示 如 typedeffloatREAL 用REAL代替float 则 floata b 与REALa b 等价 如定义NUM为整型数组类型 typedefintNUM 10 则 intn 10 m 10 与NUMn m 等价 如定义STRING为整字符指针类型 typedefchar STRING 则 char p s 10 与STRINGp s 10 等价 如定义POINTER为指向函数的指针类型 typedefint POINTER 则 int p 与POINTERp 等价 如定义NODE为指定的一结构体类型 typedefstructstudent charnum 4 floatscore NODE 则 structstudentst p 与NODEst p 等价
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!