- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1
动态分配存储区函数calloc( ) ⑵ 动态分配存储区函数 函数原型: 函数原型: void *calloc(unsigned int n,unsigned int size); 调用格式: 调用格式:calloc(n,size) 功能:在内存分配一个n倍 字节的存储区。 功能:在内存分配一个 倍size字节的存储区。 字节的存储区 调用结果为新分配的存储区的首地址,是一个void 调用结果为新分配的存储区的首地址,是一个 类型指针。若分配失败 则返回NULL(即0)。 失败, 类型指针。若分配失败,则返回 ( ) 例如: 例如: int i,*ip; i,*ip; 动态分配了10个存放整 动态分配了 个存放整 ip=(int *)calloc(10,2); *)calloc(10, 型数据的存储单元 for (i=0; i<10; i++) (i=0 i<10; scanf("%d",ip+i); scanf("%d",ip+i);
图 动态单向链表示意图
链表中每个元素称为一个结点。 ① 链表中每个元素称为一个结点。 相邻结点的地址不一定是连续的, ② 相邻结点的地址不一定是连续的,依靠指针将它们 连接起来。 连接起来。 构成链表的结点必须是结构体类型数据。 ③ 构成链表的结点必须是结构体类型数据。
6
P310 例9.8 补充练习1 补充练习 struct tt { int x; struct tt *y; }*p; struct tt a[4]={20,a+1,15,a+2,30,a+3,17,a}; main() { int i; p=a; for(i=1;i<=2;i++) { printf(“%d”,p->x); p=p->y; } }
NULL Zhang 62783410
struct node { char name[20],tel[12]; struct node *next; };
p q p q
Wang 63212986 NULL
malloc开辟新结点用 指示 开辟新结点用p指示 开辟新结点用 strcpy(p->name,name) gets(p->tel) p->next=NULL h==NULL
p
p
p
NULL
p
NULL
12
void prlist(struct node *head) { struct node *p; *p; p=head; //p指向第一个结点 p=head; //p指向第一个结点 while (p!=NULL) { printf(“name:%s\ntel:%s\n",p->name,p->tel); printf(“name: ntel: n",p->name,p->tel); p=p->next; //p指向下一个结点 p=p->next; //p指向下一个结点 } } void main( ) { struct node *head; *head; …… head=create(); head=create(); prlist(head); prlist(head); …… }
T head==NULL F
插入结点工 作分两步: 作分两步: 查找插 入位置
head=p; p->next =NULL; NULL; NULL
空表时 插入 结点 在表头 插入结点
q1=q2=head while(q2!=NULL &&strcmp(p->name,q2->name)!=0) NULL q1跟随 指针后移查找 (q1=q2;q2=q2->next;) 跟随q2指针后移查找 跟随 q2!= NULL != T F q2==head T F q1->next=p head=p q1->next=p p->next=NULL NULL p->next=q2 在链表指定位置前插入结点的N-S图 图 在链表指定位置前插入结点的 图
2
此函数无 返回值
⑶ 释放动态分配存储区函数free( ) 释放动态分配存储区函数free( 函数原型: free( p); 函数原型:void free(void *p); 调用格式:free(p) 调用格式:free(p) 功能:释放p所指向的动态分配的存储区。 功能:释放p所指向的动态分配的存储区。 实参p必须是一个指向动态分配存储区 的指针,它可以是任何类型的指针变量。 的指针,它可以是任何类型的指针变量。
3
1. #include<stdio.h> #include<stdlib.h> void main() { char *s1,*s2,m; s1=s2=(char *)malloc(sizeof(char)); *s1=15; *s2=20; m=*s1+*s2; printf(“%d\n”,m); }
新的第i个结点 新的第 个结点
14
第i个结点 个结点
NULL
q2 q1
q2 q1->next=p; p->next=q2;
【例】在学生电话簿链表中插入一个学生的信息。 在学生电话簿链表中插入一个学生的信息。 若已存在该生信息则要求将新的信息插入在已 有信息之前,否则追加在链表尾部。 有信息之前,否则追加在链表尾部。
5
结构体的应用——链表 结构体的应用——链表(9.4) 链表(9.4) 1. 链表的基本结构
struct node {char c; struct node *next; };
链表是一种动态数据结构, 头指针 链表是一种动态数据结构,可根据需要 第一结点 动态地分配存储单元。在数组中, 动态地分配存储单元。在数组中,插入或删 head 1000 1032 3284 1296 1382 2008
q p
NULL
li 68812999
T F h指向第一个 连接新结点 指向第一个 q->next=p 结点 h=p q指向新的尾结点 q=p 指向新的尾结点 读入一个学生姓名name 读入一个学生姓名
NULL
图 建立单向链表 8
#include <stdio.h> #include <stdlib.h> #include <string.h> struct node { char name[20],tel[12]; struct node *next; };
9
struct node *create( void ) { struct node *p,*q,*h=NULL; char name[20]; printf("name: "); gets(name); while (strlen(name)!=0) /* 当输入的姓名不是空串循环 */ { // 开辟新结点 p= (struct node *)malloc(sizeof(struct node)); // 为新结点中的成员赋值 strcpy(p->name,name); printf("tel: "); gets(p->tel); p->next=NULL;
11
4. 输出单向链表中各结点信息
p指向第一个结点 p=h 指向第一个结点 不为NULL 当p不为 不为
【例】输出学生电话簿链表函数 输出学生电话簿链表函数。
输出结点数据 p指向下一个结点 指向下一个结点 p=pp=p->next 输出链表的N-S图 图 输出链表的 图
h
Zhang 62783410 Wang 63212986 Li 68752341
连接 新结点
在表中间 插入结点
在表尾 追加结点
15
struct node *insert(struct node *head, struct node *p) { struct node *q1,*q2; if (head==NULL) 空表时, { head=p; p->next=NULL; } /* 空表时,插入结点 */ else { q1=q2=head; while (q2!=NULL &&strcmp(p->name,q2->name)!=0) {q1=q2;q2=q2->next;} if (q2!=NULL) { if (q2==head) head=p; /* 在表头插入结点 */ else q1->next=p; /* 在表中间插入结点 */ p->next=q2; } else { q1->next=p; p->next=NULL; } /* 在表尾插入结点 */ } return head ; 16 }
7
3. 建立单向链表
【例】建立一个学生电话簿 的单向链表函数。 的单向链表函数。 建立链表就是根据需要一个一个地开 头指针h设为 设为NULL 头指针 设为 辟新结点, 辟新结点,在结点中存放数据并建立结点 读入一个学生姓名name 读入一个学生姓名 之间的链接关系。 h 之间的链接关系。 当姓名长度不为0 当姓名长度不为
1000
除一个元素都比较繁琐, N 除一个元素都比较繁琐,而用链表则相对容 C H A G E 但是数组元素的引用比较简单, 易。但是数组元素的引用比较简单2008对于链 , 3284 1296 1382 1032 NULL 表中结点数据的存取操作则相对复杂。 表中结点数据的存取操作则相对复杂。 尾结点
2. 动态分配和释放存储单元
单向链表是一种动态数据结构,其结点数是变化的。 单向链表是一种动态数据结构,其结点数是变化的。因此应 用堆内存是最佳选择。 用堆内存是最佳选择。
8.8 堆内存空间的开辟和释放 动态分配存储区函数malloc( ) ⑴ 动态分配存储区函数 函数原型: 函数原型:void *malloc(unsigned size); 调用格式: 调用格式:malloc(size) 字节的存储区。 功能:在内存分配一个size字节的存储区 功能:在内存分配一个size字节的存储区。调用 结果为新分配的存储区的首地址,是一个void 结果为新分配的存储区的首地址,是一个 类型指针。若分配失败 则返回NULL(即0)。 失败, 类型指针。若分配失败,则返回 ( ) 需要包含头文件: 需要包含头文件: stdlib.h 或者 malloc.h
10
//建立链接关系 //建立链接关系 if (h==NULL) /* h为空,表示新结点为第一个结点 */ 为空, h=p; /* 头指针指向第一个结点 */ else /* h不为空 */ q->next=p; /* 新结点与尾结点相连接 */ q=p; /* 使q指向新的尾结点 */ printf("name: "); gets(name); } return h; } void main( ) { struct node *head; *head; …… head=create(); head=create(); …… }
4
2.若指针 已经正确定义 , 要使 指向两个连续的整 若指针p已经正确定义 要使p指向两个连续的整 若指针 已经正确定义, 型动态存储单元,不正确的语句是( 型动态存储单元,不正确的语句是() A)p=2*(int *)malloc(sizeof(int)); B)p=(int *)malloc(2*sizeof(int)); C)p=(int *)malloc(2*2); D)p=(int *)calloc(2,sizeof(int)); 3.有以下程序:若输入:abc def<回车 则输出: 有以下程序:若输入: 回车>,则输出 有以下程序 回车 则输出: #include<stdlib.h> main() { char *p,*q; p=(char*)malloc(sizeof(char)*20);q=p; scanf(“%s%s”,p,q); printf(“%s %s\n”,p,q); }
13
Βιβλιοθήκη Baidu
5. 在单向链表中插入结点 单向链表中插入 插入结点
将一个新结点插入到链表中,首先要寻找插入的位置。 将一个新结点插入到链表中,首先要寻找插入的位置。 如果要求在第i个结点前插入,可设置三个工作指针p 如果要求在第i个结点前插入,可设置三个工作指针p、q1 q2, 是指向待插入结点的指针。利用q1和q2指针查 指针查找 和q2,p是指向待插入结点的指针。利用q1和q2指针查找 个结点,找到后再将新结点链接到链表上。 第i个结点,找到后再将新结点链接到链表上。 h q2 q1 p