动态内存分配及练习
malloc与free使用时的注意事项:
1)配对使用,有一个malloc,就应该有一个
free
2)尽量在同一层上使用,不要出现malloc在函
数中,而free在函数外。最好在同一调用层上
使用这两个函数
3)malloc分配的内存一定要初始化
free后的指针不允许再使用
链表的基本操作
链表的构成:
链表通过在每个结构体变量中设置指向下一个变量的指针域,并存入下一个变量的地址,
实现将一组结构体变量链成一条链表
链表中的每个结构体变量称为该链表的一个节点,每个节点的单元一般都没有名字,它们是
通过动态分配函数生成的
链表作为一个线性存储结构,链表的使用比数组灵活的多,因为构造一个链表时不一定在程序中
指定链表的长度(节点的个数),可以在程序的运行过程中动态动态的生成一个链表而且链表使
用完后还可以通过函数free释放掉整个链表空间。
链表的每个结点都分为两个域,一个是数据域,存放各种实际的数据,另一个域为指针域,
存放下一结点的首地址
链表中的每一个结点都是同一种结构类型
链表的基本操作对链表的主要操作有以下几种:
1.建立链表;
2.遍历输出;
3.结构的查找与输出;
4.插入一个结点;
5.删除一个结点;
6.链表排序
建立动态链表
指在程序执行过程中从无到有地建立起一个链表,即一个一个地
开辟结点和输入各结点数据,并建立起前后相链的关系
一般有两种形式
正挂—即先建立链头,让链头指向首先开辟并输入数据的第一个结点;然后开辟并输入第二个结点
数据,将其“挂”到第一个结点之后..即按输入顺序将结点“挂”接在一起
倒挂—最先输入的结点作尾结点,后输入的结点始终“挂”在链头上,即按由后向前的顺序建立链表
链表的插入分为四种情况:
① 原表是空表:只需使head指向被插结点即可
② 在第一个结点之前插入:使head指向被插结点,被插
结点的指针域指向原来的第一结点即可
③ 在其它位置插入:使插入位置的前一结点的指针域指
向被插结点,使被插结点的指针域指向插入位置的后
一结点
④ 在表末插入,使原表末结点指针域指向被插结点,被
插结点指针域置为NULL
链表删除:
删除是将某一结点从链中摘除,即将待删结点与其前一结点解除联系。
删除一个节点有两种情况:
1、被删除结点是第一个结点:只需使head指向第二个结点即可,即head=head->next
2、被删结点不是第一个结点:使被删结点的前一结点指向被删结点的后一结点即可,
即pf->next=pb->next
信息管理系统练习
《学生信息管理系统1》
1. 遍历输出
2. 链表查找
3. 链表插入
4. 链表删除
1. 设计保存学生信息的链表
4. 可随时添加学生信息,将新加入的学生信
息按学号顺序添加到链表中
2. 设计遍历输出函数
3. 设计查找函数,根据学号查找或姓名查找
5. 可随时删除学生信息,根据学号删除
习题答案
main.c:
#include "link.h"
void display(void)
{
system("cls");
printf("\r************************\n");
printf("***** 1、创建链表 *****\n");
printf("***** 2、增加节点 *****\n");
printf("***** 3、删除节点 *****\n");
printf("***** 4、查找链表 *****\n");
printf("***** 5、链表排序 *****\n");
printf("***** 6、输出链表 *****\n");
printf("***** 7、回收链表 *****\n");
printf("***** 0、退出程序 *****\n");
printf("************************\n");
printf("你要我做什么? 请选择^_^\n");
}
void fun(void)
{
stulink *student,*temp;
uint n = 0;
char ch = 0;
char flag = 0;
display();
while(1)
{
ch=getch();
switch(ch)
{
case '1'://创建链表
display();
printf("\n请输入链表的长度: ");
scanf("%d", &n);
student = creatlink(n);
printlink_all(student);
printf("你要我做什么? 请选择^_^\n");
break;
case '2'://增加节点
display();
printf("增加节点前的链表:\n\n");
printlink_all(student);
addtlink(student);
printf("增加节点后的链表:\n\n");
printlink_all(student);
printf("你要我做什么? 请选择^_^\n");
break;
case '3'://删除节点
display();
printf("删除节点前的链表:\n\n");
printlink_all(student);
printf("\n请要删除的学号: ");
scanf("%d", &n);
delettlink_element(&student,n);
printf("删除节点后的链表:\n\n");
printlink_all(student);
printf("你要我做什么? 请选择^_^\n");
break;
case '4'://查找链表
display();
printlink_all(student);
printf("请输入要查找的学号: ");
scanf("%d", &n);
temp = searchlink(student,n);
if(temp)
{
printf("\n为你找到的结果:\n");
printlink_element(temp);
}
else
{
printf("未找到此学号的学生信息!\n");
}
printf("你要我做什么? 请选择^_^\n");
break;
case '5'://链表排序
display();
printf("排序前节点前的链表:\n\n");
printlink_all(student);
inorderlink(&student);
printf("排序后节点后的链表:\n\n");
printlink_all(student);
printf("你要我做什么? 请选择^_^\n");
break;
case '6'://输出链表
display();
printf("排序后的链表:\n\n");
printlink_all(student);
printf("你要我做什么? 请选择^_^\n");
break;
case '7'://回收链表
display();
freelink(student);
printf("你要我做什么? 请选择^_^\n");
break;
case '0'://退出程序
flag = 1;
break;
default:
display();
printf("\n按键非法,请重新输入!^_^\n");
break;
}
if(flag)
{
break;
}
}
}
int main(void)
{
fun();
return 0;
}
link.h:
#ifndef __link_h__
#define __link_h__
#include <stdlib.h>
#include <stdio.h >
#include <conio.h>
typedef unsigned char uchar;
typedef unsigned int uint;
typedef struct student
{
uint id;
uchar name[16];
uchar age;
struct student *next;
} stulink;
/*******************************************************
*功能: 创建一个具有n个节点的链表,并对其值进行初始化
*方式: 正挂
*参数: n: 链表的长度,即节点的个数
*返回值: 所创建链表的首地址
********************************************************/
extern stulink *creatlink(uint n);
/*******************************************************
*功能: 遍历输出链表
*参数: 链表的表头
*返回值: 无
********************************************************/
extern void printlink_all(stulink *head);
/*******************************************************
*功能: 链表查找
*参数: 链表的表头,要查找的学号
*返回值: 要输出链表的元素的首地址
********************************************************/
extern stulink *searchlink(stulink *head, uint id);
/*******************************************************
*功能: 链表输出
*参数: 要输出链表的元素的首地址
*返回值: 无
********************************************************/
extern void printlink_element(stulink *element);
/*******************************************************
*功能: 增加一个链表元素至链表结尾
*参数: 链表的元素的首地址
*返回值: 无
********************************************************/
extern void addtlink(stulink *head);
/*******************************************************
*功能: 删除一个链表元素
*参数: 链表的元素的首地址,学生的学号
*返回值: 无
********************************************************/
extern void delettlink_element(stulink **head, uint id);
/*******************************************************
*功能: 链表的元素按学号大小从小到大排序
*参数: 链表的元素的首地址
*返回值: 无
********************************************************/
void inorderlink(stulink **head);
/*******************************************************
*功能: 回收链表
*参数: 链表的元素的首地址
*返回值: 无
********************************************************/
void freelink(stulink *head);
#endif
link.c:
#include "link.h"
/*******************************************************
*功能: 创建一个具有n个节点的链表,并对其值进行初始化
*方式: 正挂
*参数: n: 链表的长度,即节点的个数
*返回值: 所创建链表的首地址
********************************************************/
stulink *creatlink(uint n)
{
stulink *head,*temp,*previous;
uint i;
for(i=0;i<n;i++)
{
temp = (stulink *)malloc(sizeof(stulink));
if(temp == NULL)
{
printf("内存分配失败,创建链表失败\n");
head = NULL;
break;
}
printf("请输入学号 姓名 年龄(中间用空格格开):");
scanf("%d %s %d", &(temp->id), &(temp->name), &(temp->age));
if(i==0)
{
previous = head = temp;
}
else
{
previous->next = temp;
previous = temp;
}
previous->next = NULL;
}
if(n == 0)
{
head = NULL;
}
return head;
}
/*******************************************************
*功能: 遍历输出链表
*参数: 链表的表头
*返回值: 无
********************************************************/
void printlink_all(stulink *head)
{
stulink *nextpr;
nextpr = head;
while(nextpr)
{
printf("学号:%d 姓名:%s 年龄:%d\n", nextpr->id, nextpr->name, nextpr->age);
nextpr = nextpr->next;
}
}
/*******************************************************
*功能: 链表查找
*参数: 链表的表头,要查找的学号
*返回值: 要输出链表的元素的首地址
********************************************************/
stulink *searchlink(stulink *head, uint id)
{
stulink *nextpr;
nextpr = head;
while(nextpr!=NULL)
{
if(nextpr->id == id)
{
return nextpr;
}
else
{
nextpr = nextpr->next;
}
}
return NULL;
}
/*******************************************************
*功能: 链表输出
*参数: 要输出链表的元素的首地址
*返回值: 无
********************************************************/
void printlink_element(stulink *element)
{
printf("学号:%d 姓名:%s 年龄:%d\n", element->id, element->name, element->age);
}
/*******************************************************
*功能: 增加一个链表元素至链表结尾
*参数: 链表的元素的首地址
*返回值: 无
********************************************************/
void addtlink(stulink *head)
{
stulink *nextpr,*temp;
nextpr = head;
while(nextpr)
{
temp = nextpr;
nextpr = nextpr->next;
}
nextpr = (stulink *)malloc(sizeof(stulink));
if(nextpr == NULL)
{
printf("内存分配失败,增加链表元素失败\n");
}
else
{
printf("请输入学号 姓名 年龄(中间用空格格开):");
scanf("%d %s %d", &(nextpr->id), nextpr->name, &(nextpr->age));
nextpr->next = NULL;
temp->next = nextpr;
}
}
/*******************************************************
*功能: 删除一个链表元素
*参数: 链表的元素的首地址,学生的学号
*返回值: 无
********************************************************/
void delettlink_element(stulink **head, uint id)
{
stulink *nextpr;
uint i = 0, j = 0; //i:链表元素个数
stulink **arry;
nextpr = *head;
while(nextpr)
{
i++;
if(nextpr->id==id)
{
j = i;
}
nextpr = nextpr->next;
}
if(j==0)
{
printf("未找到相应学号学生信息!\n");
}
else
{
arry = calloc(i,sizeof(arry));
nextpr = *head;
i = 0;
while(nextpr)
{
*(arry+i) = nextpr;//保存链表各元素地址
i++;
nextpr = nextpr->next;
}
if(i==0)
{
printf("这是一个空链表,不能删除元素!\n");
}
else
{
if(i==1)
{
printf("删除元素后,这是一个空链表!\n");
free(arry[0]);
*head = NULL;
}
else if(i>1 && j==1)
{
free(arry[0]);
*head = arry[1];
}
else if(i>1 && j>1 && j<=i)
{
arry[j-2]->next = arry[j-1]->next;
free(arry[j-1]);
}
}
free(arry);
}
}
/*******************************************************
*功能: 链表的元素按学号大小从小到大排序
*参数: 链表的元素的首地址
*返回值: 无
********************************************************/
void inorderlink(stulink **head)
{
stulink *nextpr,*temp;
uint i = 0,j,k; //i:链表元素个数
stulink **arry;
nextpr = *head;
while(nextpr)
{
i++;
nextpr = nextpr->next;
}
arry = calloc(i,sizeof(arry));
nextpr = *head;
for(j=0;j<i;j++)
{
*(arry+j) = nextpr;//保存链表各元素地址
nextpr = nextpr->next;
}
for(j=0;j<i-1;j++)//按照各链表元素的id从小到大排序,将各元素放入指针数组中
{
for(k=j+1;k<i;k++)
{
if((*(arry+j))->id > (*(arry+k))->id)
{
temp = *(arry+k);
*(arry+k) = *(arry+j);
*(arry+j)= temp;
}
}
}
*head = *arry;
for(j=0;j<i-1;j++) //按照指针数组中的各链表元素的地址的顺序重新给链表安排指针域
{
(*(arry+j))->next = *(arry+j+1);
}
(*(arry+i-1))->next = NULL;
free(arry);
}
/*******************************************************
*功能: 回收链表
*参数: 链表的元素的首地址
*返回值: 无
********************************************************/
void freelink(stulink *head)
{
stulink *temp;
while(head)
{
temp=head->next;
free(head);
head=temp;
}
}