动态内存分配

动态内存分配及练习
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;
    }
}

原文地址:https://www.cnblogs.com/qinkai/p/2429592.html