精华内容
下载资源
问答
  • c语言链表

    2017-05-01 23:23:59
    c语言链表 1. 链表介绍 C语言的单向链表翻转是面试官常问问题之一,故此,咱就谈一谈,链表并不是如此可怕,学不会,想不通. 链表和数组一样都是存储数据,链表是非连续,非顺序的存储结构. 链表是灵活的内存...

    c语言链表

    1. 链表介绍

    C语言的单向链表翻转是面试官常问问题之一,故此,咱就谈一谈,链表并不是如此可怕,学不会,想不通.

    链表和数组一样都是存储数据,链表是非连续,非顺序的存储结构.

    链表是灵活的内存动态管理(随机分配空间),删除创建结点非常方便

    链表组成:由一系列结点组成.

    链表结点:实际上是结构体变量.

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    链表结点包含两个部分:

    1.存储数据元素的数据域(结构体),

    2.存储下一个结点地址的指针域.

    clip_image002

    上图中的就是一个简单的单向链表,明白了单向链表就可以进军其余的链表结构了,都是一一相通的.

    结点:data数据域就是存放的结构体(含有各种数据),或者理解为int data;

    next就是链表的核心了,就是一个指针,指向下一个结点,与下一个结点建立联系.

    2. 链表和数组的区别

    数组:一次性分配连续的存储区域,int num[60] = {0};

    优点:随机访问元素效率高

    缺点:

    l 开辟内存过大时,易分配失败

    l 插入和删除元素效率低下

    链表:无需一次性分配连续的存储空间,只需要分配n快结点存储区域,通过指针建立联系

    优点:

    l 不需要一次性分配连续的存储区域

    l 删除和插入效率高

    缺点:

    随机访问元素效率低

    3. 链表分类

    l 1. 静态链表和动态链表

    链表按照线性表链式存储结构分为静态链表和动态链表

    静态链表:是在初始化的时候分配好足够的内存空间,存储空间是静态的,分配在栈上,模拟数组实现的,是顺序的存储结构

    动态链表:是动态申请内存的,每个节点物理地址不连续

    静态链表实例:

    #pragma warning(disable:4996)

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    // 定义链表结点

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    int main(int argc, char *argv[])

    {

    // 初始化三个链表结点(结构体)

    Link_Node Node1 = {1,NULL};

    Link_Node Node2 = {2,NULL};

    Link_Node Node3 = {3,NULL};

    // 链表串联起来,第一个结点指向第二个

    Node1.next = &Node2;// Node1的next指针指向Node2

    Node2.next = &Node3;

    Node3.next = NULL;// 尾结点

    // 定义头结点,指向第一个结点

    Link_Node *head = &Node1;

    // 遍历链表,头结点-->尾结点

    while (head != NULL)

    {

    printf("data : [ %d ]\n",head->data);

    // 指针下移

    head = head->next;

    }

    printf("hello...\n");

    system("pause");

    return 0;

    }

    动态链表实例:

    #pragma warning(disable:4996)

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    // 定义链表结点

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    int main(int argc, char *argv[])

    {

    // 动态申请3个结点

    Link_Node *Node1 = (Link_Node *)malloc(sizeof(Link_Node));

    // 初始化数据域

    Node1->data = 1;// Node是指针所以用指向箭头

    Link_Node *Node2 = (Link_Node *)malloc(sizeof(Link_Node));

    Node2->data = 2;

    Link_Node *Node3 = (Link_Node *)malloc(sizeof(Link_Node));

    Node3->data = 3;

    // 建立结点关系

    Node1->next = Node2;// Node1的next指向Node2;

    Node2->next = Node3;

    Node3->next = NULL;

    // 定义头结点指向第一个结点Node1

    Link_Node *head = Node1;

    // 遍历链表

    while (head != NULL)

    {

    printf("data:[ %d ]\n",head->data);

    // 指针下移

    head = head->next;

    }

    printf("hello...\n");

    system("pause");

    return 0;

    }

    l 2. 带头链表和不带头链表

    n 带头链表:固定一个节点作为头结点,不关心数据域,起一个标志位的作用,链表结点如何变化,此头结点固定不变

    clip_image004

    n 不带头结点:头结点不固定,所有结点都可以作为头,可以随机变化

    clip_image006

    链表按照类型:又划分为:单链表,双链表,循环链表

    单向链表:

    clip_image006[1]

    双向链表:

    clip_image008

    循环链表:

    clip_image010

    双向循环链表

    clip_image012

    4. 链表的基本操作à基于单向链表

    1. 创建链表结点域

    链表结点:数据域和指针域à结构体

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    2. 创建链表

    建立带头结点的单向链表,循环创建结点,结点数值为<=0时,作为结束,链表的头结点地址作为函数值返回.

    Link_Node* Init_Link_Node()

    {

    Link_Node *cur = NULL;// 保存上一个结点

    Link_Node *pNew = NULL;// 辅助指针

    Link_Node *head = NULL;// 固定为头结点

    // 创建头结点

    pNew = (Link_Node *)malloc(sizeof(Link_Node));

    // 初始化头结点(有头结点不保证数据安全)

    pNew->data = -1;

    pNew->next = NULL;

    head = cur = pNew;// head作为头结点,cur保存结点

    // 循环创建结点

    int dataid = 0;

    while (1)

    {

    printf("请输入data id编号:");

    scanf("%d",&dataid);

    if (dataid <= 0)

    {

    break;// 跳出循环

    }

    // 创建新结点

    pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 建立关联,头结点指向新结点

    cur->next = pNew;// 此时head已经指向了新结点

    pNew->next = NULL;

    cur = pNew;// 指针下移

    }

    return head;

    }

    3. 遍历链表

    // 遍历结点,传入链表

    int Print_Link_Node(Link_Node *head)

    {

    if (head == NULL)

    {

    return -1;

    }

    // 保存链表(带头链表的除了头之外的链表)

    Link_Node *cur = head->next;

    printf("head --> ");

    while (cur != NULL)

    {

    // 打印结点数据域

    printf("%d --> ",cur->data);

    // 指针下移操作

    cur = cur->next;

    }

    printf("NULL \n");// cur指向了NULL

    }

    4. 在头部插入结点

    // 头插法

    void Init_Head_Link_Node(Link_Node *head,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // 保存第一个有效结点

    Link_Node *cur = head->next;

    // 创建新结点

    Link_Node *pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 建立关系

    head->next = pNew;

    pNew->next = cur;

    }

    5.尾部插入

    // 尾插法

    void Init_Tail_Link_Node(Link_Node *head,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // 保存结点,获取最后一个结点

    Link_Node *cur = head;

    while (cur->next != NULL)

    {

    // 结点后移

    cur = cur->next;

    }

    // 创建新结点,插入

    Link_Node *pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 尾结点的next指向新结点

    cur->next = pNew;

    // 新结点的next指向NULL

    pNew->next = NULL;

    }

    6.指定位置

    // 找到data为num的前面插入,找不到就尾插

    void Init_Insert_Link_Node(Link_Node *head,int num,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // cur为第一个有效结点

    Link_Node *cur = head->next;

    Link_Node *pre = head;//保存前结点

    while (cur != NULL)

    {

    if (cur->data == num)

    {

    break;

    }

    // 循环查找data

    // 指针下移

    pre = pre->next;

    cur = cur->next;

    }

    // 1.找到匹配结点,cur为匹配结点,pre为上一个结点

    // 2.没有找到,说明cur指向NULL,pre为cur的上一个结点

    // pre->next = cur

    // cur = NULL

    // 插入新结点

    Link_Node *pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 尾结点的next指向新结点

    pre->next = pNew;

    // 新结点的next指向NULL

    pNew->next = cur;

    }

    7. 删除指定data第一个值

    // 删除指定data第一个值

    void Del_Link_Node(Link_Node *head,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // cur为第一个有效结点

    Link_Node *cur = head->next;

    // pre保存cur的上个结点

    Link_Node *pre = head;

    // 没有找到匹配结点,1代表找到

    int flag = 0;

    while (cur != NULL)

    {

    if (cur->data == dataid)

    {

    // 找到匹配结点

    flag = 1;

    pre->next = cur->next;

    free(cur);

    cur = NULL;

    break;

    }

    pre = pre->next;

    cur = cur->next;

    }

    if (0 == flag)

    {

    printf("没有找到%d的结点\n",dataid);

    }

    }

    8.释放链表

    // 清空链表

    void Destroy_Link_Node(Link_Node *head)

    {

    Link_Node *cur = head;

    while (cur->next != NULL)

    {

    // 先保存下一个结点

    head = head->next;

    // 释放第一个结点

    free(cur);

    cur = NULL;

    // 当前结点下移

    cur = head;

    }

    printf("链表清空\n");

    }

    9.main函数

    int main(int argc, char *argv[])

    {

    // 创建链表

    Link_Node *headLink_Node = Init_Link_Node();

    Print_Link_Node(headLink_Node);

    // 头插

    Init_Head_Link_Node(headLink_Node,1111);

    // 尾插法

    Init_Tail_Link_Node(headLink_Node,2222);

    Print_Link_Node(headLink_Node);

    // 查找4,插入

    Init_Insert_Link_Node(headLink_Node,4,3333);

    Print_Link_Node(headLink_Node);

    // 删除2

    Del_Link_Node(headLink_Node,2);

    Print_Link_Node(headLink_Node);

    // 清空链表

    Destroy_Link_Node(headLink_Node);

    printf("hello...\n");

    system("pause");

    return 0;

    }

    展开全文
  • 掌握C语言链表

    2021-06-10 20:43:11
    链表是一种使用极其广泛的数据结构,它也可以用来作为实现栈、队列等数据结构的基础,链表没有像数组需要预先知道数据大小的缺点,可充分利用计算机内存,实现动态灵活的内存管理。除非需要频繁的通过下标来随机访问...
  • C语言链表详解附实例

    万次阅读 多人点赞 2020-03-11 23:43:02
    链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。链表和数组比较,不用事先确定存储空间,而是根据需要开辟内存单元。本文章实现了用C语言编写学生管理系统,可以实现添加、删除、增加..,等功能

    C语言链表详解附实例

    什么是链表

    链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。链表和数组比较,不用事先确定存储空间,而是根据需要开辟内存单元。
    下图1是最简单的一种链表(单向链表)的结构
    图一
    第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量。以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号 num,姓名 name,性别 sex 和成绩 score 等。另一个域为指针域,存放下一结点的首地址。链表中的每一个结点都是同一种结构类型。

    环境构建

    用的Visual Studio 2019软件
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在源文件中添加C文件
    在这里插入图片描述

    建立静态链表

    包含所需要的头文件

    #include<stdio.h> //标准输入输出头文件
    #include<stdlib.h>//包含了C、C++语言的最常用的系统函数
    

    宏定义相关变量

    #define LEN sizeof(struct Student)//宏定义节点长度得命名
    #define TYPE struct Student//宏定义结构体变量命名
    

    创建一个结构体

    struct Student//定义一个学生类型结构体,包括学号,分数
    {
    	long num;
    	float score;
    	struct Student* next;//next是指针变量,指向结构体变量
    };
    //指向结构体对象得指针变量既可以指向结构体变量,也可以指向结构体数组中得元素
    

    主函数

    int main()
    {
    	TYPE* head,*p;//定义头指针
    	struct Student a,b,c;//定义三个结构体变量
    	a.num = 101; a.score = 20;//分别对三个结点赋值
    	b.num = 102; b.score = 20;
    	c.num = 103; c.score = 20;
    	/*1、A.B则A为对象或者结构体
          2、A->B则A为指针,->是成员提取,A->B是提取A中的成员B,A只能是指向类、结构、联合的指针;*/
    	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;//使P指向下一个结点
    	} while (p != NULL);//直到指针域指向空值
    	return 0;
    }
    

    结果展示

    在这里插入图片描述

    说明

    将第一个结点的起始地址赋值给头指针head,将第二个结点的起始地址赋值给第一个结点的next成员,将第二个结点的起始地址赋给第一个结点的next…第三个结点的next赋值为NULL,这就形成了简单的链表。

    建立动态链表

    所谓建立动态链表是指在程序执行过程中从无到有地建立起一个 链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相连的关系。

    包含所需要的头文件

    #include<stdio.h> //标准输入输出头文件
    #include<stdlib.h>//包含了C、C++语言的最常用的系统函数
    #include<malloc.h>//动态存储分配函数头文件
    

    宏定义相关变量

    #define LEN sizeof(struct Student)//宏定义节点长度得命名
    #define TYPE struct Student//宏定义结构体变量命名
    

    创建一个结构体

    struct Student//定义一个学生类型结构体,包括学号,分数
    {
    	long num;
    	float score;
    	struct Student* next;//next是指针变量,指向结构体变量
    };
    //指向结构体对象得指针变量既可以指向结构体变量,也可以指向结构体数组中得元素
    

    建立链表函数

    TYPE* Creat(void)//定义函数,此函数返回一个指向链表头的指针
    {
    	TYPE* head;//定义头指针
    	TYPE* p1,*p2;//定义两个 指针变量用来相互保存
    	number = 0;//开始时,结点清零
    	p1 = p2 = (TYPE*)malloc(LEN);//创建存储空间
    	printf("请按格式输入学生学号,分数\n");//输出提示信息
    	printf("例如101,1 并以0,0结束\n");
    	scanf("%ld,%f", &p1->num, &p1->score);//按格式输入第一个结点的信息
    	head = NULL;//第一个结点头指针赋空值
    	while (p1->num!=0)//循环直到输入学生学号为0,就结束
    	{
    		number++;//结点自增
    		if (number == 1)//如果只有一个结点,那么头指针指向第一个输入的结点
    			head = p1;
    		else
    			p2->next = p1;//如果大于1个,那么要用next保存前一个结点的信息
    		p2 = p1;//保存前一个结点信息
    		p1 = (TYPE*)malloc(LEN);//开辟新的结点
    		scanf("%ld,%f", &p1->num, &p1->score);//输入下一个结点信息
    	}
    	p2->next = NULL;//循环结束,将指向信息赋空值
    	return (head);//返回首地址
    }
    

    主函数

    int main()
    {
    	TYPE* pt;//定义一个结构体指针变量
    	pt = Creat();//函数返回链表第一个结点的地址
    	printf("\nnum:%ld\nscore:%5.lf\n", pt->num,pt->score);//输出第一个结点的成员值
    	return 0;
    }
    

    结果展示

    在这里插入图片描述
    == 文中最后结果显示的是第一个结点的内容,作为有强大功能的链表,对他的操作当然有许多,比如:链表的创建,修改,删除,插入,输出,排序,反序,清空链表的元素,求链表的长度等等。==

    链表的输出

    用循环直接可以输出链表

    输出函数

    void print(TYPE * head)
    {
    	TYPE * p;//定义指针
    	printf("\nNOW These %d records are:\n");//输出显示信息
    	p = head;//使p指向第一个结点
    	if(head!=NULL)//输出第一个结点后的信息
    		do {
    			printf("%ld %5.1f\n",p->num,p->score);
    			p = p->next;//指向下个结点
    		} while (p != NULL);
    }
    
    

    主函数

    int main()
    {
    	TYPE * pt;//定义一个结构体指针变量
    	pt = Creat();//函数返回链表第一个结点的地址
    	print(pt);//输出调用
    	return 0;
    }
    

    链表的修改

    修改函数

    修改链表节点值很简单。下面是一个传入链表和要修改的节点,来修改值的函数.

    void change(TYPE* head, int n) //修改指定位置的结点的信息
    {
    	TYPE* p = head;//传入首地址
    	int i = 0;
    	while (i < n && p != NULL) {
    		p = p->next;
    		i++;
    	}//找到相应的位置结点
    	if (p != NULL) {
    		printf("输入要修改的值\n");
    		scanf("%ld,%f", &p->num, &p->score);//输入下一个结点信息
    	}
    	else 
    		printf("节点不存在\n");
    	}
    

    主函数

    int main()
    {
    	TYPE* pt;//定义一个结构体指针变量
    	pt = Creat();//函数返回链表第一个结点的地址
    	change(pt,2);//修改相关结点的信息,假设修改第2+1个
    	print(pt);//输出调用
    	return 0;
    }
    

    ##链表的删除
    删除链表的元素也就是把前节点的指针域越过要删除的节点指向下下个节点。即:p->next = q->next;然后放出q节点的空间,即free(q);
    在这里插入图片描述

    删除函数

    void delet(TYPE* head, int n) {
    	TYPE* p = head, * in;//定义两边指针
    	int i = 0;
    	while (i < n && p != NULL) {
    		in = p;//找到左边的
    		p = p->next;//找到右边的
    		i++;
    	}
    	if (p != NULL) {
    		in->next = p->next;//将左右链接
    		free(p);//释放中间结点
    	}
    	else {
    		printf("节点不存在\n");
    	}
    
    }
    

    主函数

    int main()
    {
    	TYPE* pt;//定义一个结构体指针变量
    	pt = Creat();//函数返回链表第一个结点的地址
    	delet(pt,1);//删除第1+1个结点
    	print(pt);//输出调用
    	return 0;
    }
    

    输出结果

    在这里插入图片描述
    ##链表的插入
    我们可以看出来,插入节点就是用插入前节点的指针域链接上插入节点的数据域,再把插入节点的指针域链接上插入后节点的数据域。根据图,插入节点也就是:e->next = head->next; head->next = e;
    增加链表节点用到了两个结构体指针和一个int数据。

    在这里插入图片描述

    插入函数

    void insert(TYPE* head, int n) {//链表的插入
    	TYPE* p = head, * in;
    	int i = 0;
    	while (i < n && p != NULL) {
    		p = p->next;
    		i++;//找到相应结点
    	}
    	if (p != NULL) {
    		in = (TYPE*)malloc(sizeof(TYPE));//开辟新的空间
    		printf("输入要插入的值\n");
    		scanf("%ld,%f", &in->num, &in->score);//输入新的结点信息
    		in->next = p->next;//填充in节点的指针域,也就是说把in的指针域指向p的下一个节点
    		p->next = in;//填充p节点的指针域,把p的指针域重新指向in
    	}
    	else {
    		printf("节点不存在\n");
    	}
    
    }
    

    主函数

    int main()
    {
    	TYPE* pt;//定义一个结构体指针变量
    	pt = Creat();//函数返回链表第一个结点的地址
    	insert(pt, 1);//从1+1后插入
    	print(pt);//输出调用
    	return 0;
    }
    

    结果显示

    在这里插入图片描述

    出现的问题

    1、出现scanf 和printf 在VS2019中使用时会出错,解决办法如下
    在这里插入图片描述
    在这里插入图片描述

    最后是测试的所有源程序

    链接: https://download.csdn.net/download/xiaoxiaodawei/12242402.

    展开全文
  • C语言链表源代码

    2012-08-11 10:56:45
    从MTK 分离出来的C语言链表代码,使用独立内存管理
  • 2. 内存分配 以段为单位分配内存, 每个段在内存中占据连续 空间(内存随机分割, 需要多少分配多少), 但各段之间 可以不连续存放。 3.通过段表进行地址映射 段表记录各段的首(地)址和长度 4.内存的分配算法 首先适配...

    首先理解这几个概念

    1. 内存物理空间的划分

        内存空间被动态的划分为若干个长度不相同的 物理段, 每个物理段由起始地址和长度确定。 
    

    2. 内存分配

        以段为单位分配内存, 每个段在内存中占据连续 空间(内存随机分割, 需要多少分配多少), 但各段之间 可以不连续存放。 
    

    3.通过段表进行地址映射

        段表记录各段的首(地)址和长度 
    

    4.内存的分配算法

        首先适配(FF);最佳适配(BF);最坏适配(WF);
    
        首次适配算法:(特点:简单、快速分配) 
            当接到内存申请时, 查空闲块表(按地址有序), 找 到第一个不小于请求的空块, 将其分割并分配。 
    
        最佳适配算法: (特点:用最小空间满足要求)
            接到内存申请时, 在空闲块表(按容量递增有序) 中找到一个不小于请求的最小空块进行分配。 
    
        最坏适配算法: (特点:分割后空闲块仍较大)       
            接到内存申请时, 在空闲块表(按容量递减有序) 中找到一个不小于请求的最大空块进行分配。 
    
    #include<stdio.h>
    #include<stdlib.h>
    
    //常量
    #define PROCESS_NAME_LEN 32     //进程名长度
    #define MIN_SLICE 10            //最小碎片大小
    #define DEFAULT_MEM_SIZE 1024   //内存大小
    #define DEFAULT_MEM_START 0     //起始位置
    
    //内存分配算法
    #define MA_FF 1
    #define MA_BF 2
    #define MA_WF 3
    
    int mem_size = DEFAULT_MEM_SIZE;    //内存大小
    int ma_algorithm = MA_FF;           //当前算法
    static int pid = 0;                 //初始化pid
    int flag = 0;                       //设置内存大小标志
    
    //函数声明
    int display_menu();         //展示功能菜单
    int set_mem_size();         //设置申请内存空间大小 
    int set_algorithm();        //设置算法 
    int rearrange_FF();         //首次适配算法 
    int rearrange_BF();         //最优适配算法 
    int rearrange_WF();         //最坏适配算法 
    
    int kill_process();         //删除进程,归还分配的储存空间
    int do_exit();              //退出程序,释放空间 
    int display_mem_usage() ;   //显示当前内存的使用情况,包括空闲区和已经分配的情况
    int rearrange(int algorithm) ;              //选择算法 
    int free_mem(struct get_block *ab);     //释放链表 
    int allocate_mem(struct get_block *ab);     //分配内存模块 
    int dispose(struct get_block* free_ab);     //处理free后的链表 
    
    int FF();           //按地址由低到高排序 
    int BF();           //按内存大小由小到大排序 
    int WF();           //按内存大小由大到小排序 
    struct get_block* find_process(int pid);            //按pid找到需要释放的链表节点 
    struct free_block* init_free_block(int mem_size);   //初始化空闲块 
    
    //内存空闲分区
    struct free_block {
        int size;
        int start_addr;
        struct free_block* next;
    };
    struct free_block* free_b;//内存空闲块来链表的首指针
    
    
    //分配到内存块的描述
    struct get_block {
        int pid;
        int size;
        int start_addr;
        char process_name[PROCESS_NAME_LEN];
        struct get_block* next;
    };
    struct get_block* get_block_head = NULL; //进程分配内存块链表的首指针
    
    struct free_block*  init_free_block(int mem_size) {
        struct free_block *fb,*ptemp;
        get_block_head = (struct get_block*)malloc(sizeof(struct get_block));
        fb = (struct free_block*)malloc(sizeof(struct free_block));
        ptemp=(struct free_block*)malloc(sizeof(struct free_block));
        if (fb == NULL) {
            printf("No nen \n");
        }
        get_block_head->next=NULL;
        fb->next=ptemp;
        ptemp->size = mem_size;
        ptemp->start_addr = DEFAULT_MEM_START;
        ptemp->next = NULL;
        return fb;
    }
    
    int  display_menu()
    {
        printf("\n");
        printf("1- Set memory size (%d)\n",mem_size);
        printf("2- Select memory size allocation algorithm \n");
        printf("3- New process \n");
        printf("4- Terminate a process \n");
        printf("5- Display memory usage \n");
        printf("0- Exit\n");
        return 1;
    }
    
    int set_mem_size() {
        int size;
        if (flag != 0) {//防止重复设置 
            printf("Cannot set memory size again\n");
            return 0;
        }
        printf("Total memory size =");
        scanf("%d", &size);
        if (size>0) {
            mem_size = size;
            free_b->next->size = mem_size;
        }
        flag = 1;
        return 1;
    }
    int FF(){
        free_block* fbh=free_b->next;
        free_block* fbp=free_b->next;
        int sizep;
        int addrp;
        while(fbh!=NULL){
            while(fbp->next!=NULL){
                    if(fbp->start_addr>fbp->next->start_addr){
                        addrp=fbp->start_addr;
                        fbp->start_addr=fbp->next->start_addr;
                        fbp->next->start_addr=addrp;
                        sizep=fbp->size;
                        fbp->size=fbp->next->size;
                        fbp->next->size=sizep;                  
                    }
                    fbp=fbp->next;
            }
            fbp=free_b->next;
            fbh=fbh->next;
        }
        while(fbh!=NULL){
            printf("%d,%d",fbh->size,fbh->start_addr);
            fbh=fbh->next;
        }
        return 0;   
    }
    
    int rearrange_FF() {
        FF(); 
        return 0;
    }
    
    int BF(){
        free_block* fbh=free_b->next;
        free_block* fbp=free_b->next;
        int sizep;
        int addrp;
        while(fbh!=NULL){
            while(fbp->next!=NULL){
                    if(fbp->size>fbp->next->size){
                        addrp=fbp->start_addr;
                        fbp->start_addr=fbp->next->start_addr;
                        fbp->next->start_addr=addrp;
                        sizep=fbp->size;
                        fbp->size=fbp->next->size;
                        fbp->next->size=sizep;                  
                    }
                    fbp=fbp->next;
            }
            fbp=free_b->next;
            fbh=fbh->next;
        }
        while(fbh!=NULL){
            printf("%d,%d",fbh->size,fbh->start_addr);
            fbh=fbh->next;
        }   
        return 0;
    }
    
    int rearrange_BF() {
        BF();
        return 0;
    }
    
    int WF(){
        free_block* fbh=free_b->next;
        free_block* fbp=free_b->next;
        int sizep;
        int addrp;
        while(fbh!=NULL){
            while(fbp->next!=NULL){
                    if(fbp->size<fbp->next->size){
                        addrp=fbp->start_addr;
                        fbp->start_addr=fbp->next->start_addr;
                        fbp->next->start_addr=addrp;
                        sizep=fbp->size;
                        fbp->size=fbp->next->size;
                        fbp->next->size=sizep;                  
                    }
                    fbp=fbp->next;
            }
            fbp=free_b->next;
            fbh=fbh->next;
        }
        while(fbh!=NULL){
            printf("%d,%d",fbh->size,fbh->start_addr);
            fbh=fbh->next;
        }   
        return 0;
    }
    
    int rearrange_WF() {
        WF();
        return 0;
    }
    
    int rearrange(int algorithm) {
        switch (algorithm) {
        case MA_FF: rearrange_FF(); break;
        case MA_BF:rearrange_BF(); break;
        case MA_WF:rearrange_WF(); break;
        }
        return 0;
    }
    
    int set_algorithm() {
        int algorithm;
        printf("\t1 - First Fit \n");
        printf("\t2 - Best Fit \n");
        printf("\t3 - Worst Fit \n");
        scanf("%d", &algorithm);
        if (algorithm >= 1 && algorithm <= 3) {
            ma_algorithm = algorithm;
            //按指定算法重新排列空闲区链表
            rearrange(ma_algorithm);
        }
        return 0;
    }
    
    int allocate_mem(struct get_block *ab) {    //分配内存模块 
        struct free_block* fbt, *pre;
        int request_size = ab->size;
        fbt = pre = free_b->next;
        while(fbt!=NULL){
            if(fbt->size>=request_size){
                ab->start_addr=fbt->start_addr+fbt->size-request_size;  
                fbt->size=fbt->size-request_size;   
                return 1;
            }
            else {
                pre=fbt;
                fbt=fbt->next;  
            }
        }
        printf("空闲区不够!\n");
        return 0;
    }
    
    int new_process() {
        int size,ret;
        struct get_block *ab,*temp;
        ab = (struct get_block*)malloc(sizeof(struct get_block));
        temp=get_block_head->next;
        if (!ab) {
            exit(-5);
        }
        ab->next = NULL;    
        pid++;
        sprintf(ab->process_name, "PROCESS-%02d", pid);
        ab->pid = pid;
        printf("Memory for %s:\n", ab->process_name);
        scanf("%d", &size);
        ab->size = size;    
        ret = allocate_mem(ab);     //从空闲区分配内存,ret==1表示分配完成 
        if ((ret == 1) && (get_block_head->next == NULL)) {//get_b_h没有赋值,进行赋值 
            get_block_head->next= ab;
            printf("ret==1");
            return 1;
        }
        else if (ret == 1) {
            printf("分配成功\n");
            while(temp->next!=NULL){
                temp=temp->next;
            }
    
            temp->next=ab;
            return 2;
        }
        else if (ret == -1) {
            printf("Allocation fail\n");
            free(ab);
            return 1;
        }
        return 3;
    }
    
    struct get_block* find_process(int pid){
        get_block* get_temp=get_block_head;
        while(get_temp!=NULL){
            if(get_temp->pid==pid){
                return get_temp;
            }
            else{
                get_temp=get_temp->next;
            }
        }
        printf("操作错误\n");
        return NULL;
    } 
    
    int free_mem(struct get_block *ab) {
        int algorithm = ma_algorithm;
        struct free_block *fbt, *pre, *work;
        fbt = (struct free_block*) malloc(sizeof(struct free_block));
        if (!fbt) return -1;
        // 进行可能的合并,基本策略如下
        // 1. 将新释放的结点插入到空闲分区队列末尾
        // 2. 对空闲链表按照地址有序排列
        // 3. 检查并合并相邻的空闲分区
        // 4. 将空闲链表重新按照当前算法排序
        fbt->size=ab->size;
        fbt->start_addr=ab->start_addr;
        pre=free_b->next;
        while(pre->next!=NULL){
            pre=pre->next;
        }
        pre->next=fbt;
        fbt->next=NULL;
        FF();
        pre=free_b->next;
        while(pre->next!=NULL){
            if(pre->start_addr+pre->size==pre->next->start_addr){
                pre->size=pre->size+pre->next->size;
                if(pre->next->next!=NULL){
                    pre->next=pre->next->next;
                }else{
                        pre->next=NULL; 
                        break;
                }
            }
            pre=pre->next;
        }
        pre=free_b->next;
        while(pre->next!=NULL){
            if(pre->start_addr+pre->size==pre->next->start_addr){
                pre->size=pre->size+pre->next->size;
                if(pre->next->next!=NULL){
                    pre->next=pre->next->next;
                }else{
                        pre->next=NULL; 
                        break;
                }
            }
            pre=pre->next;
        }
        printf("内存紧缩完成");
        rearrange(ma_algorithm);
        return 1;
    }
    
    int dispose(struct get_block* free_ab){
        struct get_block *pre, *ab;
        if (free_ab == get_block_head) {//如果要释放第一个节点
            get_block_head = get_block_head->next;
            free(free_ab);
            return 1;
        }
        pre = get_block_head;
        ab = get_block_head->next;
        while (ab != free_ab) {
            pre = ab;
            ab = ab->next;
        }
        pre->next = ab->next;
        free(ab);
        return 2;
    }
    
    int display_mem_usage() {//显示当前内存的使用情况,包括空闲区和已经分配的情况
        struct free_block *fbt = free_b->next;
        struct get_block *ab = get_block_head->next;
    
        if (fbt == NULL) return 1;
        printf("------------------------------------\n");
    
        //显示空闲区
        printf("Free Memory:\n");
        while(fbt!=NULL){
            printf("%20d%20d\n", fbt->start_addr, fbt->size);
            fbt = fbt->next;
        }
        //显示已分配区
        printf("\nUsed Memory:\n");
        printf("%10s %20s %10s %10s \n", "PID", "ProcessName    ", "start_addr", "size");
        while (ab != NULL) {
            printf("%10d %20s %10d %10d \n",ab->pid,ab->process_name,ab->start_addr,ab->size);
            ab = ab->next;
        }
        printf("------------------------------------------\n");
        return 0;
    }
    int kill_process() {//删除进程,归还分配的储存空间
                        //,删除描述该进程的内存分配的节点
        struct get_block *ab;
        int pid;
        printf("Kill Process , pid =");
        scanf("%d",&pid);
        ab = find_process(pid);
        if (ab != NULL) {
            free_mem(ab);//释放ab表示的分配区
            dispose(ab);//释放ab数据结构的节点
        }
        return 0;
    }
    int do_exit() {
        struct get_block *temp;
        while (get_block_head != NULL) {
            temp = get_block_head;
            get_block_head = get_block_head->next;
            free(temp);
        }
        return 0;
    }
    int main() {
        char choice;
        pid = 0;
        free_b = init_free_block(mem_size);//初始化空闲区
        while (1) {
            display_menu();//显示菜单 
            fflush(stdin);
            choice = getchar();//获取用户输入 
            switch (choice) {
            case'1':set_mem_size();flag=1;break;        //设置内存大小 
            case'2':set_algorithm(); flag = 1; break;   //设置算法
            case'3':new_process(); flag = 1; break;     //创建新进程 
            case'4':kill_process(); flag = 1; break;    //删除进程 
            case'5':display_mem_usage(); flag = 1; break;//显示内存使用
            case'0': do_exit(); exit(0);                //释放链表退出 
            default:break;
            }
        }
    }
    
    展开全文
  • c语言链表详解

    万次阅读 多人点赞 2016-11-24 16:56:33
    c语言链表 1. 链表介绍 c语言的单向链表翻转是面试官常问问题之一,故此,咱就谈一谈,链表并不是如此可怕,学不会,想不通. 链表和数组一样都是存储数据,链表是非连续,非顺序的存储结构. 链表是灵活的内存动态管理(随机...

    c语言链表

    1. 链表介绍

    c语言的单向链表翻转是面试官常问问题之一,故此,咱就谈一谈,链表并不是如此可怕,学不会,想不通.

    链表和数组一样都是存储数据,链表是非连续,非顺序的存储结构.

    链表是灵活的内存动态管理(随机分配空间),删除创建结点非常方便

    链表组成:由一系列结点组成.

    链表结点:实际上是结构体变量.

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    链表结点包含两个部分:

    1.存储数据元素的数据域(结构体),

    2.存储下一个结点地址的指针域.

    clip_image002

    上图中的就是一个简单的单向链表,明白了单向链表就可以进军其余的链表结构了,都是一一相通的.

    结点:data数据域就是存放的结构体(含有各种数据),或者理解为int data;

    next就是链表的核心了,就是一个指针,指向下一个结点,与下一个结点建立联系.

    2. 链表和数组的区别

    数组:一次性分配连续的存储区域,int num[60] = {0};

    优点:随机访问元素效率高

    缺点:

    l 开辟内存过大时,易分配失败

    l 插入和删除元素效率低下

    链表:无需一次性分配连续的存储空间,只需要分配n快结点存储区域,通过指针建立联系

    优点:

    l 不需要一次性分配连续的存储区域

    l 删除和插入效率高

    缺点:

    随机访问元素效率低

    3. 链表分类

    l 1. 静态链表和动态链表

    链表按照线性表链式存储结构分为静态链表和动态链表

    静态链表:是在初始化的时候分配好足够的内存空间,存储空间是静态的,分配在栈上,模拟数组实现的,是顺序的存储结构

    动态链表:是动态申请内存的,每个节点物理地址不连续

    静态链表实例:

    #pragma warning(disable:4996)

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    // 定义链表结点

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    int main(int argc, char *argv[])

    {

    // 初始化三个链表结点(结构体)

    Link_Node Node1 = {1,NULL};

    Link_Node Node2 = {2,NULL};

    Link_Node Node3 = {3,NULL};

    // 链表串联起来,第一个结点指向第二个

    Node1.next = &Node2;// Node1的next指针指向Node2

    Node2.next = &Node3;

    Node3.next = NULL;// 尾结点

    // 定义头结点,指向第一个结点

    Link_Node *head = &Node1;

    // 遍历链表,头结点-->尾结点

    while (head != NULL)

    {

    printf("data : [ %d ]\n",head->data);

    // 指针下移

    head = head->next;

    }

    printf("hello...\n");

    system("pause");

    return 0;

    }

    动态链表实例:

    #pragma warning(disable:4996)

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    // 定义链表结点

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    int main(int argc, char *argv[])

    {

    // 动态申请3个结点

    Link_Node *Node1 = (Link_Node *)malloc(sizeof(Link_Node));

    // 初始化数据域

    Node1->data = 1;// Node是指针所以用指向箭头

    Link_Node *Node2 = (Link_Node *)malloc(sizeof(Link_Node));

    Node2->data = 2;

    Link_Node *Node3 = (Link_Node *)malloc(sizeof(Link_Node));

    Node3->data = 3;

    // 建立结点关系

    Node1->next = Node2;// Node1的next指向Node2;

    Node2->next = Node3;

    Node3->next = NULL;

    // 定义头结点指向第一个结点Node1

    Link_Node *head = Node1;

    // 遍历链表

    while (head != NULL)

    {

    printf("data:[ %d ]\n",head->data);

    // 指针下移

    head = head->next;

    }

    printf("hello...\n");

    system("pause");

    return 0;

    }

    l 2. 带头链表和不带头链表

    n 带头链表:固定一个节点作为头结点,不关心数据域,起一个标志位的作用,链表结点如何变化,此头结点固定不变

    clip_image004

    n 不带头结点:头结点不固定,所有结点都可以作为头,可以随机变化

    clip_image006

    链表按照类型:又划分为:单链表,双链表,循环链表

    单向链表:

    clip_image006[1]

    双向链表:

    clip_image008

    循环链表:

    clip_image010

    双向循环链表

    clip_image012

    4. 链表的基本操作à基于单向链表

    1. 创建链表结点域

    链表结点:数据域和指针域à结构体

    typedef struct _LINKNODE

    {

    int data;// 数据域

    struct _LINKNODE *next;// 指针域

    }Link_Node;

    2. 创建链表

    建立带头结点的单向链表,循环创建结点,结点数值为<=0时,作为结束,链表的头结点地址作为函数值返回.

    Link_Node* Init_Link_Node()

    {

    Link_Node *cur = NULL;// 保存上一个结点

    Link_Node *pNew = NULL;// 辅助指针

    Link_Node *head = NULL;// 固定为头结点

    // 创建头结点

    pNew = (Link_Node *)malloc(sizeof(Link_Node));

    // 初始化头结点(有头结点不保证数据安全)

    pNew->data = -1;

    pNew->next = NULL;

    head = cur = pNew;// head作为头结点,cur保存结点

    // 循环创建结点

    int dataid = 0;

    while (1)

    {

    printf("请输入data id编号:");

    scanf("%d",&dataid);

    if (dataid <= 0)

    {

    break;// 跳出循环

    }

    // 创建新结点

    pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 建立关联,头结点指向新结点

    cur->next = pNew;// 此时head已经指向了新结点

    pNew->next = NULL;

    cur = pNew;// 指针下移

    }

    return head;

    }

    3. 遍历链表

    // 遍历结点,传入链表

    int Print_Link_Node(Link_Node *head)

    {

    if (head == NULL)

    {

    return -1;

    }

    // 保存链表(带头链表的除了头之外的链表)

    Link_Node *cur = head->next;

    printf("head --> ");

    while (cur != NULL)

    {

    // 打印结点数据域

    printf("%d --> ",cur->data);

    // 指针下移操作

    cur = cur->next;

    }

    printf("NULL \n");// cur指向了NULL

    }

    4. 在头部插入结点

    // 头插法

    void Init_Head_Link_Node(Link_Node *head,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // 保存第一个有效结点

    Link_Node *cur = head->next;

    // 创建新结点

    Link_Node *pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 建立关系

    head->next = pNew;

    pNew->next = cur;

    }

    5.尾部插入

    // 尾插法

    void Init_Tail_Link_Node(Link_Node *head,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // 保存结点,获取最后一个结点

    Link_Node *cur = head;

    while (cur->next != NULL)

    {

    // 结点后移

    cur = cur->next;

    }

    // 创建新结点,插入

    Link_Node *pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 尾结点的next指向新结点

    cur->next = pNew;

    // 新结点的next指向NULL

    pNew->next = NULL;

    }

    6.指定位置

    // 找到data为num的前面插入,找不到就尾插

    void Init_Insert_Link_Node(Link_Node *head,int num,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // cur为第一个有效结点

    Link_Node *cur = head->next;

    Link_Node *pre = head;//保存前结点

    while (cur != NULL)

    {

    if (cur->data == num)

    {

    break;

    }

    // 循环查找data

    // 指针下移

    pre = pre->next;

    cur = cur->next;

    }

    // 1.找到匹配结点,cur为匹配结点,pre为上一个结点

    // 2.没有找到,说明cur指向NULL,pre为cur的上一个结点

    // pre->next = cur

    // cur = NULL

    // 插入新结点

    Link_Node *pNew = (Link_Node *)malloc(sizeof(Link_Node));

    pNew->data = dataid;

    // 尾结点的next指向新结点

    pre->next = pNew;

    // 新结点的next指向NULL

    pNew->next = cur;

    }

    7. 删除指定data第一个值

    // 删除指定data第一个值

    void Del_Link_Node(Link_Node *head,int dataid)

    {

    if (head == NULL)

    {

    return;

    }

    // cur为第一个有效结点

    Link_Node *cur = head->next;

    // pre保存cur的上个结点

    Link_Node *pre = head;

    // 没有找到匹配结点,1代表找到

    int flag = 0;

    while (cur != NULL)

    {

    if (cur->data == dataid)

    {

    // 找到匹配结点

    flag = 1;

    pre->next = cur->next;

    free(cur);

    cur = NULL;

    break;

    }

    pre = pre->next;

    cur = cur->next;

    }

    if (0 == flag)

    {

    printf("没有找到%d的结点\n",dataid);

    }

    }

    8.释放链表

    // 清空链表

    void Destroy_Link_Node(Link_Node *head)

    {

    Link_Node *cur = head;

    while (cur->next != NULL)

    {

    // 先保存下一个结点

    head = head->next;

    // 释放第一个结点

    free(cur);

    cur = NULL;

    // 当前结点下移

    cur = head;

    }

    printf("链表清空\n");

    }

    9.main函数

    int main(int argc, char *argv[])

    {

    // 创建链表

    Link_Node *headLink_Node = Init_Link_Node();

    Print_Link_Node(headLink_Node);

    // 头插

    Init_Head_Link_Node(headLink_Node,1111);

    // 尾插法

    Init_Tail_Link_Node(headLink_Node,2222);

    Print_Link_Node(headLink_Node);

    // 查找4,插入

    Init_Insert_Link_Node(headLink_Node,4,3333);

    Print_Link_Node(headLink_Node);

    // 删除2

    Del_Link_Node(headLink_Node,2);

    Print_Link_Node(headLink_Node);

    // 清空链表

    Destroy_Link_Node(headLink_Node);

    printf("hello...\n");

    system("pause");

    return 0;

    }

    展开全文
  • 链表: 1)链表分类: 表头:只有指针域 节点:指针域+数据域 指针域指向下一节点数据域,指针域为下一节点的首地址 即ptemp->next=pnew 表尾:指针域+数据域 指针域指向为NUL 2)链表是链式存贮结构,在空间内...
  • C语言链表及链表上机题.ppt第13讲 链表,链表概述(1),所谓链表是指若干个数据项(每个数据项称为一个“结点”)按一定的原则连接起来。每个数据项都包含有若干个数据和一个指向下一个数据项的指针,依靠这些指针将所有...
  • 链表是一种使用极其广泛的数据结构,它也可以用来作为实现栈、队列等数据结构的基础,链表没有像数组需要预先知道数据大小的缺点,可充分利用计算机内存,实现动态灵活的内存管理。除非需要频繁的通过下标来随机访问...
  • C语言链表

    2021-05-27 14:27:40
    链表是一种“链式”存储数据的结构,通过指针,可以把每一个元素连接起来,形成一个数据集合。假设有如下3个int类型的变量: int a1, a2, a3; 那么,我们可以把它组成一个集合,如下: 可以看到,a1、a2、a3...
  • C语言链表实现商品库存管理系统

    千次阅读 多人点赞 2020-05-15 18:55:31
    //为头节点开辟内存空间 L->next = NULL; //将头节点的指针域置空 do { Menu(); //菜单 printf("请输入相应的数字,进行相应的操作:\n"); scanf("%d", &item); system("cls"); switch (item) { case 1: printf("请...
  • C语言动态内存管理

    2021-01-13 16:29:24
    C语言动态内存管理 程序开发过程中,很多情况是不能够预先知道需要多大的内存,此时内存就需要随用随获取。比如链表的插入,不确定大小数组的建立。C语言中动态内存获取的接口函数在<stdlib.h>头文件中,下面...
  • C语言链表实现简单图书管理系统

    千次阅读 2020-08-27 10:38:28
    通过链来实现简单的图书管理系统,实现如下功能: 1. 添加图书 2. 查询图书信息 3. 修改图书价格 4. 删除图书 5. 查看所有图书 6. 退出 需要熟悉结构体和指针的使用,具有简单的数据结构链表概念。还需要处理好一些...
  • C语言链表基础入门

    2020-08-25 16:57:15
    链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。 二.如何建立一个链表 首节点:存放第一个有效数据的节点,...
  • C语言链表实现考试报名管理系统

    千次阅读 2020-06-14 15:49:17
    } //创建链表,将新生成的节点插入到链表的表头 STU *ListCreate(STU *L, int n) { int i; for (i = 0; i; i++) { STU *p; //将新生成的节点插入到链表中 p=NULL; p = (STU *)malloc(sizeof(STU)); Input(p,i); p->...
  • 第一次写博客,今天学习了C语言链表的相关知识,自己实现了一个很简单的学生成绩管理系统,同时也温习了一下多文件编程,想和大家分享一下自己从中的一些经验和感受。 头文件 //List.h 包含结构体的定义 #...
  • C语言》双链表——内存管理Main.cMemManage.hMemManage.c Main.c #define USING_MEMORY_MANAGE #include "MemManage.h" #include &lt;time.h&gt; #define N 50 void main() { srand(...
  • 因为最近学习了数据结构的链表操作,然而我还是掌握不太熟练,这个货物信息管理系统的链表操作写了整整快一天(可能是真的不适合敲代码,一个对代码兴趣不大的人的垂死挣扎),不管怎么样,算是完成了。本文把我对这...
  • 链表是一种使用极其广泛的数据结构,它也可以用来作为实现栈、队列等数据结构的基础,链表没有像数组需要预先知道数据大小的缺点,可充分利用计算机内存,实现动态灵活的内存管理。除非需要频繁的通过下标来随机访问...
  • C语言内存管理机制

    万次阅读 多人点赞 2018-07-22 15:39:30
    本文是作者在学习C语言内存管理的过程中做的一个总结。 变量概念: 全局变量(外部变量):出现在代码块{}之外的变量就是全局变量。 局部变量(自动变量):一般情况下,代码块{}内部定义的变量就是自动变量,...
  • 链表是一种使用极其广泛的数据结构,它也可以用来作为实现栈、队列等数据结构的基础,链表没有像数组需要预先知道数据大小的缺点,可充分利用计算机内存,实现动态灵活的内存管理。除非需要频繁的通过下标来随机访问...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,611
精华内容 10,644
关键字:

c语言链表的内存管理

c语言 订阅