动态内存分配和链表

Posted pigcv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态内存分配和链表相关的知识,希望对你有一定的参考价值。

什么是链表?
链表是一种重要的数据结构,它最大的优点是可以进行动态的存储分配。链表有单向链表,双向链表,循环链表。对于c,这里我们只讨论单向链表。
我们知道,内存是由栈和堆组成的。栈空间是由操作系统和编译系统控制的,比如我们定义int a;这个a就是在栈中开辟内存单元的。而堆空间,则允许给用户提供了虚拟空间,在堆中
是没有变量名这个说法的,只能通过地址来找到内存中存放的东西。

既然是动态内存分配,当然有动态分配的特殊方法。在c中是以函数的形式实现的。
1.malloc函数
函数原型:void *malloc(unsigned int size)
函数的作用是:在内训的动态存储区开辟一个size个字节的连续空间,返回所分配区域的首字节地址。
可以看到,函数返回值是一个void指针,请注意,void指针不是一个可以指向任何类型数据的指针,而是 说,不指向任何类型的数据,仅仅是提供了一个地址。
因而,你想让这个指针指向int型数据,要进行显式的类型转换(强制类型转换),即在前面加(int *)。一般来说,如果不加,是可以自动进行隐式类型转换的。

2.calloc函数
函数原型:void *calloc(unsigned n,unsigned size)
作用:开辟n个长度为size的连续空间。一般用来保存一个数组。
3.realloc函数
原型:void *realloc(void *p,unsigned int size)
作用:用来重新分配已经分配的动态空间的大小。
4.free函数
原型:void free(void *p)
作用:把已经分配的动态空间释放掉。

言归链表:
一个链表,是由许多节点组成的。可以自由的删除、添加。指向首节点的指针叫做head指针,它是链表的唯一标示。每个节点包含两部分,一是数据,而是下一个节点的地址。通过这个下个节点的地址,建立了整个链表的联系。

如何建立一个链表呢?
用结构体建立链表当然是再合适不过了。
比如:现在建立一个静态链表。
struct S
{
int a;
struct S *next;
}S1,S2,S3;
struct S *head;
S1.a=1;S2.a=2;S3.a=3;

head=&S1;
S1.next=&S2;
S2.next=&S3;
S3.next=NULL; //请注意让最有一个节点存放的地址为NULL。

这样,我们就建立了一个有三个节点的静态链表。
如何建立一个动态链表呢?又如何添加、删除节点,更进一步说,怎么使得链表有序,并且进行删除添加操作后使之依然有序 ?

建立动态链表,就是可以随时根据需要来增加结点 。看代码:
#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct S)
struct S
{
int a;
struct S *next;
};
int n; //全局变量n,记录节点个数。未赋初值默认为0;
struct S *creat_autolist(void) //函数,来创建一个动态链表
{
struct S *head; //头指针;
struct S *p0,*p1; //p0为当前节点;
p0=p1=(struct S*)malloc(LEN);//用malloc函数开辟一个结点的空间 ;
scanf("%d",&p0->a);//输入数据;
head=NULL;
while(p0->a!=0) //循环,输入的a不为0则继续输入;
{
n++;
if(n==1) head=p0; //是否为第一个结点;
else p1=p0->next;

p1=p0; //让p1也指向p0所指向的结点
p0= (struct S*)malloc(LEN); //在开辟一个节点;
scanf("%d",&p0->a);
}
p1->next=NULL;//尾结点的指针部分为NULL
return (head);
}
void main()
{
struct S *head,*pt;
head=creat();
pt=head;

/*
这是输出链表的方法
*/
if(head!=NULL)
{
do
{
printf("%d\n",pt->a);
pt=pt->next;
}while(pt!=NULL);
}
}

至此,动态链表的创建和输出已经实现。

怎么删除结点呢?实际上就是改变要删除的结点的前后的两个节点中地址的指向。
怎么添加结点呢?实际上也是改变指向。
使其做到有序?
那么,我们就要进行一个大小比较的过程了。不过,要考虑在表首,表中,表尾三种情况。

下面给出一个小栗子:

要进行链表的结点添加,并顺序。
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define LEN sizeof(struct Student)

struct Student
{
long num;
double score;
struct Student *next;
};
int n=0;

void print(struct Student *head)
{
struct Student *pt;
pt=head;
printf("there are %d records:\n");
if(head!=NULL)
{
do
{
printf("%ld,%5.1lf",pt->num,pt->score);
pt=pt->next;
}while(pt!=NULL);
}

}

struct Student *creat()
{
struct Student *head,*p0,*p1;
head=NULL;
printf("*****creat list*****");
printf("please input record(0,0 for exit)\n");
p0=(struct Student *)malloc(LEN);
scanf("%ld,%lf",&p0->num,&p0->score);
while(p0->num!=0)
{
head=insert(head,p0);
p0=(struct Student *)malloc(LEN);
scanf("%ld,%lf",&p0->num,&p0->score);
}
return (head);
}

 

struct Student *insert(struct Student *head,struct Student *stu)
{
struct Student *p0,*p1,*p2;
p0=stu;
if(head==NULL)
{
head=p0;
p0->next=NULL;
}
else
{
p1=head;
while(p0->num>p1->num&&p1->next!=NULL) //这是个遍历
{
p2=p1;
p1=p1->next;
}
if(p0->num<=p1->num)
{
if(head==p1)
{
head=p0;
p0->next=p1;
}
else
{
p2.next=p0;
p0.next=p1;
}
}
else
{
p1.next=p0;
p0.next=NULL;
}

}

n++;
return(head);

}


这仅仅是链表的最简单形式和应用,数据结构中还会深究。

 

 

 

 

 

以上是关于动态内存分配和链表的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法 - 链表

内存对象管理器(基于数组和链表实现)

浅谈HashMap实现原理

数组和链表的区别

数组还是链表?

数组和链表区别