本文对链表以及C/C++中的动态链表做详细诠释。

什么是链表?
  链表是一种重要的数据结构,它最大的优点是可以进行动态的存储分配。链表有单向链表,双向链表,循环链表。对于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);

}  
  

 

 

 

 

 

【C/C++】动态内存分配和链表的更多相关文章

  1. 郑州尚学堂:链表的C语言如何实现动态内存分配

    一.为什么用动态内存分配 但我们未学习链表的时候,如果要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数组.比如说我们要存储一个班级学生的某科分数,总是定义一个float型(存在0.5分)数 ...

  2. c 链表和动态内存分配

    兜兜转转又用到了c.c的一些基本却忘记的差不多了(笑哭)!! 动态内存分配 当malloc完将返回的指针类型强制转换成想要的类型后,指针中存有该指针的数据结构,而分配的内存恰好可用于该数据结构. 链表 ...

  3. SQLite剖析之动态内存分配

    SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存.建立数据库文件的内存Cache.保存查询结果. 1.特性    SQLite内核和它的内存分配子系统提供以下特性 ...

  4. 转: Linux C 动态内存分配 malloc及相关内容 .

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

  5. iOS开发——C篇&动态内存分配

    再C语言中关于内存是一个很重要的知识点,所以今天我就从c语言的内存分配开始为大家解析一下C语言再iOS开发中非常重要的一些知识. 1:malloc函数的介绍 C语言中开辟内存空间:malloc函数 再 ...

  6. C—动态内存分配之malloc与realloc的区别

    在程序的执行期间分配内存时,内存区域中的这个空间称为堆(heap).还有另一个内存区域,称为堆栈(stack),其中的空间分配给函数的参数和本地变量.在执行完该函数后,存储参数和本地变量的内存空间就会 ...

  7. Linux C 动态内存分配--malloc,new,free及相关内容

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

  8. C和指针--动态内存分配

    1.为什么需要使用动态内存分配 数组的元素存储于内存中连续的位置上,当一个数组被声明时,它所需要的内存在编译时就被分配.当你声明数组时,必须用一个编译时常量指定数组的长度.但是,数组的长度常常在运行时 ...

  9. molloc堆区的动态内存分配

    [前言]前面有一篇文章介绍了堆区栈区的区别.栈区的核心主要集中在操作一个栈结构,一般由操作系统维护.堆区,主要是我们程序员来维护,核心就是动态内存分配. 这篇笔记结束就不在高新CSAPP的读书笔记了, ...

随机推荐

  1. Git创建项目基本命令

    前提:先在coding.net上创建项目Paper,并勾选“启用README.md文件”初始化项目. 1.给项目Paper创建版本库(仓库) cd Paper git init 2.把项目文件放到仓库 ...

  2. CAS5.X 集群配置 初版

    基础版 cas-overlay  pom.xml <?xml version="1.0" encoding="UTF-8"?> <projec ...

  3. 立足中国,走向世界(Made in China, Go to World)

    FineUI一路走来已经历经 9 年的风风雨雨,拥有国内最为广泛的捐赠群体(1500多位),和众多企业客户的青睐(200多家). 今天,我们很高兴的宣布:FineUI英文版上线了! FineUI英文版 ...

  4. 十分钟学会Java8:lambda表达式和Stream API

    Java8 的新特性:Lambda表达式.强大的 Stream API.全新时间日期 API.ConcurrentHashMap.MetaSpace.总得来说,Java8 的新特性使 Java 的运行 ...

  5. Java模拟登录带验证码的教务系统(原理详解)

    一:原理 客户端访问服务器,服务器通过Session对象记录会话,服务器可以指定一个唯一的session ID作为cookie来代表每个客户端,用来识别这个客户端接下来的请求. 我们通过Chrome浏 ...

  6. C#(.NET) HMAC SHA256实现

    HMAC SHA256的实现比较简单,可以用多种语言实现,下面我用C#语言实现,一种结果是居于BASE64,另外一种是居于64位. C# HMAC SHA256 (Base64) using Syst ...

  7. flink1.7自定义source实现

    flink读取source data 数据的来源是flink程序从中读取输入的地方.我们可以使用StreamExecutionEnvironment.addSource(sourceFunction) ...

  8. BAT美团滴滴java面试大纲(带答案版)之三:多线程synchronized

    继续面试大纲系列文章. 从这一篇开始,我们进入ava编程中的一个重要领域---多线程!多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生:而滥用则会遭其反噬. 在多线程编程中要渡的 ...

  9. Meterpreter常⻅见⽤用法

    0x01 背景 meterpreter作为后渗透模块有多种类型,并且命令由核⼼心命令和扩展库命令组成,极⼤大的丰富了了攻击⽅方式. 需要说明的是meterpreter在漏漏洞洞利利⽤用成功后会发送第二 ...

  10. 16-使用Selenium模拟浏览器抓取淘宝商品美食信息

    淘宝由于含有很多请求参数和加密参数,如果直接分析ajax会非常繁琐,selenium自动化测试工具可以驱动浏览器自动完成一些操作,如模拟点击.输入.下拉等,这样我们只需要关心操作而不需要关心后台发生了 ...