第9章 结构体.

Slides:



Advertisements
Similar presentations
目 录  第 1 章 C++ 概述  第 2 章 数据类型、运算符和表达式  第 3 章 简单的输入 / 输出  第 4 章 C++ 的流程控制  第 5 章 函数  第 6 章 编译预处理  第 7 章 数组  第 8 章 结构体、共同体和枚举类型  第 9 章 指针和引用  第.
Advertisements

程序设计导论 ——第15讲 结构与结构数组.
程序设计导论 结构与结构数组.
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
电子成绩单项目实现.
第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型
二级指针与二维数组.
大学实用教程 C语言.
数据结构与算法 数据结构与算法实验
第11章 结构体与共用体 结构体 共用体 枚举类型 用typedef定义类型 Tc工具. 江南大学控制科学与工程研究中心
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
第九章 结构体 主讲教师 :贾月乐 电话:
使用VC++6.0调试程序.
第10章 结构体与共用体 概述 结构体 共用体 枚举类型.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
7.1 结构体类型 7.2 共用体 7.3 枚举类型 7.4 用typedef声明类型
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
第 十 章 指 针.
结构体和共用体 2 梁春燕 华电信息管理教研室.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
第9章 用户自己建立数据类型 9.1 定义和使用结构体变量 9.2 使用结构体数组 9.3 结构体指针 9.4 用指针处理链表
程序设计专题 第2讲 - 结构 刘新国.
STRUCTURE 授課:ANT 日期:2010/5/12.
自定义数据类型 潘荣江 山东大学计算机科学与技术学院
程序设计基础.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
C语言程序设计 李祥.
辅导课程六.
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针
第7讲 结构体与共用体 7.1 结构体 7.2 共用体.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第8章 结 构 体.
第8章 结构体、共用体和枚举类型 教学目的: 通过本章的学习,要求了解结构型、链表、共用型和枚举型数据的特点,熟练掌握结构型的定义方法,结构型变量、数组、指针变量的定义、初始化和成员的引用方法;掌握简单链表的基本操作原理和应用;掌握共用型和枚举型的定义方法及对应变量的定义与引用;掌握用户自定义类型的定义和使用。学习本章内容可以为今后学习数据结构中的链表创建和使用打下基础。
第11章 结构体和共用体.
第七章 结构体、共同体和枚举类型.
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
Struct結構 迴圈
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言复习3----结构体.
C语言程序设计.
第十章 用户自定义数据类型 目录 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组
第十章 结构体与链表 西安工程大学.
第9章 用户自己建立数据类型 C语言提供了一些系统已定义好的数据类型,如int,float,char,用户可以用它们定义变量。
浙江长征职业技术学院—计算机与信息技术系—相方莉制作
第九章 用户建立的数据类型.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第 四 讲 线性表(二).
第九节 赋值运算符和赋值表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
结构体与共用体 结构体 结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体 自定义数据类型 结构体类型定义
第十一章 链表.
本节内容 结构体.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C语言程序设计 第9章 结构体.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
基本知识 数据类型、变量、常量、运算符.
第14讲 结构体和共用体 计算机与通信工程学院.
第18讲 从C到C++ 计算机与通信工程学院.
第八章 结构体和共用体 结构体类型和结构体变量 结构体数组 结构体指针变量 共用体.
安排座位.
Presentation transcript:

第9章 结构体

目 录 定义结构体类型变量的方法 结构体变量的引用 结构体变量的初始化 结构体数组 指向结构体类型数据的指针 用指针处理链表 目 录 定义结构体类型变量的方法 结构体变量的引用 结构体变量的初始化 结构体数组 指向结构体类型数据的指针 用指针处理链表 重点是函数的定义、引用、函数间数据传递的方式、变量的作用范围。 难点是函数的递归调用。 外部函数与外部变量的应用。 用typedef定义类型

本章学习目标 理解结构体的概念和它对于编程的重要性; 理解定义结构体类型和定义结构体变量的区别; 能够用“ . ”和“->”分量运算符操作结构体变量和指向结构体的指针变量; 能够定义并使用结构体数组; 了解用typedef定义数据类型。

有些问题仅用基本类型和数组来描述,无法反映其内在联系,如学生情况: 9.1 定义和使用结构体变量 有些问题仅用基本类型和数组来描述,无法反映其内在联系,如学生情况: num name sex age score addr 11001 Zhang xin m 19 96. 5 Shang hai 12001 Wang li f 20 98. 5 Bei jing 由不同类型数据组成的这种数据结构称为结构体(structure)。

注意:这只是声明一种数据类型并没有定义变量。 1、结构体 结构体是一种构造数据类型。 定义:由相互关联的不同数据类型的数据组成的有机整体。 用途:为处理复杂的数据结构提供了手段。 为函数间传递不同类型的参数提供了便利。 关键字:struct 结构体类型定义 注意:这只是声明一种数据类型并没有定义变量。 合法标识符 可省:无名结构体 struct [结构体名] { 类型标识符 成员名1; 类型标识符 成员名2; ……………. }; 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、定义结构体类型变量的方法(3种) (1)先声明结构体类型,再定义结构体变量 定义结构体 类型 struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. }; struct 结构体名 变量名表列; struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu1,stu2; 定义结构体变量

(2)声明结构体类型的同时定义结构体变量 struct student struct 结构体名 { int num; char name[20]; char sex; int age; float score; char addr[30]; } stu1,stu2 ; struct 结构体名 { 类型标识符 成员名; 类型标识符 成员名; ……………. }变量名表列; 定义结构体类型 只有在定义了结构体变量后系统才为其分配内存。 定义结构体变量

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

说明 结果:28 printf ("%d ", sizeof (stu) ); 结构体类型与结构体变量概念不同 类型:不分配内存; 变量:分配内存 类型:不能赋值、存取、运算; 变量:可以 结构体变量中的成员可单独使用,方法如普通变量; 结构体可嵌套 struct date { int month; int day; int year; }; struct student { int num; char name[20]; struct date birthday; }stu; struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu; num name birthday month day year printf ("%d ", sizeof (stu) ); 结果:28

struct student { int num; char name[20]; float score; }stu; int num; 结构体成员名与程序中变量名可相同,两者不代表同一个对象。 struct student { int num; char name[20]; float score; }stu; int num; stu. num num

3、 结构体变量的引用 结构体变量名.成员名 结构体变量不能整体引用,只能引用变量成员 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu1.num=10; stu1.age++; stu1.score=85.5; stu1.score+=stu2.score; 成员(分量)运算符 优先级: 1 结合性:从左向右

main() { struct student { int No; float score; } stu1,stu2; } scanf(“%d,%f”,&stu1); () scanf(“%d,%f”,&stu1.No, &stu1.score); (√) printf(“%d,%f”,stu1); () printf(“%d,%f” , stu1.No, stu1.score); (√) stu2=stu1; (√)

结构体变量的成员与普通变量用法相同。 结构体成员本身又是一个结构体类型,则需要找到最低一级的成员。 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; 结构体变量的成员与普通变量用法相同。

4、 结构体变量的初始化 形式一 struct 结构体名 { 类型标识符 成员名1; 类型标识符 成员名2; ……………. }; { 类型标识符 成员名1; 类型标识符 成员名2; ……………. }; struct 结构体名 结构体变量={初始数据}; struct stu { int num; char name[20]; int age; char addr[30]; }; struct stu a={112,“Wang Lin”, 19, “200 Beijing Road”};

形式二 struct 结构体名 { 类型标识符 成员名1; 类型标识符 成员名2; ……………. } 结构体变量={初始数据}; { 类型标识符 成员名1; 类型标识符 成员名2; ……………. } 结构体变量={初始数据}; struct stu { int num; char name[20]; int age; char addr[30]; } a={112,“Wang Lin”, 19, “200 Beijing Road”};

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

#include <stdio.h> void main() { struct student { long int num; 例9.1 对结构体变量初始化 #include <stdio.h> void main() { struct student { long int num; char name[20]; char sex; char addr[20]; }a={89031,“Li Lin”,‘M’, “123 Beijing Road”}; printf("No. :%ld\nname:%s\nsex:%c\naddress:%s\n", a.num,a.name,a.sex,a.addr); }

9.2 结构体数组 具有相同结构的结构体也可以组成数组 定义结构体数组:3种形式 形式一:间接定义 struct student 9.2 结构体数组 具有相同结构的结构体也可以组成数组 定义结构体数组:3种形式 num name sex age stu[0] stu[1] 25B 形式一:间接定义 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];

结构体数组初始化 struct 结构名 结构数组名[数组长度]={初始数据}; 定义数组时初始化: struct student { int num; char name[20]; char sex; int age; }; struct student stu[3]={{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[3]={{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}, ……}; stu[0].age++; strcpy(stu[0].name, “ ZhaoDa”);

“.”成员运算符优先于“++”,所以Leader[j].count++相当于(learer[j].count)++ 例9.3 统计候选人选票 #include <stdio.h> #include <string.h> struct person { char name[20]; int count; }leader[3]={“Li”,0,“Zhang”,0, “Wang”,0}; void 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++; } printf("\n"); for(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count);} name count Li Zhang Wang 4 3 name count Li Zhang Wang 全局结构体数组 “.”成员运算符优先于“++”,所以Leader[j].count++相当于(learer[j].count)++

9.3 指向结构体类型数据的指针 指向结构体变量的指针 例 struct student *p; struct student 9.3 指向结构体类型数据的指针 存放结构体首地址 指向结构体变量的指针 定义形式: struct 结构体名 *结构体指针名 例 struct student *p; 存放结构体变量在内存的起始地址 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 以下三种形式等价: 结构体变量名.成员名 stu.num =101; (*结构体指针名).成员名 (*p).num=101 结构体指针名成员名 pnum =101 指向运算符 优先级: 1 结合方向:从左向右 ( )不能少!

例9.5 指向结构体变量的指针的应用 #include <stdio.h> #include <string.h> void 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);}

指向结构体数组的指针 数组首地址赋给指向结构体类 型的指针变量 当指针变量增1时,指向下一个 数组元素。 p num name stu[0] sex age stu[0] p stu[1] stu[2] p+1

例9.6 指向结构体数组的指针的应用 #include <stdio.h> struct student { int num; 例9.6 指向结构体数组的指针的应用 #include <stdio.h> 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}}; void 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);} num name sex age stu[0] p stu[1] stu[2] p+1 p=str[1].name (×) p=(struct student *)stu[1].name (√) 强制转换

运行结果: 11 200 20 300 注意区分以下三种运算( > 优先级比++高) ①p >n ② p >n++ ③ ++p >n struct s { int x; int y; }data[4]={10,100,20,200,30,300,40,400}; void main( ) { struct s *pointer=data; printf("%d\n",++pointerx); printf(("%d\n",(++pointer)y); printf("%d\n", (pointer++)x); printf("%d\n", (pointer)y++); } 取x值加1后输出 运行结果: 11 200 20 300 地址加1后再取y值 先取当前地址x值 再地址加1 y值输出后地址 再加1

用结构体变量和指向结构体的指针作函数参数 将一个结构体变量的值传递给另一函数 , 方法有3种: 用结构体变量的成员作函数实参----值传递 注意形、实的类型要一致。 用指向结构体变量或数组的指针作实参----地址传递 传递的是结构体变量的地 址。 用结构体变量作参数----多值传递,效率低 将结构体变量所占的内存单元的内容全部顺序传递给形参,要求形参与实参同类型。函数调用是单值传递,且形参占用内存单元,若形参的值被改变,不会返回主调函数。

例9.7 结构体变量stu有学号、姓名和3门课成绩, 在main函数中赋值,在print函数中打印输出。 #include <stdio.h> #include <string.h> #define FORMAT "%d\n%s\n%f\n%f\n%f\n" struct student /*定义为外部结构体类型*/ { int num; char name[20]; float score[3];}; void main() { void print(struct student); struct student stu; /*定义为局部结构体类型变量*/ stu.num=12345; strcpy(stu.name,"Li Li"); stu.score[0]=67.5;stu.score[1]=89;stu.score[2]=78.6; print(stu); /*结构体变量作实参*/ } void print(struct student stu) { printf(FORMAT,stu.num,stu.name,stu.score[0],stu.score[1],stu.score[2]); printf(“\n”);} 无"&" /* 对成员赋值也可以改为scanf函数输入*/ scanf("%d%s%f%f%f",&stu.num,stu.name, &stu.score[0],&stu.score[1],&stu.score[2]);

将例9.7改为用结构体变量的指针作实参 #include <stdio.h> #define FORMAT "%d\n%s\n%f\n%f\n%f\n" struct student /*定义为外部结构体类型*/ { int num; char name[20]; float score[3]; }; stu={12345, "Li Li",67.5,89,78.6}; void main() { void print(struct student * ); /*形参指向结构体的指针变量*/ print(&stu); /*实参为stu的起始地址*/ } void print(struct student *p) { printf(FORMAT,pnum,pname,pscore[0],pscore[1], pscore[2]); /*用指针变量调用成员之值*/ printf(“\n”);

9.4 用指针处理链表 数组:静态分配存储单元,容易造成内存浪费。 链表:是重要的数据结构,它根据需要,动态分配内存单元 。 head 9.4 用指针处理链表 数组:静态分配存储单元,容易造成内存浪费。 链表:是重要的数据结构,它根据需要,动态分配内存单元 。 head 1249 1356 1475 1021 A B C D Null 特征:头指针变量,存放链表首地址,链表中每个元素称结点,其内容: 数据部分:可有若干项(整、实、字符、结构体类型等) 指针变量:下一结点的地址,最后一个结点(表尾)的地址部分为NULL。

它指向struct student数据类型. struct student { int num; float score; 链表各结点的特点: 在内存中可以不连续,访问某结点应找上一结点提供的地址,每一结点有一指针变量存放下一结点的地址。 链表的每个结点实际上是一个结构体变量,它有若干成员组成 其中:next是成员名,是指针类型, 它指向struct student数据类型. struct student { int num; float score; struct student *next; }; 99101 89. 5 99103 90 99107 85 NULL num score next

简单链表 例9.8 建立简单链表,它由3个学生数据的结点组成。 输出各结点中的数据。 #include <stdio.h> 例9.8 建立简单链表,它由3个学生数据的结点组成。 输出各结点中的数据。 #include <stdio.h> #define NULL 0 struct student {long num; float score; struct student *next; }; void main( ) {struct student a,b,c,*head,*p; a.num=99101;a.score=89.5; b.num=99102;b.score=90; c.num=99103;c.score=85; head=&a;a.next=&b;b.next=&c; c.next=NULL; p=head; do { printf(“%ld %5.1f\n”,pnum,pscore); p=pnext; }while(p!=NULL); }

每个结点都属于struct student类型,它的next成员存放下一个结点的地址,这样一环扣一环,将各结节紧密的扣在一起,最后一次循环,将p=pnext是将c结点的地址赋给p,这时p指向c结点,然后将c结点的num,score输出,之后将p=pnext实际上是将c结点的next内容,即NULL赋给p 再进行判断, P!=NULL条件不成立,循环结束。 本例所有结点是在程序中定义的,不是临时开辟的,用完也不能释放,这种链表称“静态链表”。

处理动态链表所需的函数 为处理动态链表,C提供了开辟和释放存储单元的函数: malloc函数 calloc函数 函数原型:void *malloc(unsigned int size); 作用:在动态区分配一个长度为size的连续空间,函数返回值是一个指向分配域起始地址的指针,如内存空间不足,返回空指针NULL。 (此处:void为无确定类型) calloc函数 函数原型:void *calloc(unsigned n,unsigned size); 作用:在内存动态区分配n个长度为size的连续空间,函数返回指向分配域起始地址的指针,若分 配不成功,返回NULL值。

注:旧版本提供的malloc和calloc函数得到的是指向字符型数据的指针。 free函数 函数原型:void free(void *p); 作用:释放由p指向的内存区,使这部分内存区能被其它变量使用。P所指向的是最近一次calloc或malloc分配的存储区域。 free函数无返回值。 注:旧版本提供的malloc和calloc函数得到的是指向字符型数据的指针。 ANSI C提供的malloc和calloc函数规定为void *类型,这并不是说该函数调用后无返回值,而是返回一个结点的地址,该地址的类型为void(无类型或类型不确定),即一段存储区的首址,其具体类型无法确定,只有使用时根据各个域值数据再确定。

建立动态链表 建立动态链表:是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。 例9.9 写一函数建立一个有3名学生数据的单向动态链表。 思路: ⑴ 设置3个指针变量head、p1、p2 head:指向链表头的指针变量,初始化head=NULL。 p1:指向后继结点的首地址的指针变量 p2:指向结点成员next的指针变量。 next的值是下一个结点的首地址。 ⑵ 循环方式用malloc函数开辟第1个结点。n=1 p1、p2指向第1结点首地址(见下页插图) 输入数据,如果p1num !=0, 则head=p1结点链入链表,反之不链入。

(n=1) 99101 89.5 head p1 p2 (a) (n=2) head p2 p1 99101 89.5 99103 90 输入数据。 如果p1num !=0,链入2结点, 方法: p2next=p1 (a) (n=2) head p2 p1 99101 89.5 99103 90 ⑷ 为建立第3个结点做准备: p2=p1,腾出p1 。 head p2 p1 99101 89.5 99103 90 (c) (n=2) head p2 p1 99101 89.5 99103 90 (b) (n=2)

⑸ 重复⑶⑷两步开辟第3个结点,并链入链表。 99101 89.5 99103 90 head p2 p1 99107 85 (a) n=3 n=n+1 n==1 head=p1 p2next=p1 真 假 (把p1所指结点作为第一个结点) (把p1所指结点连接到表尾) p2=p1 (p2移到表尾) 再开辟一个新结点,使p1指向它 读入一个学生数据给p1所指结点 表尾结点的指针变量置NULL 开辟一个新结点,并使p1, p2指向它 读入一个学生数据给p1所指向的结点 head=NULL, n=0 当读入的p1  num 不是零 99101 89.5 99103 90 head p2 p1 99107 85 (b) n=3

⑹ 再开辟新结点,由于num数据为0,退出循环。 并使p2next=NULL,虽然p1指向新结点但没有链入链表。 99101 89.5 99103 90 p2 p1 99107 85 (a) n=3 head 99101 89.5 99103 90 p2 p1 99107 85 NULL (b) n=3 head

#include “stdio.h” #include “malloc.h” #define NULL 0 #define LEN sizeof (struct student) struct student {long num; float score; struct student *next; }; int n; struct student *creat(void) { struct student *head; struct student *p1, *p2; n=0; p1=p2=(struct student *) malloc(LEN); scanf(“%ld,%f”,&p1  num, &p1  score); head=NULL; while(p1  num !=0) {n=n+1; if(n==1)head=p1; else p2  next=p1; p2=p1; p1=(struct student *)malloc (LEN); scanf(“%ld,%f”,&p1  num, & p1  score); } p2  next=NULL; return(head); }

#include “stdio.h” /*改进后*/ #include “stdlib.h” #define NULL 0 #define LEN sizeof (struct student) struct student {long num; float score; struct student *next; }; int n; struct student *creat(void) { struct student *head; struct student *p1, *p2; flot s; n=0; p1=p2=(struct student *) malloc(LEN); scanf(“%ld,%f”,&p1  num,&s); p1  score=s; head=NULL; while(p1  num !=0) {n=n+1; if(n==1)head=p1; else p2  next=p1; p2=p1; p1=(struct student *)malloc (LEN); scanf(“%ld ,%f”,&p1  num,&s); p1  score=s; } p2  next=NULL; return(head); }

设一个指针变量p,找到链表第1个结点的地址(head的值),p指向该结点,输出结点各成员的数据,再p后移指向下一结点。 输出链表 思路: 设一个指针变量p,找到链表第1个结点的地址(head的值),p指向该结点,输出结点各成员的数据,再p后移指向下一结点。 P=head,使p指向第一个结点 P指向的不是尾结点 真 假 输出p所指向的结点 p=p  next 当p指的不是表尾 NULL head P P’

void print( struct student *head) { struct student *p; printf(“\n Now, these %d records are :\n”, n); p=head; if(head) !=NULL) do { printf(“%ld, %5.2f\n”, p  num, p  score); p=p  next; } while(p !=NULL);

对链表的删除操作 并不真从内存中抹掉,只是把它分离,再前后结点相链接。 例9.11 写一函数删除动态链表中指定的结点。 例9.11 写一函数删除动态链表中指定的结点。 思路:本例以学号作为删除结点的标志(查找对象)。 ⑴ 设两个指针变量p1和p2。从head开始,p1依次指向各结点查找num值是否等于要删除结点的学号。每次下移前使p2=p1。学号相等删除该结点,直至查到表尾。 p2 (b) 下移一个结点 head p1 99107 NULL 99101 99103 p2=p1 99101 head p1 99103 99107 NULL (a) 初始状态

⑵找到要删除的结点后: ①如果要删除的是第1结点,则head=p1next 。head指向第二结点,第一结点脱离。 head p2 p1 p2 next=p1  next (d) 第二个结点被删除 99107 NULL 99101 99103 head=p1  next head p1 (c) 选中第一个结点 99101 99107 NULL 99103 ②如果要删除的不是第1结点,则p2next=p1next 。P1指向的结点脱离。 ③还要考虑链表为空和链表中没有要删除的结点的情况。

p1是要删除的结点 是 否 链表是一个空表 真 假 输出 空表 p1=head 当num≠ p1  num 以及p1 所指的结点不是表尾结点 p2=p1 (p2后移一个位置) p1 = p1  next (p1后移一个位置) 输出“找不 到”的信息 P1所指是头结点 是 否 head=p1 next (删除头结点) p2next=p1next (删除一个结点)

struct student *del(struct student *head,long num) { struct student *p1,*p2; if(head = = NULL) {printf(“\n list null ! \n”); goto end; } p1=head; while(num !=p1  num && p1  next != NULL) { p2=p1; p1=p1  next; } if(num == p1  num) { if(p1 = = head) head=p1  next; else p2  next = p1  next; printf(“delete: %d\n”,num); n=n-1; } else printf(“%ld not been found ! \n”,num); return(head);

对链表的插入操作 假设结点按成员的学号从小到大排列,按排序顺序插入结点。 思路:找到插入点后,将该点的next值指向新结点,并使新结点的next值等于断点后面结点的首地址。 ⑴ 设置p0、p1、p2三个指针变量。创建一个新结点,p0指向其起始位置地址。p1指向第1个结点。 head 99101 99103 99107 NULL 99102 p0 p1 (a)准备将p0插入链表中

⑵ 如果p0num大于p1num,则p2=p1,然后p1后移一个结点。直至p0num小于或等于p1num。这时p0所指结点插在p1所指结点之前。 head 99101 99103 99107 NULL 99102 p0 p1 p2 (b) 插入点位于链表中间 p0num>p1num p2=p1, p1=p1next 99103 99107 NULL p1 head 99101 99102 p0 p2 (c) 链接新结点 p0num ≤p1num p2next=p0, p0next=p1 ⑶ 如果插入点在链表中间,则p2next=p0,p0next=p1,新结点插入了链表。

⑷ 如果插入点位于最前面,则head=p0,p0 next=p1。 99107 NULL head 99100 99103 99101 p0 p1 (d) 结点插在表首 p0num < p1num head=p0, p0next=p1 p1 99101 99107 99103 99109 NULL p0 (e) 结点插在表尾 p1next = p0 p0next = NULL head ⑸ 如果插入点位于最后面,则p1不再后移,p1next=p0, p0next=NULL

将一个结点插入到链表中算法: p1=head, p0=stud 原来的链表是空表 是 否 是 否 当p0  num > p1  num 以及p1所指的不是表尾结点 p2=p1 p1=p1  next p0  num ≤p1  num 真 假 P0指向头结点 是 否 head=p0 p0  next=p1 (插到表头之前) p2  next=p0 (插到表中间) p1  next=p0 p0  next=NULL (插到表尾之后) 将p0所 指的结 点作为 唯一结 点 n=n+1

{ struct student *p0, *p1, *p2; p1=head; /*使p1指向第一个结点*/ struct student *insert(struct student *head, struct student *stud) { struct student *p0, *p1, *p2; p1=head; /*使p1指向第一个结点*/ p0=stud; /*p0指向要插入的结点*/ if(head = = NULL) /*原来的链表是空表*/ {head=p0; p0next=NULL; } /*使p0指向的结点作为头结点*/ else { while((p0num > p1num) && (p1next != NULL)) { p2=p1; /*使p2指向刚才p1指向的结点*/ p1=p1  next; } /*p1后移一个结点*/ if(p0num <= p1num) { if(head == p1) head=p0; /*插到原来第一个结点之前 */ else p2next=p0; /*插到p2指向的结点之后*/ p0next = p1; } else {p1next=p0; p0next=NULL; } /*插到最后的结点之后*/ } n=n+1; /*结点数加1*/ return(head);

对链表的综合操作 用main函数作主调函数,调用前述建立、输出、删除、插入结点的函数。 void main( ) { struct student *head, *stu; long del_num; printf(“input records: \n”); head=creat(); /*建立链表,返回头指针*/ print(head); /*输出全部结点*/ printf(“\n input delete number:”); scanf(“%ld”, &del_num); /*输入要删除的学号*/ while(del_num !=0) { head=del(head,del_num); /*删除后链表的头地址*/ print(head); /*输出全部结点*/ printf(“input the delete number:”); scanf(“%ld”, &del_num); /*输入要删除的学号*/ }

printf(“\n input the inserted record:”); stu=(struct student *) malloc(LEN); /*输入要插入的结点*/ scanf(“%ld,%f”, &stunum, &stuscore); while(stunum !=0) { head=insert(head,stu); /*插入新结点,返回地址*/ print(head); /*输出全部结点*/ printf(“input the inserted record:”); }

9.7 用typedef定义类型 功能:用自定义名字为已有数据类型命名 类型定义简单形式: typedef type name; 例 typedef int INTEGER; 例 INTEGER a,b,c; REAL f1,f2; 类型定义语句关键字 已有数据类型名 用户定义的类型名 例 typedef float REAL; int a,b,c; float f1,f2; 说明: 1.typedef 没有创造新数据类型 2.typedef 是定义类型,不能定义变量 3.typedef 与 define 不同 类型定义后,与已有类型一样使用 define typedef 预编译时处理 编译时处理 简单字符置换 为已有类型命名

typedef定义类型步骤 类型定义可嵌套 ① 按定义变量方法写出定义体 如 int i; ② 将变量名换成新类型名 如 int INTEGER; ③ 最前面加typedef 如 typedef int INTEGER; ④ 用新类型名定义变量 如 INTEGER i,j; 类型定义可嵌套 例 typedef struct club { char name[20]; int size; int year; }GROUP; typedef GROUP *PG; PG pclub; 例 定义数组类型 int a[100]; int ARRAY[100]; typedef int ARRAY[100]; ARRAY a,b,c;  int a[100],b[100],c[100]; 例 定义结构体类型 struct date { int month; int day; int year; }DATE; 例 定义结构体类型 struct date { int month; int day; int year; }d; 例 定义函数指针类型 int (*p)(); int (*POWER)(); typedef int (*POWER)(); POWER p1,p2;  int (*p1)(),(*p2)(); 例 定义指针类型 char *str; char *STRING; typedef char *STRING; STRING p,s[10];  char *p; char *s[10]; 例 定义结构体类型 DATE birthday, *p;  struct date { int month; int day; int year; }birthday, *p; 例 定义结构体类型 typedef struct date { int month; int day; int year; }DATE; GROUP为结构体类型 PG为指向GROUP的指针类型  GROUP *pclub;  struct club *pclub;

本章小结 构造数据类型分为三种,即:结构体、共用体、枚举。这三种数据类型仍然是以变量的形式使用的,只是在定义变量的时候要确定具体的构造模式。有了这三种数据类型,就能很容易地描述和构成不同的数据结构,并对这些数据结构进行操作。