




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、可以看到链表中各元素在内存中可以不是连续存放的。要找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素。如果不提供“头指针”(head),则整个链表都无法访问。链表如同一条铁链一样,一环扣一环,中间是不能断开的。打个通俗的比方:幼儿园的老师带领孩子出来散步,老师牵着第一个小孩的手,第一个小孩的另一只手牵着第二个孩子这就是一个“链”,最后一个孩子有一只手空着,他是“链尾”。要找这个队伍,必须先找到老师,然后顺序找到每一个孩子。可以看到,这种链表的数据结构,必须利用指针变量才能实现。即:一个结点中应包含一个指针变量,用它存放下一结点的地址。第1页/共98页前面介绍了结构体变
2、量,用它作链表中的结点是最合适的。一个结构体变量包含若干成员,这些成员可以是数值类型、字符类型、数组类型,也可以是指针类型。我们用这个指针类型成员来存放下一个结点的地址。例如,可以设计这样一个结构体类型:structstudentintnum; floatscore; structstudentnext;第2页/共98页其中成员num和score用来存放结点中的有用数据(用户需要用到的数据),相当于图11.10结点中的A,B,C,D。next是指针类型的成员,它指向struct student类型数据(这就是next所在的结构体类型)。一个指针类型的成员既可以指向其他类型的结构体数据,也可以指
3、向自己所在的结构体类型的数据。现在,next是struct student类型中的一个成员,它又指向struct student类型的数据。用这种方法就可以建立链表。见图11.11。第3页/共98页图11.11图中每一个结点都属于struct student类型,它的成员next存放下一结点的地址,程序设计人员可以不必具体知道各结点的地址,只要保证将下一个结点的地址放到前一结点的成员next中即可。请注意:上面只是定义了一个struct student类型,并未实际分配存储空间。只有定义了变量才分配内存单元。第4页/共98页1 1 . 7 . 2 简 单 链 表下 面 通 过 一 个 例 子
4、来 说 明 如 何 建 立 和 输 出 一 个 简 单 链 表 。例 1 1 . 7 建 立 一 个 如 图 1 1 . 1 1 所 示 的 简 单 链 表 , 它 由 3 个 学 生 数 据 的 结 点 组 成 。 输 出 各 结 点 中 的 数 据 。 # d e f i n e N U L L 0 s t r u c t s t u d e n t l o n g n u m ; f l o a t s c o r e ; s t r u c t s t u d e n t * n e x t ; ;第5页/共98页 m a i n ( ) s t r u c t s t u d e n
5、 t a , b , c , * h e a d , * p ;a . n u m = 9 9 1 0 1 ; a . s c o r e = 8 9 . 5 ;b . n u m = 9 9 1 0 3 ; b . s c o r e = 9 0 ;c . n u m = 9 9 1 0 7 ; c . s c o r e = 8 5 ; / * 对 结 点 的 n u m 和 s c o r e 成 员 赋 值 * / h e a d = & a ; / * 将 结 点 a 的 起 始 地 址 赋 给 头 指 针 h e a d * / a . n e x t = & b
6、; / * 将 结 点 b 的 起 始 地 址 赋 给 a 结 点 的 n e x t 成 员 * / b . n e x t = & c ; / * 将 结 点 c 的 起 始 地 址 赋 给 b 结 点 的 n e x t 成 员 * /第6页/共98页 c . n e x t = N U L L ; / * c 结 点 的 n e x t 成 员 不 存 放 其 他 结 点 地 址 * / p = h e a d ; / * 使 p 指 针 指 向 a 结 点 * / d o p r i n t f ( % l d % 5 . 1 f n , p - n u m , p - s
7、c o r e ) ; / * 输 出 p 指 向 的 结 点 的 数 据 * / p = p - n e x t ; / * 使 p 指 向 下 一 结 点 * / w h i l e ( p ! = N U L L ) ; / * 输 出 完 c 结 点 后 p 的 值 为 N U L L * / 第7页/共98页各个结点是怎样构成链表的。没有头指针head行不行?p起什么作用?没有它行不行?开始时使head指向a结点,a.next指向b结点,b.next指向c结点,这就构成链表关系。“c.next=NULL” 的作用是使c.next不指向任何有用的存储单元。在输出链表时要借助p,先使p指
8、向a结点,然后输出a结点中的数据,“p=p-next” 是为输出下一个结点做准备。p-next的值是b结点的地址,因此执行“p=p-next”后p就指向b结点,所以在下一次循环时输出的是b结点中的数据。本例是比较简单的,所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为“静态链表”。第8页/共98页11.7.311.7.3处理动态链表所需的函数 库函数提供动态地开辟和释放存储单元的 有关函数:(1)malloc函数 其函数原型为void *malloc(unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的值(即“返
9、回值”)是一个指向分配域起始地址的指针(类型为void)。如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。 第9页/共98页 (2) calloc函数 其函数原型为void *calloc(unsigned , unsigned size);其作用是在内存的动态存储区 中分配个长度为size的连续空间。函数返回 一个指向分配域起始地址的指针;如果分配不 成功,返回NULL。 用calloc函数可以为一维数组开辟动态存 储空间,n为数组元素个数,每个元素长度为 Size。第10页/共98页 (3) free函数 其函数原型为void free(void *p);其作用 是
10、释放由指向的内存区,使这部分内存区能 被其他变量使用。是最近一次调用calloc或 malloc函数时返回的值。free函数无返回值。 以前的版本提供的malloc和calloc函数 得到的是指向字符型数据的指针。 ANSI 提 供的malloc和calloc函数规定为void类型。第11页/共98页11.7.4建立动态链表所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。例11.8写一函数建立一个有3名学生数据的单向动态链表。先考虑实现此要求的算法(见图11.12)。图图11.12第12页/共98页设3个指针变量:he
11、ad、p1、p2,它们都是用来指向struct student类型数据的。先用malloc函数开辟第一个结点,并使p1、p2指向它。然后从键盘读入一个学生的数据给p1所指的第一个结点。我们约定学号不会为零,如果输入的学号为0,则表示建立链表的过程完成,链表为“空”时的head指向DULL(即head不指向任何结点,链表中无结点),以后增加一个结点就使head指向该结点。如果输入的p1-num不等于0,则输入的是第一个结点数据(n=1),令head=p1,即把p1的值赋给head,也就是使head也指向新开辟的结点(图11.13 )。p1所指向的新开辟的结点就成为链表中第一个结点。第13页/共9
12、8页然后再开辟另一个结点并使p1指向它,接着输入该结点的数据(见图11.14(a)。如果输入的p1-num0,则应链入图11.13第2个结点(n=2),由于n1,则将p1的值赋给p2-next,此时p2指向第一个结点,因此执行“p2-next=p1” 就将新结点的地址赋给第一个结点的next成员,使第一个结点的next成员指向第二个结点(见图11.14(b)。接着使p2=p1,也就是使p2指向刚才建立的结点,见图11.14(c)。接着再开辟一个结点并使p1指向它,并输入该结点的数据(见图11.15(a),在第三次循环中,由于n=3(n1),又将p1的值赋给p2-next,也就是将第3个结点连接
13、到第2个结点之后,并使p2=p1,使p2指向最后一个结点(见图11.15(b)。第14页/共98页图图11.13第15页/共98页图图11.14第16页/共98页图图11.15第17页/共98页再开辟一个新结点,并使p1指向它,输入该结点的数据(见图11.16(a)。由于p1-num的值为0,不再执行循环,此新结点不应被连接到链表中。此时将NULL赋给p2-next,见图11.16(b)。建立链表过程至此结束,p1最后所指的结点未链入链表中,第3个结点的next成员的值为NULL,它不指向任何结点。虽然p1指向新开辟的结点,但从链表中无法找到该结点。第18页/共98页图图11.16第19页/共
14、98页 建 立 链 表 的 函 数 可 以 如 下 : # d e f i n e N U L L 0 # d e f i n e L E N s i e o f ( s t r u c t s t u d e n t ) s t r u c t s t u d e n t l o n g n u m ; f l o a t s c o r e ; s t r u c t s t u d e n t n e x t ; ; i n t n ; / * n 为 全 局 变 量 , 本 模 块 中 各 函 数 均 可 使 用 它 * /第20页/共98页 s t r u c t s t u d e
15、 n t * c r e a t ( v o i d ) / * 定 义 函 数 。 此 函 数 带 回 一 个 指 向 链 表 头 的 指 针 * / s t r u c t s t u d e n t h e a d ; s t r u c t s t u d e n t p 1 , * p 2 ; n = 0 ;p 1 = p 2 = ( s t r u c t s t u d e n t * ) m a l l o c ( L E N ) ; / * 开 辟 一 个 新 单 元 * / s c a n f ( % l d , % f , & p 1 - n u m , &
16、; p 1 - s c o r e ) ; h e a d = N U L L ; w h i l e ( p 1 - n u m ! = 0 )第21页/共98页 n = n + 1 ; i f ( n = = 1 ) h e a d = p 1 ; e l s e p 2 - n e x t = p 1 ; p 2 = p 1 ; p 1 = ( s t r u c t s t u d e n t ) m a l l o c ( L E N ) ; s c a n f ( % l d , % f , & p 1 - n u m , & p 1 - s c o r e ) ;
17、 p 2 - n e x t = N U L L ; r e t u r n ( h e a d ) ; 第22页/共98页函 数 首 部 在 括 弧 内 写 v o i d , 表 示 本 函 数 没 有 形 参 , 不 需 要 进 行 数 据 传 递 。 可 以 在 m a i n 函 数 中 调 用 c r e a t 函 数 : m a i n ( ) c r e a t ( ) ; / * 调 用 c r e a t 函 数 后 建 立 了 一 个 单 向 动 态 链 表 * / 调 用 c r e a t 函 数 后 , 函 数 的 值 是 所 建 立 的 链 表 的 第 一 个
18、结 点 的 地 址 ( 请 查 看 r e t u r n 语 句 ) 。第23页/共98页请 注 意 :(1) 第1行为#define命令行,令NULL代表0,用它表示“空地址”。第2行令LEN代表struct student类型数据的长度,sieof是“求字节数运算符”。(2) 第9行定义一个creat函数,它是指针类型,即此函数带回一个指针值,它指向一个struct student类型数据。实际上此creat函数带回一个链表起始地址。(3) malloc(LEN)的作用是开辟一个长度为LEN的内存区,LEN已定义为sieof(struct student),即结构体struct stud
19、ent的长度。malloc带回的是第24页/共98页不指向任何类型数据的指针(void *类型)。而p1、p2是指向struct student类型数据的指针变量,因此必须用强制类型转换的方法使指针的基类型改变为struct student类型,在malloc(LEN)之前加了“(struct student *)”,它的作用是使malloc返回的指针转换为指向struct student类型数据的指针。注意“*”号不可省略,否则变成转换成struct student类型了,而不是指针类型了。(4) 最后一行return后面的参数是head(head已定义为指针变量,指向struct stud
20、ent类型数据)。因此函数返回的是head的值,也就是链表的头地址。第25页/共98页( 5 ) n 是 结 点 个 数 。( 6 ) 这 个 算 法 的 思 路 是 让 p 1 指 向 新 开 的 结 点 , p 2 指 向 链 表 中 最 后 一 个 结 点 , 把 p 1 所 指 的 结 点 连 接 在 p 2 所 指 的 结 点 后 面 , 用 “ p 2 - n e x t = p 1 ” 来 实 现 。我 们 对 建 立 链 表 过 程 做 了 比 较 详 细 的 介 绍 , 读 者 如 果 对 建 立 链 表 的 过 程 比 较 清 楚 的 话 , 对 下 面 介 绍 的 删 除
21、 和 插 入 过 程 也 就 比 较 容 易 理 解 了 。1 1 . 7 . 5 输 出 链 表将 链 表 中 各 结 点 的 数 据 依 次 输 出 。 这 个 问 题 比 较 容 易 处 理 。 例 1 1 . 7 中 已 初 步 介 绍 了 输 出 链 表 的 方 法 。 首 先 要 知 道 链 表 第 一 个 结 点 的 地 址 , 也 就 是 要第26页/共98页知 道 h e a d 的 值 。 然 后 设 一 个 指 针 变 量 p , 先 指 向 第 一 个 结 点 , 输 出 p 所 指 的 结 点 , 然 后 使 p 后 移 一 个 结 点 , 再 输 出 。 直 到 链
22、 表 的 尾 结 点 。例 1 1 . 9 编 写 一 个 输 出 链 表 的 函 数 p r i n t 。 v o i d p r i n t ( s t r u c t s t u d e n t * h e a d ) s t r u c t s t u d e n t * p ; p r i n t f ( n N o w , T h e s e % d r e c o r d s a r e : n , n ) ; p = h e a d ; i f ( h e a d ! = N U L L ) d o第27页/共98页 p r i n t f ( % l d % 5 . 1 f
23、 n , p - n u m , p - s c o r e ) ; p = p - n e x t ; w h i l e ( p ! = N U L L ) ; 算 法 可 用 图 1 1 . 1 7 表 示 。其 过 程 可 用 图 1 1 . 1 8 表 示 。 p 先 指 向 第 一 结 点 , 在 输 出 完 第 一 个 结 点 之 后 , p 移 到 图 中 p 虚 线 位 置 , 指 向 第 二 个 结 点 。 程 序 中 p = p - n e x t 的 作 用 是 将 p 原 来 所 指 向 的 结 点中 n e x t 的 值 赋 给 p , 而 p - n e x t
24、 的 值 就 是 第 二 个 结 点 的 起 始 地 址 。 将 它 赋 给 p , 就 是 使 p 指 向 第 二 个 结 点 。第28页/共98页图图11.17图图11.18第29页/共98页h e a d 的 值 由 实 参 传 过 来 , 也 就 是 将 已 有 的 链 表 的 头 指 针 传 给 被 调 用 的 函 数 , 在 p r i n t 函 数 中 从 h e a d 所 指 的 第 一 个 结 点 出 发 顺 序 输 出 各 个 结 点 。1 1 . 7 . 6 对 链 表 的 删 除 操 作已 有 一 个 链 表 , 希 望 删 除 其 中 某 个 结 点 。 怎 样
25、考 虑 此 问 题 的 算 法 呢 ? 先 打 个 比 方 : 一 队 小 孩 ( A 、 B 、 C 、 D 、 E ) 手 拉 手 , 如 果 某 一 小 孩 ( C ) 想 离 队 有 事 , 而 队 形 仍 保 持 不 变 。只 要 将 C 的 手 从 两 边 脱 开 , B 改 为 与 D 拉 手 即 可 , 见 图 1 1 . 1 9 。 图 1 1 . 1 9 ( a ) 是 原 来 的 队 伍 , 图 1 1 . 1 9 ( b ) 是 C 离 队 后 的 队 伍 。第30页/共98页图图11.1911.19第31页/共98页与 此 相 仿 , 从 一 个 动 态 链 表 中
26、删 去 一 个 结 点 , 并 不 是 真 正 从 内 存 中 把 它 抹 掉 , 而 是 把 它 从 链 表 中 分 离 开 来 , 只 要 撤 消 原 来 的 链 接 关 系 即 可 。例 1 1 . 1 0 写 一 函 数 以 删 除 动 态 链 表 中 指 定 的 结 点 。以 指 定 的 学 号 作 为 删 除 结 点 的 标 志 。 例 如 , 输 入 9 9 1 0 3 表 示 要 求 删 除 学 号 为 9 9 1 0 3 的 结 点 。 解 题 的 思 路 是 这 样 的 : 从 p 指 向 的 第 一 个 结 点 开 始 , 检 查 该 结 点 中 的 n u m 值是 否
27、 等 于 输 入 的 要 求 删 除 的 那 个 学 号 。 如 果 相 等 就 将 该 结 点 删 除 , 如 不 相 等 , 就 将 p 后 移 一 个 结 点 , 再 如 此 进 行 下 去 , 直 到 遇 到 表 尾 为 止 。第32页/共98页图图11.20第33页/共98页可以设两个指针变量p1和p2,先使p1指向第一个结点(图11.20(a)。如果要删除的不是第一个结点,则使p1后指向下一个结点(将p1-next赋给p1),在此之前应将p1的值赋给p2,使p2指向刚才检查过的那个结点,见图11.20(b)。如此一次一次地使p后移,直到找到所要删除的结点或检查完全部链表都找不到要删
28、除的结点为止。如果找到某一结点是要删除的结点,还要区分两种情况:要删的是第一个结点(p1的值等于head的值,如图11.20(a)那样),则应将p1-next赋给head。见图11.20(c)。这时head指向原来的第二个结点。第一个结点虽然仍存在,但它已与链表脱离,因为链表中没有一个结点或头指针指向它。虽然p1还指向它,它仍指向第二个结点,第34页/共98页但仍无济于事,现在链表的第一个结点是原来的第二个结点,原来第一个结点已“丢失” ,即不再是链表中的一部分了。 如果要删除的不是第一个结点,则将p1-next赋给p2-next,见图11.20(d)。p2-next原来指向p1指向的结点(图
29、中第二个结点),现在p2-next改为指向p1-next所指向的结点(图中第三个结点)。p1所指向的结点不再是链表的一部分。还需要考虑链表是毡?无结点)和链表中找不到要删除的结点的情况。图11.21表示解此题的算法。第35页/共98页图11.21第36页/共98页删 除 结 点 的 函 数 d e l 如 下 : s t r u c t s t u d e n t d e l ( s t r u c t s t u d e n t * h e a d , l o n g n u m ) s t r u c t s t u d e n t * p 1 , * p 2 ; i f ( h e a
30、d = = N U L L ) p r i n t f ( n l i s t n u l l ! n ) ; r e t u r n ( h e a d ) ; p 1 = h e a d ; w h i l e ( n u m ! = p 1 - n u m & & p 1 - n e x t ! = = N U L L ) / * p 1 指 向 的 不 是 所 要 找 的 结 点 , 并 且 后 面 还 有 结 点 / p 2 = p 1 ; p 1 = p 1 - n e x t ; / p 1 后 移 一 个 结 点 * /第37页/共98页 i f ( n u m
31、 = = p 1 - n u m ) / 找 到 了 * / i f ( p 1 = = h e a d ) h e a d = p 1 - n e x t ; / 若 p 1 指 向 的 是 首 结 点 , 把 第 二 个 结 点 地 址 赋 予 h e a d / e l s e p 2 - n e x t = p 1 - n e x t ; / * 否 则 将 下 一 结 点 地 址 赋 给 前 一 结 点 地 址 * / p r i n t f ( d e l e t e : % l d n , n u m ) ; n = n - 1 ; e l s e p r i n t f ( %
32、 l d n o t b e e n f o u n d ! n , n u m ) ; / 找 不 到 该 结 点 / 第38页/共98页 return(head); 函数的类型是指向struct student类型数据的指针,它的值是链表的头指针。函数参数为head和要删除的学号num。head的值可能在函数执行过程中被改变(当删除第一个结点时)。第39页/共98页11.7.7对链表的插入操作对链表的插入是指将一个结点插入到一个已有的链表中。若已有一个学生链表,各结点是按其成员项num(学号)的值由小到大顺序排列的。今要插入一个新生的结点,要求按学号的顺序插入。为了能做到正确插入,必须解决
33、两个问题: 怎样找到插入的位置; 怎样实现插入。如果有一群小学生,按身高顺序(由低到高)手拉手排好队。现在来了一名新同学,要求按身高顺序插入队中。首先要确定插到什么位置。可以将新同学先与队中第1名小学生比身高,若新同学比第1名学生高,就使新同学后移一个位置,与第2名学生比,如果仍比第2名学生高,再往后移,与第3名学生比直到出现比第40页/共98页第i名学生高,比第i+1名学生低的情况为止。显然,新同学的位置应该在第i名学生之后,在第i+1名学生之前。在确定了位置之后,让第i名学生与第i+1名学生的手脱开,然后让第i名学生的手去拉新同学的手,让新同学另外一只手去拉第i+1名学生的手。这样就完成了
34、插入,形成了新的队列。根据这个思路来实现链表的插入操作。先用指针变量p0指向待插入的结点,p1指向第一个结点。见图11.22(a)。将p0-num与p1-num相比较,如果p0-nump1-num,则待插入的结点不应插在p1所指的结点之前。此时将p1后移,并使p2指向刚才p1所指的结点,见图11.22(b)。再将p1-num与p0-num比。如果仍然是p0-num大,则应使p1继续后移,直到第41页/共98页p0-nump1-num为止。这时将p0所指的结点插到p1所指结点之前。但是如果p1所指的已是表尾结点,则p1就不应后移了。如果p0-num比所有结点的num都大,则应将p0所指的结点插到
35、链表末尾。如果插入的位置既不在第一个结点之前,又不在表尾结点之后,则将p0的值赋给p2-next,使p2-next指向待插入的结点,然后将p1的值赋给p0-next,使得p0-next指向p1指向的变量。见图11.22(c)。可以看到,在第一个结点和第二个结点之间已插入了一个新的结点。如果插入位置为第一个结点之前(即p1等于head时),则将p0赋给head,将p1赋给p0-next。见图第42页/共98页11.22(d)。如果要插到表尾之后,应将p0赋给p1-next,NULL赋给p0-next,见图11.22(e)。以上算法可用图11.23表示。第43页/共98页图图11.2211.22第
36、44页/共98页图图11.2311.23第45页/共98页例 1 1 . 1 1 插 入 结 点 的 函 数 i n s e r t 如 下 。s t r u c t s t u d e n t * i n s e r t ( s t r u c t s t u d e n t * h e a d , s t r u c t s t u d e n t * s t u d ) s t r u c t s t u d e n t * p 0 , * p 1 , * p 2 ;p 1 = h e a d ; / 使 p 1 指 向 第 一 个 结 点 /p 0 = s t u d ; / p 0
37、指 向 要 插 入 的 结 点 /i f ( h e a d = = N U L L ) / 原 来 的 链 表 是 空 表 / h e a d = p 0 ; p 0 - n e x t = N U L L ; / * 使 p 0 指 向 的 结 点 作 为 头 结 点 * /e l s e第46页/共98页 w h i l e ( ( p 0 - n u m p 1 - n u m ) & & ( p 1 - n e x t ! = N U L L ) ) p 2 = p 1 ; / * 使 p 2 指 向 刚 才 p 1 指 向 的 结 点 * /p 1 = p 1 -
38、n e x t ; / * p 1 后 移 一 个 结 点 * /i f ( p 0 - n u m p 1 - n u m ) i f ( h e a d = = p 1 ) h e a d = p 0 ; / 插 到 原 来 第 一 个 结 点 之 前 * / e l s e p 2 - n e x t = p 0 ; / 插 到 p 2 指 向 的 结 点 之 后 * / p 0 - n e x t = p 1 ; 第47页/共98页elsep1-next=p0; p0-next=NULL;/*插到最后的结点之后*/ n=n+1; /结点数加1*/ return(head); 函数参数是
39、head和stud。stud也是一个指针变量,从实参传来待插入结点的地址给stud。语句p0=stud的作用是使p0指向待插入的结点。函数类型是指针类型,函数值是链表起始地址head。第48页/共98页1 1 . 7 . 8 对 链 表 的 综 合 操 作将 以 上 建 立 、 输 出 、 删 除 、 插 入 的 函 数 组 织 在 一 个 C 程 序 中 , 即 将 例 1 1 . 8 1 1 . 1 1 中 的 4 个 函 数 顺 序 排 列 , 用 m a i n 函 数 作 主 调 函 数 。 可 以 写 出 以 下 m a i n 函 数 ( m a i n 函 数 的位 置 在 以
40、 上 各 函 数 的 后 面 ) 。m a i n ( ) s t r u c t s t u d e n t * h e a d , s t u ; l o n g d e l - n u m ; p r i n t f ( i n p u t r e c o r d s : n ) ; h e a d = c r e a t ( ) ; / 返 回 头 指 针 * /第49页/共98页 print(head); /输出全部结点*/ printf(ninput the deleted number:); scanf(%ld,&del-num); /输入要删除的学号*/ head=de
41、l(head,del-num); /删除后链表的头地址/ print(head); /输出全部结点*/ printf(ninput the inserted record:); /输入要插入的结点*/第50页/共98页 scanf(%ld,%f,&stunum,&stuscore); head=insert(head,&stu); /返回地址/ print(head);/*输出全部结点*/此程序运行结果是正确的。它只删除一个结点,插入一个结点。但如果想再插入一个结点,重复写上程序最后4行,共插入两个结点。运行结果却是错误的。运行结果如下:第51页/共98页i n p u
42、 t r e c o r d s : ( 建 立 链 表 ) 9 9 1 0 1 , 9 0 9 9 1 0 3 , 9 8 9 9 1 0 5 7 6 0 , 0 N o w , T h e s e 3 r e c o r d s a r e : 9 9 1 0 1 9 0 0 9 9 1 0 3 9 8 0 9 9 1 0 5 7 6 0 i n p u t t h e d e l e t e d n u m b e r : 9 9 1 0 3 ( 删 除 ) d e l e t e : 9 9 1 0 3第52页/共98页 N o w , T h e s e 2 r e c o r d
43、s a r e : 9 9 1 0 1 9 0 0 9 9 1 0 5 7 6 0 i n p u t t h e i n s e r t e d r e c o r d : 9 9 1 0 2 , 9 0 ( 插 入 第 一 个 结 点 ) N o w , T h e s e 3 r e c o r d s a r e : 9 9 1 0 1 9 0 0 9 9 1 0 2 9 0 0 9 9 1 0 5 7 6 0 i n p u t t h e i n s e r t e d r e c o r d : 8 9 1 0 4 , 9 9 ( 插 入 第 二 个 结 点 )第53页/共98页
44、 N o w , T h e s e 4 r e c o r d s a r e : 9 9 1 0 1 9 0 0 9 9 1 0 4 9 9 0 9 9 1 0 4 9 9 0 9 9 1 0 4 9 9 0 ( 无 终 止 地 输 出 9 9 1 0 4 的 结 点 数 据 )出 现 以 上 结 果 的 原 因 是 s t u 是 一 个 有 固 定 地 址 的 结 构 体 变 量 。 第 一 次 把 s t u 结 点 插 入 到 链 表 中 。 第 二 次 若 再 用 它 来 插 入 第 二 个 结 点 , 就 把 第 一 次 结 点 的 数 据 冲 掉 了 。 实 际 上 并 没
45、有 开 辟 两 个 结 点 。m a i n 函 数 如 下 :第54页/共98页 m a i n ( ) s t r u c t s t u d e n t * h e a d , * s t u ; l o n g d e l - n u m ; p r i n t f ( i n p u t r e c o r d s : n ) ; h e a d = c r e a t ( ) ; p r i n t ( h e a d ) ; p r i n t f ( n i n p u t t h e d e l e t e d n u m b e r : ) ; s c a n f ( %
46、l d , & d e l - n u m ) ; w h i l e ( d e l - n u m ! = 0 ) h e a d = d e l ( h e a d , d e l - n u m ) ; p r i n t ( h e a d ) ;第55页/共98页 p r i n t f ( i n p u t t h e d e l e t e d n u m b e r : ) ; s c a n f ( % l d , & d e l - n u m ) ; p r i n t f ( n i n p u t t h e i n s e r t e d r e
47、 c o r d : ) ; s t u = ( s t r u c t s t u d e n t ) m a l l o c ( L E N ) ; s c a n f ( % l d , % f , & s t u - n u m , & s t u - s c o r e ) ; w h i l e ( s t u - n u m ! = 0 ) h e a d = i n s e r t ( h e a d , s t u ) ; p r i n t ( h e a d ) ; p r i n t f ( i n p u t t h e i n s e r t e d
48、 r e c o r d : ) ;第56页/共98页 s t u = ( s t r u c t s t u d e n t ) m a l l o c ( L E N ) ; s c a n f ( % l d , % f , & s t u - n u m , & s t u - s c o r e ) ; s t u 定 义 为 指 针 变 量 , 在 需 要 插 入 时 先 用 m a l l o c 函 数 开 辟 一 个 内 存 区 , 将 其 起 始 地 址 经 强 制 类 型 转 换 后 赋 给 s t u , 然 后 输 入 此 结 构 体 变 量 中 各
49、成 员 的 值 。 对 不 同 的 插 入 对象 , s t u 的 值 是 不 同 的 , 每 次 指 向 一 个 新 的 s t r u c t s t u d e n t 变 量 。 在 调 用 i n s e r t 函 数 时 , 实 参 为 h e a d 和 s t u , 将 已 建 立 的 链 表 起 始 地 址 传 给 i n s e r t 函 数 的 形 参 , 将s t u ( 即 新 开 辟 的 单 元第57页/共98页 的 地 址 ) 传 给 形 参 s t u d , 返 回 的 函 数 值 是 经 过 插 入 之 后 的 链 表 的 头 指 针 ( 地 址 )
50、 。运 行 情 况 如 下 :i n p u t r e c o r d s : 9 9 1 0 1 , 9 9 9 9 1 0 3 , 8 7 9 9 1 0 5 , 7 7 0 , 0 N o w , T h e s e 3 r e c o r d s a r e : 9 9 1 0 1 9 9 0第58页/共98页 9 9 1 0 3 8 7 0 9 9 1 0 5 7 7 0 i n p u t t h e d e l e t e d n u m b e r : 9 9 1 0 3 d e l e t e : 9 9 1 0 3 N o w , t h e s e 2 r e c o
51、r d s a r e : 9 9 1 0 1 9 9 0 9 9 1 0 5 7 7 0 i n p u t t h e d e l e t e d n u m b e r : 9 9 1 0 5 d e l e t e : 9 9 1 0 5 N o w , T h e s e 1 r e c o r d s a r e :9 9 1 0 1 9 9 0第59页/共98页 i n p u t t h e d e l e t e d n u m b e r : 0 i n p u t t h e i n s e r t e d r e c o r d : 9 9 1 0 4 , 8 7 N
52、o w , T h e s e 2 r e c o r d s a r e : 9 9 1 0 1 9 9 09 9 1 0 4 8 7 0 i n p u t t h e i n s e r t e d r e c o r d : 9 9 1 0 6 , 6 5 N o w , T h e s e 3 r e c o r d s a r e : 9 9 1 0 1 9 9 0 9 9 1 0 4 8 7 09 9 1 0 6 6 5 0 i n p u t t h e i n s e r t e d r e c o r d : 0 , 0第60页/共98页11.8共用体 11.8.1共用体的
53、概念有时需要使几种不同类型的变量存放到同一段内存单元中。例如,可把一个整型变量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中(见图11.24)。以上3个变量在内存中占的字节数不同,但都从同一地址开始(图中设地址为1000)存放。也就是使用覆盖技术,几个变量互相覆盖。这种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。第61页/共98页定义共用体类型变量的一般形式为union共用体名图图11.24第62页/共98页 成 员 表 列 变 量 表 列 ;例 如 :u n i o n d a t a i n t i ; c h a r c h ; f l o a t f
54、; a , b , c ;第63页/共98页 也 可 以 将 类 型 声 明 与 变 量 定 义 分 开 :u n i o n d a t a i n t i ; c h a r c h ; f l o a t f ; ; u n i o n d a t a a , b , c ;即 先 声 明 一 个 u n i o n d a t a 类 型 , 再 将 a 、 b 、 c 定 义 为 u n i o n d a t a 类 型 。 当 然 也 可 以 直 接 定 义 共 用 体 变 量 , 如 :第64页/共98页u n i o n i n t i ; c h a r c h ; f l
55、 o a t f ; a , b , c ;可 以 看 到 , “ 共 用 体 ” 与 “ 结 构 体 ” 的 定 义 形 式 相 似 。 但 它 们 的 含 义 是 不 同 的 。结 构 体 变 量 所 占 内 存 长 度 是 各 成 员 占 的 内 存 长 度 之 和 。 每 个 成 员 分 别 占 有 其 自 己 的 内 存 单 元 。有 些 C 变 量 所 占 的 内 存 长 度 等 于 最 长 的 成 员 的 长 度 。 例 如 , 上 面 定 义 的 “ 共 用 体 ” 变 量 a 、 b 、 c 各 占 4 个 字 节 ( 因 为 一 个 实 型 变 量 占 4 个 字 节 )
56、, 而 不 是 各 占 2 + 1 + 4 = 7 个 字 节 。第65页/共98页1 1 . 8 . 2 共 用 体 变 量 的 引 用 方 式只 有 先 定 义 了 共 用 体 变 量 才 能 引 用 它 。 而 且 不 能 引 用 共 用 体 变 量 , 而 只 能 引 用 共 用 体 变 量 中 的 成 员 。 例 如 , 前 面 定 义 了 a 、 b 、 c 为 共 用 体 变 量 , 下 面 的 引 用 方 式 是 正 确 的 :a i ( 引 用 共 用 体 变 量 中 的 类 型 变 量 i )a c h ( 引 用 共 用 体 变 量 中 的 字 符 变 量 c h )a
57、f ( 引 用 共 用 体 变 量 中 的 实 型 变 量 f )不 能 只 引 用 共 用 体 变 量 , 例 如 :p r i n t f ( % d , a )是 错 误 的 , a 的 存 储 区 有 好 几 种 类 型 , 分 别 占 不 同 长 度 的 存 储 区 , 仅 写 共 用 体 变 量 名 a , 难 以 使 系 统第66页/共98页确定究竟输出的是哪一个成员的值。应该写成printf(%d,ai)或printf(%c,ach)等。11.8.3共用体类型数据的特点在使用共用体类型数据时要注意以下一些特点:(1) 同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能
58、存放其中一种,而不是同时存放几种。也就是说,每一瞬时只有一个成员起作用,其他的成员不起作用,即不是同时都存在和起作用。(2) 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用。如有以下赋值语句:第67页/共98页a i = 1 ;a c = a ;a f = 1 5 ;在 完 成 以 上 3 个 赋 值 运 算 以 后 , 只 有 a f 是 有 效 的 , a i 和 a c 已 经 无 意 义 了 。 此 时 用 p r i n t f ( % d , a i ) 是 不 行 的 , 而 用 p r i n t f ( % f , a f ) 是 可
59、以 的 , 因 为 最 后 一次 的 赋 值 是 向 a f 赋 值 。 因 此 在 引 用 共 用 体 变 量 时 应 十 分 注 意 当 前 存 放 在 共 用 体 变 量 中 的 究 竟 是 哪 个 成 员 。( 3 ) 共 用 体 变 量 的 地 址 和 它 的 各 成 员 的 地 址 都 是 同 一 地 址 。 例 如 : & a 、 & a i 、 & a c 、 & a f 都 是 同 一 地 址 值 , 其 原 因 是 显 然 的 。第68页/共98页( 4 ) 不 能 对 共 用 体 变 量 名 赋 值 , 也 不 能 企 图 引 用 变 量
60、名 来 得 到 一 个 值 , 又 不 能 在 定 义 共 用 体 变 量 时 对 它 初 始 化 。 例 如 , 下 面 这 些 都 是 不 对 的 : u n i o n i n t i ; c h a r c h ; f l o a t f ; a = 1 , a , 1 5 ; ( 不 能 初 始 化 ) a = 1 ; ( 不 能 对 共 用 体 变 量 赋 值 ) m = a ; ( 不 能 引 用 共 用 体 变 量 名 以 得 到 一 个 值 )第69页/共98页(5) 不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针(与结构体变量这种用法相仿)。(6) 共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。例11.12设有若干个人员的数据,其中有学生和教师。学生的数据
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 助理广告师考试消费市场趋势分析试题及答案
- 太原社区面试题及答案
- 全科医学试题及答案详解
- 地理西亚测试题及答案
- 2024年国际商业设计师考试备考要点试题及答案
- 助理广告师考试数据分析基础试题及答案
- c语言测试试题及答案
- 商业设计师考试全新试题及答案揭晓
- 2024年职称考试纺织品检验问答试题及答案
- 破解国际商业美术设计师考试难题试题及答案
- 数字贸易学 课件 第1章 导论
- 广东省省级政务信息化(2024年第一批)项目需求-广东省财政厅业务系统运维运营服务(2024年)项目
- 寄拍行业分析
- 培训地坪漆课件
- 搪瓷制品的艺术创作与文化创意
- 江苏开放大学2024年春《毛泽东思想和中国特色社会主义理论体系概论060878》实践作业参考答案
- 标书中人员配备方案
- 蛇咬伤的快速应急方法
- 采购管理教学第9讲采购环境与供应市场分析课件
- 宁夏回族自治区劳动合同(官方范本)
- 220kv交流输电线路金具技术规范书
评论
0/150
提交评论