第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型

Slides:



Advertisements
Similar presentations
电子成绩单项目实现.
Advertisements

第三章 鏈結串列 Linked List.
C语言基础——指针的高级应用 Week 05.
数据结构与算法 数据结构与算法实验
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
Linked List Operations
單向鏈結串列 Singly Linked Lists.
第2章 线性表 线性结构 是一个数据元素的有序集合。.
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
内容提要 对象的生命周期 构造函数 析构函数 拷贝构造函数. 常宝宝 北京大学计算机科学与技术系
佇列 (Queue).
计算概论 第二十一讲 文件操作 北京大学信息学院.
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
If … else 選擇結構 P27.
结构体和共用体 2 梁春燕 华电信息管理教研室.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
第十一章 文件 文件概述 文件操作 文件操作实例 本章小结 作业: 练习:
Introduction to the C Programming Language
Introduction to the C Programming Language
STRUCTURE 授課:ANT 日期:2010/5/12.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
C语言程序设计 李祥.
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针
Introduction to the C Programming Language
作弊是否很有诱惑性? 上堂课已经讲了 作业不一定在两个小时里都能完成 答疑没有一个人? 作弊是有记录的 心理系很多同学集体作弊,让人震惊
THE C PROGRAMMING LANGUAGE
C++语言程序设计 第二章 C++简单程序设计.
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
第八章 使用指针.
第十章 指针.
第5讲 结构化程序设计(Part II) 周水庚 2018年10月11日.
Struct結構 迴圈
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
自我參考結構 (self-reference – 1)
C语言程序设计.
第十章 用户自定义数据类型 目录 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组
OOP6 結構Struct 黃兆武.
目录 9.1 结构体类型 9.2 共用体类型 9.3 枚举类型 9.4 类型声明符typedef 1.
第十章 结构体与链表 西安工程大学.
C语言概述 第一章.
C语言复习3----指针.
浙江长征职业技术学院—计算机与信息技术系—相方莉制作
指標
輸出與輸入(I/O).
本教學投影片係屬教科書著作之延伸,亦受著作權法之保護。
第三章 数据抽象.
C程序设计.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
Introduction to the C Programming Language
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
第18讲 从C到C++ 计算机与通信工程学院.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
第一次上機考參考答案 僅供參考,同學可自行再想更好的方法..
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
安排座位.
C语言基础学习 从外行到入门.
Presentation transcript:

第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型 第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型 学习方法建议:   结合第二章的数据类型,了解属于构造类型的结构体类型、共用体类型、枚举类型,比较它们的相同点和区别,通过例题掌握这些数据类型的定义和使用,并在此基础上掌握链表的应用。本章的难点是链表的应用。

10.1 引例 1.问题描述——构建手机通讯录 众所周知,手机中有一个简单的通讯录工具,用于管理联系人的基本信息,其基本功能包括对联系人信息的新建、修改、删除和查询等。 2.引例分析 要想构建手机通讯录,应创建联系人的基本信息,而联系人的基本信息应该包括姓名、年龄和联系电话等,假设通讯录最多容纳50名联系人的信息,建立一个数组friends,数组的大小为50,每一个数组元素都应存放姓名、年龄和联系电话等信息。

3.程序代码 #include<stdio.h> #include<string.h> struct friend_list /*手机通讯录结构体定义*/ { char name[10]; /*姓名*/ int age ; /*年龄*/ char telephone[13]; /*联系电话*/ }; main() { int choice; char name[10]; struct friend_list friends[50]; /*包含50个人的通讯录*/ do{ printf("手机通讯录功能选项:1:新建 2:修改 3:删除 4:查询0:退出\n"); printf( "请选择功能:"); scanf( "%d",&choice) ;

switch(choice) { case 1: printf("新建联系人姓名:"); ; /* new_friend(friends); */ break; case 2: printf("请输入要修改的联系人姓名:"); scanf("%s",name); ; /* modify_friend(friends,name); */ case 3: printf("请输入要删除的联系人姓名:"); ; /* delete_friend(friends,name); */ case 4: printf("请输入要查询的联系人姓名:"); ; /* search_friend(friends,name); */ case 0:break; } }while(choice!=0); printf("谢谢使用通信录功能!\n"); }

10.2 结构体类型及其变量 10.2.1 结构体类型与结构体变量的定义 结构体是一种构造数据类型 10.2 结构体类型及其变量 10.2.1 结构体类型与结构体变量的定义 结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体-------自定义数据类型 1. 结构体类型定义 合法标识符 可省:无名结构体 struct 结构体名 { 类型标识符 成员名; ……………. }; 成员类型可以是 基本型或构造型 struct是关键字, 不能省略

… ….. 例 struct student { int num; char name[20]; char sex; int age; score addr 2字节 20字节 1字节 4字节 30字节 … ….. 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } ; 结构体类型定义描述结构 的组织形式,不分配内存 结构体类型定义的作用域

2.2 结构体类型变量定义 先定义结构体类型,再定义结构体变量 一般形式: 例 #define STUDENT struct student { 类型标识符 成员名; ……………. }; struct 结构体名 变量名表列; 例 #define STUDENT struct student STUDENT { int num; char name[20]; char sex; int age; float score; char addr[30]; }; STUDENT stu1,stu2; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu1,stu2; 用宏定义一个符号常量来表示一个结构体类型名

定义结构体类型的同时定义结构体变量 一般形式: 例 struct student { int num; char name[20]; 类型标识符 成员名; ……………. }变量名表列; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;

直接定义结构体变量 一般形式: 例 struct { int num; char name[20]; char sex; int age; 用无名结构体直接定义 变量只能一次 struct { 类型标识符 成员名; ……………. }变量名表列; 例 struct { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;

说明 结构体类型与结构体变量概念不同 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体可嵌套 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体可嵌套 结构体成员名与程序中变量名可相同,不会混淆 结构体类型及变量的作用域与生存期 例 struct date { int month; int day; int year; }; struct student { int num; char name[20]; struct date birthday; }stu; num name birthday month day year 例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu; num name birthday month day year

10.2.2 结构体变量的引用与初始化 引用规则 引用方式: 结构体变量名.成员名 结构体变量不能整体引用,只能引用变量成员 引用方式: 结构体变量名.成员名 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu1.num=10; stu1.score=85.5; stu1.score+=stu2.score; stu1.age++; 可以将一个结构体变量赋值给另一个结构体变量 结构体嵌套时逐级引用 成员(分量)运算符 优先级: 1 结合性:从左向右 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; printf(“%d,%s,%c,%d,%f,%s\n”,stu1); () stu1={101,“Wan Lin”,‘M’,19,87.5,“DaLian”}; () 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; if(stu1==stu2) …….. () 例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu1,stu2; num name birthday month day year stu1.birthday.month=12; 例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu2=stu1; ( )

【例10.2】 利用例10.1中定义的结构体类型struct std_info,定义一个结构体变量student,用于存储和显示一个学生的基本情况。 #include"stdio.h" struct date /*定义并初始化一个外部结构体变量student */ { int year; int month; int day; }; struct std_info { char no[7]; char name[9]; char sex[3]; struct date birthday; struct std_info student={"000102","张三","男",{1980,9,20}};

main() { printf("No: %s\n",student.no); /*引用student中的no成员项*/ printf("Name: %s\n",student.name); /*引用student中的name成员项*/ printf("Sex: %s\n",student.sex); /*引用student中的sex成员项*/ printf("Birthday: "); printf("%d- ", student.birthday.year); /*引用student中birthday的year成员项*/ printf("%d- ",student.birthday.month); /*引用birthday的month成员项*/ printf("%d\n", student.birthday.day); /*引用student中birthday的day成员项*/ }

结构体变量的初始化 形式一: 例 struct student { int num; char name[20]; char sex; 类型标识符 成员名; ……………. }; struct 结构体名 结构体变量={初始数据}; 例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }; struct student stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};

形式二: 例 struct student { int num; char name[20]; char sex; int age; 类型标识符 成员名; ……………. }结构体变量={初始数据}; 例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};

形式三: 例 struct { int num; char name[20]; char sex; int age; 类型标识符 成员名; ……………. }结构体变量={初始数据}; 例 struct { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};

10.3 结构体数组 结构体数组的定义 三种形式: 形式一: struct student { int num; 形式二: 10.3 结构体数组 结构体数组的定义 三种形式: num name sex age stu[0] stu[1] 29B 形式一: struct student { int num; char name[20]; char sex; int age; }; struct student stu[2]; 形式二: struct student { int num; char name[20]; char sex; int age; }stu[2]; 形式三: struct { int num; char name[20]; char sex; int age; }stu[2];

strcpy(stu[0].name,”ZhaoDa”); 结构体数组初始化 结构体数组引用 分行初始化: struct student { int num; char name[20]; 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 name[20]; 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 name[20]; char sex; int age; }stu[ ]={{……},{……},{……}}; 例 struct { int num; char name[20]; char sex; int age; }stu[ ]={{……},{……},{……}}; struct student { int num; char name[20]; char sex; int age; }str[3]; stu[1].age++; strcpy(stu[0].name,”ZhaoDa”);

例3 计算学生的平均成绩和不及格的人数。 #include <stdio.h> struct student { int num; char *name; char sex; float score; } boy[5]={{101, "Li ping", 'M', 45}, {102, "Zhang ping", 'M', 62.5}, {103, "He fang", 'F', 92.5}, {104, "Cheng ling", 'F', 87}, {105, "Wang ming", 'M', 58} }; void main() { int i, count=0; float sum=0; for (i=0; i<5; i++) { sum+=boy[i].score; if (boy[i].score<60) count++; } printf("average=%f, count=%d\n", sum/5, count);

例4 统计候选人选票 #include <stdio.h> #include<string.h> 例4 统计候选人选票 #include <stdio.h> #include<string.h> struct person { char name[20]; int count;}leader[3]={"Li",0,"Zhang",0,"Wang",0}; main() { int i,j; char leader_name[20]; for(i=1;i<=10;i++) { scanf("%s",leader_name); for(j=0;j<3;j++) if(strcmp(leader_name,leader[j].name)==0) leader[j].count++; } for(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count); name count Li Zhang Wang

10.4 指向结构体类型数据的指针 10.4.1 指向结构体变量的指针 定义形式:struct 结构体名 *结构体指针名; 10.4 指向结构体类型数据的指针 10.4.1 指向结构体变量的指针 定义形式:struct 结构体名 *结构体指针名; 例 struct student *p; #include <stdio.h> #include<string.h> main() { struct student {long int num; char name[20]; char sex; float score; }stu_1,*p; p=&stu_1; stu_1.num=89101; strcpy(stu_1.name,"Li Lin"); p->sex='M'; p->score=89.5; printf("\nNo:%ld\nname:%s\nsex:%c\nscore:%f\n", (*p).num,p->name,stu_1.sex,p->score);} 使用结构体指针变量引用成员形式 num name sex age stu p struct student { int num; char name[20]; char sex; int age; }stu; struct student *p=&stu; 存放结构体变量在内存的起始地址 (*结构体指针名).成员名 结构体指针名->成员名 结构体变量名.成员名 例 int n; int *p=&n; *p=10;  n=10 struct student stu1; struct student *p=&stu1; stu1.num=101;  (*p).num=101 例 指向结构体的指针变量 指向运算符 优先级: 1 结合方向:从左向右

10.4.2 指向结构体数组的指针 例 指向结构体数组的指针 struct student { int num; 10.4.2 指向结构体数组的指针 例 指向结构体数组的指针 num name sex age stu[0] p stu[1] stu[2] p+1 struct student { int num; char name[20]; char sex; int age; }stu[3]={{10101,"Li Lin",'M',18}, {10102,"Zhang Fun",'M',19}, {10104,"Wang Min",'F',20}}; main() { struct student *p; for(p=stu;p<stu+3;p++) printf("%d%s%c%d\n",p->num,p->name,p->sex,p->age); }

* 结构体与函数 *.1 函数的结构体类型参数 用指向结构体的指针作函数参数 用结构体变量的成员作参数----值传递 用指向结构体变量或数组的指针作参数----地址传递 用结构体变量作参数----多值传递,效率低

例4.5 求某年某月某日是该年的第几天。 #include <stdio.h> struct ymd { int day; int month; int year; int dyear; }; int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int d_of_y(struct ymd *p) // 形参p为结构体指针变量 { int i, d; if(p->year%4==0&&p->year%100!=0||p->year%400==0) days[2]=29; else days[2]=28; d=p->day; //d的初值 for (i=1; i<p->month; i++) d=d+days[i]; return(d); /* 亦可以将d的值直接赋给p->dyear,实现返回 */ }

void main() { struct ymd date; // 定义结构体变量date while (1) printf("date(yyyy-mm-dd)=?(yyyy=0----Exit)\n"); scanf("%d-%d-%d", &date.year, &date.month, &date.day); if (date.year==0) break; date.dyear=d_of_y(&date); // 实参为结构体变量date的指针 printf("The days of the year is %d!\n", date.dyear); }

*.2 结构体类型的函数 例4.6 求下星期的今天是什么日期。 #include <stdio.h> struct ymd { *.2 结构体类型的函数 例4.6 求下星期的今天是什么日期。 #include <stdio.h> struct ymd { int day; int month; int year; }; int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; struct ymd date_nextweek(struct ymd d); // 对结构类型的函数进行声明 void main() { struct ymd whatdate, today; printf(Todays date(mm-dd-yyyy): ); scanf(%d-%d-%d, &today.month, &today.day, &today.year); whatdate=date_nextweek(today); // 函数的实参以及返回值都是结构类型 printf(The date after 7 days is %d-%d-%d!\n, whatdate.month, whatdate.day, whatdate.year); }

struct ymd date_nextweek(struct ymd d) { struct ymd newd; if(d.year%4==0&&d.year%100!=0||d.year%400==0) days[2]=29; else days[2]=28; newd.day=d.day+7; newd.month=d.month; newd.year=d.year; if (newd.day>days[d.month]) { newd.day=newd.day-days[d.month]; newd.month=newd.month+1; if (newd.month>12) { newd.month=1; newd.year=newd.year+1; } return (newd);

10.5 链表处理 10.5.1 链表结构 1.链表的概念 链表是用指针把各个结点链接在一起,其一般形式如图所示。 指向链表的首结点 10.5 链表处理 10.5.1 链表结构 1.链表的概念 链表是用指针把各个结点链接在一起,其一般形式如图所示。 指向链表的首结点 尾结点,NULL:链表结束标志 指向后续结点的指针,存放后续结点的地址 存储结点本身的数据信息

【例10.7】 建立一个简单的链表,它由3个存放学生数据(包括学号和成绩)的结点组成,然后输出各结点的数据。 #include "stdio.h" struct node /*定义结构体类型*/ { int num; /*学号*/ float score; /*成绩*/ struct node *next; /*指向struct node类型的指针变量*/ }

main( ) { struct node a,b,c,*head,*p; a.num=101; a.score=85.4; b.num=103; b.score=96.1; c.num=105; c.score=77.5; head=&a; a.next=&b; b.next=&c; c.next=NULL; p=head; do { printf("学号: %d 成绩:%5.2f\n",p->num,p->score); p=p->next;} while(p!=NULL); } 静态链表

2.动态存储分配函数 (1)分配内存空间函数malloc() 调用形式: (类型说明符*) malloc(size); 例如: pc=(char *) malloc (sizeof(char)); 表示分配1个字节的内存空间,并强制转换为字符类型,函数的返回值为指向该字节的指针,把该指针赋予指针变量pc。

(2)分配内存空间函数 calloc() 调用形式:(类型说明符*) calloc(n,size); 说明:“(类型说明符*)”用于强制类型转换。 calloc()函数与malloc()函数的区别仅在于一次可以分配n块区域。 例如: ps=(struet stu*) calloc(2,sizeof (struct stu)); 其中的sizeof(struct stu)是求stu的结构体长度。因此该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。

(3)释放内存空间函数free() 调用形式:free(void *ptr); 功能:释放ptr所指向的一块内存空间,ptr 是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc()或calloc()函数所分配的区域。

ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; 【例10.8】 分配一块区域,输入一个学生数据。 #include "stdlib.h" #include "stdio.h" main( ) { struct stu { int num; char *name; char sex; float score; } *ps; ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; ps->name="Zhang ping"; ps->sex='M'; ps->score=62.5; printf("Number=%d \nName=%s \n",ps->num,ps->name); printf("Sex=%c \nScore=%f \n",ps->sex,ps->score); free(ps); }

10.5.2 对链表的基本操作 对链表的常用的操作主要包括创建、插入、删除和输出等基本操作。 创建链表 10.5.2 对链表的基本操作 对链表的常用的操作主要包括创建、插入、删除和输出等基本操作。 创建链表 【例10.9】 编写一个create()函数,按照规定的结点结构,创建一个单链表。 基本思路: 首先向系统申请一个结点的空间,然后输入结点数据域中的数据项,并将指针域置为空(链尾标志),最后将新结点插入到链表尾。对于链表的第一个结点,还要设置头指针变量。 本题中设3个指针变量head、new1和tail,分别说明如下: head:头指针变量,指向链表的第一个结点,用作函数返回值。 new1:指向新申请的结点。 tail:指向链表的尾结点,用tail->next=new1,实现将新申请的结点,插入到链表尾,使之成为新的尾结点。

#include "stdio.h" #include "malloc.h" #define NULL 0 #define LEN sizeof(struct student) /*定义结点长度*/ struct student /*定义结点结构*/ { int num; /*学号*/ float score; /*成绩*/ struct student *next; /*指针域*/ };

struct student *create() /*create()函数: 创建单链表*/ { struct student *head=NULL, *new1, *tail; int count=0; /*链表中的结点个数(初值为0)*/ new1=tail=(struct student *)malloc(LEN); /*向系统申请一新结点空间*/ scanf("%d%f",&new1->num,&new1->score); while((new1->num)!=0) /*如果学号0,则退出*/ { count++; /*结点个数加1*/ if(count==1) head=new1; /*将新结点插入到链表尾,并设置新的尾指针*/ else tail->next=new1; /*非首结点, 将新结点插入到链表尾*/ tail=new1; /*设置新的尾结点*/ new1=(struct student *)malloc(LEN); scanf("%d%f",&new1->num,&new1->score); } tail->next=NULL; return(head); /*返回单链表的头指针*/ }

S->next =p->next; p->next= S; 3. 插入操作 在结点a与b之间插入一个新的结点x。插入前,结点a是结点b的前驱结点,结点b是结点a的后继结点;插入后,新插入的结点x成为结点a的后继结点、结点b的前驱结点。 算法如下: S->next =p->next; p->next= S; 结点插入前的链表 结点插入后的链表

【例10.10】 编写insert()函数,完成在单链表的第i个结点后插入1个新结点的操作。 struct student *insert(struct student *head, struct student *stu, int i) { struct student *pointer; if(head==NULL) /*若为空链表*/ head=stu, stu->next=NULL; /*将新结点插入到空链表中*/ else /*非空链表*/ if(i==0) stu->next=head, head=stu; /*使新结点成为链表新的首结点*/ else /*其他位置*/ { pointer=head; /*查找单链表的第i个结点(pointer指向它)*/ for(; pointer!=NULL && i>1; pointer=pointer->next, i--) if(pointer==NULL) /*越界错*/ printf("Out of the range, can't insert new node!\n"); else /*一般情况:pointer指向第i个结点 */ stu->next=pointer->next, pointer->next=stu; } return(head);

pa->next=px->next; free(px); 4. 删除操作 删除结点x。删除前,结点x是结点b的前驱结点、结点a的后继结点;删除后,结点a成为结点b的前驱结点,结点b成为结点a的后继结点。 结点删除前的链表 结点删除后的链表 pa->next=px->next; free(px);

【例10.11】 编写一个dele ()函数,删除链表中学号为num的指定结点。 struct student *dele( struct student *head, int num) { struct student *pf,*pb; if(head==NULL) /*若为空表,输出提示信息*/ { printf("\nempty list!\n"); return head; } pb=head; while (pb->num!=num && pb->next!=NULL) /*当前结果不是要删除的结点,而且也不是最后一个结点时,继续循环*/ { pf=pb; pb=pb->next; } /*pf指向当前结点,pb指向下一结点*/ if(pb->num==num) { if(pb==head) head=pb->next; /*找到被删结点,且为第一结点,则使head指向第二个结点,否则使pf所指结点的指针指向下一结点的后续*/ else pf->next=pb->next; free(pb); printf("The node is deleted\n"); } else printf("The node not been foud!\n");

5. 输出链表 首先知道head头指针的值,设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出,直到链表的尾结点。 【例10.12】 输出链表。 void output (struct student *head) { struct student *p; p=head; if(head!=NULL) do { printf("%d %5.1f\n", p->num , p->score); p=p->next; } while(p!=NULL); }

例 创建一个链表,用来存储下表所示n条的学生成绩记录表。 功能要求: (1) 学生成绩信息由键盘录入,一个记录一行; (1) 学生成绩信息由键盘录入,一个记录一行; (2)可插入记录到链表中,由用户指定插入位置; (3 )查找指定位置的记录(链表中的位置而非排序的顺序编号); (4 )可以进行记录的修改或删除; (5 )可以按照链表的组织顺序打印记录, (6 )可以对链表记录排序。 以上每个功能处理后都提供按链表顺序打印记录和排序输出记录的功能。 输入的一行记录如下,中间用制表或空格符分隔开: 0053864 智婷 女 SystemView仿真 C01 072 20.0 89.0 91.2

//定义学生记录结构类型及对应的指针类型 typedef struct studentrec 步骤1.首先应该根据记录的各个数据项目,相应的定义一个成绩记录结构体类型,用来保存数据: /*文件名:mysubs.h*/ //定义学生记录结构类型及对应的指针类型 typedef struct studentrec { char number[8]; //保存学生7位学号字符串 char name[21]; //保存学生姓名,最长10个中文字 char gender; //性别,取值为'M'或'F' char course[30]; //课程名 char classno[5]; //课程编号 char semester[4]; //开课学期 float pingshi, final, score;//平时分,期末分,总评分 struct studentrec *next; //指针,指向下一个记录 } STUREC, * PSTUREC;

步骤2.创建链表。 首先应该创建一个具有N个结点的链表,同时输入数据记录。创建链表,首先应该创建一个个的结点,并把各结点用指针连接起来。第一个结点为首元素结点,又叫表头;指向它的指针称为链表的表头指针。每个链表必须有一个表头指针。 步骤2.1.开始的时候,链表是空的,空表的表头指针值为NULL。还要创建一个表尾结点指针,开始也为NULL。 (0) 创建空表 表头指针 head = NULL 表尾指针 tail = NULL

步骤2.2.创建一个结点p,作为首元素结点,同时也是尾结点: 记录1数据 NULL head 表头指针 首元素结点 (1) 创建首元素结点 p tail /*文件名:mysubs.cpp*/ #include“mysubs.h“ /*CreateRecNode:创建链表结点。成功则返回指向 该结点的指针,否则返回NULL*/ PSTUREC CreateRecNode( ) { PSTUREC p=( PSTUREC)calloc(1, sizeof(STUREC));//用calloc创建结 点,保证内存中都是0 return p; }

PSTUREC CreateRecNode( );//创建链表结点。成功则返回指向该结 PSTUREC InputRecord(PSTUREC p);//输入学生成绩记录数据,该记录由p00 PSTUREC CreateLst(int n)00/*创建有n个结点的链表,返回表头指针*/0 { PSTUREC head, tail, p = NULL;00int i=0;00 0 tail = head = NULL; //(2.1)创建空链表00 0 while(i<n) //循环创建n个结点的链表00 {0 p=CreateRecNode();//创建一个结点 00 if(p==NULL)0 0 {0printf("创建结点失败!退出程序......\n");0 0 exit(-1);0 }00 p->next = NULL;//把新建的、由p指向的结点作为尾结点 00 if(head==NULL) //(2.2) 创建首元素结点后,把它链入链表 00 tail=head=p; 00 else //(2.3) 把新建的非首元素结点连在链表最后作为新的尾结点 00 {0 tail->next=p; //把新建结点挂在尾部0 0 tail =p; //新建结点作为新的尾结点 }0 0 InputRecord(p); //输入数据 00 i++; //创建下一个结点0 }0 0 return head; //返回链表表头指针 }

步骤3 实现函数InputRecord。 这个函数根据用户输入的一行信息,从中提取出用空白符(空格、制表符等)分隔开的各项数据,利用它们分别为形参指针p指向的struct studentrec类型的结构体的各成员变量赋值。采用一行一行的输入(利用函数fgets),是为了简化输入的麻烦,而且还能保证输入的安全。这样,用户就可以先把用空白符分隔的一行行的记录存放在一个文本文件中,在程序要求输入数据的时候,用拷贝-粘贴的方式很快捷的把记录输入程序中。 PSTUREC InputRecord( PSTUREC p ) 000 { if(p == NULL ) return; //指针p不为NULL时才允许接受输入 char line[200]={'\0'};000 char gender[3]; //用来保存性别字串"男""女"000 fflush(stdin); //输入记录前先清空输入缓冲区00 fgets(line, sizeof(line), stdin); //用fgets从控制台输入一行数据00 sscanf(line,"%s%s%s%s%s%s%f%f%f\n", p->number,p->name, gender,00 p->course, p->classno, p->semester, &(p->pingshi),00 &(p->final),&(p->score) ); //读取数据,写到结构的成员变量中00 if(strcmp("男",gender)==0) p->gender = 'M'; //把性别转换成字符值'F'/'M '00 else p->gender = 'F';00 return;00 }

步骤4.检验链表创建的结果,设计打印链表数据的函数。 步骤4.1.首先设计打印单条记录的函数。该函数根据输入的指向记录的指针,分别打印各个字段: 000 /*PrtStuRec:打印单个学生成绩记录,利用指向学生成绩结构体的指针p*/000 void PrtRecord(PSTUREC p) //打印结构体中所有成员变量的函数,采用传指针的方式000 { (p!=NULL)&& printf("%-8s%-8s%5s%20s%7s%7s%8.1f%8.1f%8.1f\n",p->number, p->name, 00 (p->gender=='F')?"女":"男",p->course, p->classno, p->semester, 0005 p->pingshi, p->final, p->score );//用指针来存取成员变量0006 return ;0007 }

步骤4.2.能够打印单条记录了,接下来设计打印整个链表表示的所有记录的函数。其实只需要从链表的表头开始,逐条打印记录,直至表尾即可。 void PrtStuRecLst(PSTUREC head) { PSTUREC p=head; int i =0; if(p==NULL ) return; printf("===============================================================================\n"); printf("学号 姓名 性别 课程名 班级 学期 平时分 期末分 总评\n"); do PrtRecord(p); }while(p=p->next); return ; }

10.6 共用体和枚举类型 10.6.1 共用体 共用体类型的定义与结构体类型的定义类似,格式为: union 共用体类型名 { 成员列表; }; 1. 间接定义──先定义类型、再定义变量。 例如:定义data共用体类型变量un1,un2,un3的语句如下: union data { int i; char ch; float f; }; union data un1,un2,un3; 2. 直接定义──定义类型的同时定义变量。 union [data] float f; } un1, un2, un3;

10.6.2 枚举类型 枚举类型的定义为: enum 枚举类型名 {取值表}; 10.6.2 枚举类型 枚举类型的定义为: enum 枚举类型名 {取值表}; 如:enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 枚举类型变量的定义与结构体变量类似。 例如:enum weekdays   {Sun,Mon,Tue,Wed,Thu,Fri,Sat } workday;

10.7 定义已有类型的别名   在C语言中,可以用typedef关键字来为系统已经有的数据类型定义别名,该别名与标准类型名一样,可以用来定义相应的变量。 例如: typedef int INTEGER; /*指定别名INTEGER代表int*/ typedef float REAL; /*指定别名REAL代表float */ INTEGER x,y;等价于int x,y; REAL a,b;等价于float a,b;

也可以声明一个新的别名DATE代表一个结构体类型。 例如: typedef struct date { int month; int day; int year; }DATE; 下面可以用DATE定义变量 DATE birthday; /*定义结构体变量*/