引用自身的结构体,一个结构体中有一个或多个成员的基类型就是本结构体类型时,说明这个结构体可以引用自己,所以称作引用自身的结构体。

例如下面的结构体:

struct link{ char ch; struct link *p} a;

p是一个可以指向struct link类型变量的指针成员,这样,a.p=&a就是合法的表达式。那么,这有什么意义呢?

这样的意义就是我们可以把分散存储的数据项,用一个结构体成员链接起来(当然这也耗费了那个存储指针的内存空间)看下面的程序

#include
struct node{int data;struct node *next;
};
main(){struct node a,b,c,*p;//我们假设,这样声明的结构体变量a 、b、c在内存中并不是相临的a.data=10;  b.data=20; c.data=30; a.next=&b; b.next=&c; c.next='\0';p=&a;//结构体变量a地址赋给p while(p){printf(" %d ",p->data);//每输出一个值后,p自动指向本项的链接项
/*这样有了一个单独保持链接的成员就把不相临的存储单元在逻辑上存储在了一起*/ p=p->next;}printf("\n");
}

这样的相链的数据存储形式称为链表!上面形成链表的方法是人为定义的,在程序执行过程中,不会生成新的存储单元,所以也称为“静态链表”

下面看一种更方法使用的“动态链表”

前面的日志中提到了C语言动态存储分配提供了“按需分配内存”的实现方法,有一个问题是,如果多次动态分配存储单元,各存储单元的地址不是一定是连续的,而所需要处理的批量数据往往是一个整体,各数据之间存在着顺序关系,这样,我们可以利用上面的链表把动态得到的存储单元在逻辑上(而不是在物理上)连接起来,就可以实现我们需要的顺序关系了。这时,是把链表技术与动态存储分配结合了起来,所以这里我们给了链表一个新的名词叫做“动态链表”

很自然,我们上面例子中的链表只有一个指向后面数据项的指针,如果有两个呢?一个指后,一个指前,这样就会出现“双向链表”与“单向链表”的区别

下面我们主要看单向链表

事实上,单身链表中的每个存储单元的数据(也就是结构体)的格式类型是相同的(包括数据成员和指针成员)

如下:struct abc{int data,……struct abc *next;};

与单向链表有关的算法有以下几类:

建立链表  输出结点数据   插入结点数据 删除结点数据

下面这个程序是示例

#include
#include
struct slist{ int data; struct slist *next;};
typedef struct slist SLIST;SLIST *creat_slist(){
/*该函数的作用是创建动态链表,函数的返回值是结构体指针变量,也就是新创建的动态链表的头结点,需要注意的是,这里的头结点没有数据data,只有指针next指向动态链表的第一个结点*/int c;/*用来临时存储结构体中的data*/ SLIST *h,*s,*r;/*声明工作指针*/h=(SLIST *)malloc(sizeof(SLIST));/*动态获取一个结构体的存储空间*/r=h;/*结构体指针r用来在下面的循环中使用h指针不变*/scanf("%d",&c);/*得到一个结构体成员int data数据*/ while(c!=-1){/*如果上面得到的int data数据不为-1就进入循环 */s=(SLIST *)malloc(sizeof(SLIST));/*循环中用结构体指针s获取结点*/s->data=c;/*s成员data为c注意第一次进入循环时,这个c是在循环外部上面输入的*/r->next=s;/*r指针本来与h相同,r的成员next在进入循环前是没有指向的现在进入了循环得到了一个结点,就把r的next指向新的结点,这样就使h头结点指向了s*/r=s;/*r依次与最新的结点相同,为了依次用最新的存储空间的next指向下一个获得的结点*/scanf("%d",&c);}r->next='\0';/*退出循环后,r指向最后一个结点,而这个最后结点的成员next要指向'\0'*/return h;/*返回动态链表的头结点指针*/
}
void print_slist(SLIST *head){
/*该函数是依次输出动态链表的结点,参数是结构体指针变量,也就是
动态链表的头结点*/ SLIST *p;/*声明一个工作指针,因为head不能自己往后依次移动,所以用指针p实现*/p=head->next;if(p=='\0')printf("linklist is null!\n");/*空链表*/ else{printf("head");/*非空链表*/ do{ printf("->%d",p->data);p=p->next;}while(p!='\0');printf("->end\n");}}SLIST *insert_snode(SLIST *head,int x,int y){
/*该函数实现在链表值为x的结点前面插入一个结点,值为y参数有三个链表头结点,值x,y*/ SLIST *s,*p,*q;/*定义工作指针*/s=(SLIST *)malloc(sizeof(SLIST));s->data=y;/*上面这两句先获取了一个结构体动态存储空间,并给其成员data赋值为y,但此时该空间并未成为链表的一个结点*/q=head;p=head->next;/*上面两句初始化工作指针,就是把工作指针q与head相同,p指向head的next*/while((p!='\0')&&(p->data!=x)){/*这个循环是供查找到值为x的结点所在位置的,需要注意的是这里的并的两个条件位置不能变,因为只有在p指向不为空的时候才能讨论其data成员值是否为x,否则如果p的指向是空,程序确要先判断p指向的data是不是x这样会发生地址访问错误,因为p本不指向结点,也就无从谈成员data,所以判断p指向的data是不是x是不对的*/q=p;p=p->next;/*满足循环条件的话,p与q依次后移直到找到值为x的结点或到了链表的尾部*/}s->next=p;/*在p指向的结点前面插入,所以新的结点的next指向p*/q->next=s;/*q-next本指向p结点,现在令其指向s结点,实现了插入*/return head;/*头指针并未变化,返回即可*/
}SLIST *insert_bnode(SLIST *head,int x,int y){
/*该函数实现在链表值为x的结点后面插入一个结点,值为y参数有三个链表头结点,值x,y*/ SLIST *s,*p,*q;/*定义工作指针*/s=(SLIST *)malloc(sizeof(SLIST));s->data=y;/*上面这两句先获取了一个结构体动态存储空间,并给其成员data赋值为y,但此时该空间并未成为链表的一个结点*/q=head;p=head->next;/*上面两句初始化工作指针,就是把工作指针q与head相同,p指向head的next*/while((p!='\0')&&(p->data!=x)){/*这个循环是供查找到值为x的结点所在位置的,需要注意的是这里的并的两个条件位置不能变,因为只有在p指向不为空的时候才能讨论其data成员值是否为x,否则如果p的指向是空,程序确要先判断p指向的data是不是x这样会发生地址访问错误,因为p本不指向结点,也就无从谈成员data,所以判断p指向的data是不是x是不对的*/q=p;p=p->next;/*满足循环条件的话,p与q依次后移直到找到值为x的结点或到了链表的尾部*/}s->next=p->next;/*在p指向的结点后面插入,所以新的结点的next指向p*/p->next=s;/*p-next本指向p后面的结点,现在令其指向s结点,实现了后插入*/return head;/*头指针并未变化,返回即可*/
}SLIST *del_node(SLIST *head,int x){
/*该函数实现删除链表值为x的结点,参数有两个链表头结点,值x */ SLIST *s,*p,*q;/*定义工作指针*/q=head;p=head->next;/*上面两句初始化工作指针,就是把工作指针q与head相同, p指向head的next*/while((p!='\0')&&(p->data!=x)){/*这个循环是供查找到值为x的结点所在位置的,需要注意的是这里的并的两个条件位置不能变,因为只有在p指向不为空的时候才能讨论其data成员值是否为x,否则如果p的指向是空,程序确要先判断p指向的data是不是x这样会发生地址访问错误,因为p本不指向结点,也就无从谈成员data,所以判断p指向的data是不是x是不对的*/q=p;p=p->next;/*满足循环条件的话,p与q依次后移直到找到值为x的结点或到了链表的尾部*/}q->next=p->next;/*把q->next置成p->next,*/free(p);/*释放p的存储空间,实现删除*/return head;/*头指针并未变化,返回即可*/
}
//在公众号【C语言中文社区】回复“C语言”,免费领取200G编程资料
main(){SLIST *head; int x,y;head=creat_slist();//创建链表函数print_slist(head);printf("please input x\n");  scanf("%d",&x);printf("please input y\n");  scanf("%d",&y);head=insert_snode(head,x,y);//结点前插入函数print_slist(head);printf("please input x\n");  scanf("%d",&x);printf("please input y\n");   scanf("%d",&y);head=insert_bnode(head,x,y);//结点后插入函数print_slist(head);printf("please input x\n"); scanf("%d",&x);head=del_node(head,x);//删除结点函数print_slist(head);
}

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

C语言——结构体链表,附完整示例相关推荐

  1. C语言结构体和结构体数组示例 - Win32窗口程序演示

    C语言结构体和结构体数组的使用: /* C结构体和结构体数组示例,by bobo */#include <windows.h>LRESULT CALLBACK WndProc (HWND, ...

  2. C语言结构体和链表结合,C语言结构体与链表

    C语言结构体与链表 第 10章 CHAPTER 10 结构体与共用体 学习目标 本章主要介绍结构体的定义和使用方法,然后介绍链表的概念和相关操作,最后介绍两种新的数据类型--共用体和枚举.通过本章的学 ...

  3. c++ new一个结构体_C语言结构体,又一个纸老虎,纯干货讲解(附代码)

    来源:网络,排版整理:晓宇 微信公众号:芯片之家(ID:chiphome-dy)结构体的定义结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构.结构体和其他类型基础数 ...

  4. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  5. linux中c语言结构体详解,Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

  6. python展开 c函数中的宏预处理_Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

  7. C语言结构体的定义与使用、结构体数组、指向结构体的指针(有代码详解)

    1.结构体的定义与使用 结构体是一种构造数据类型 把不同类型的数据组合成一个整体 结构体的定义形式: struct 结构体名{结构体所包含的变量或数组 }; 结构体是一种集合,它里面包含了多个变量或数 ...

  8. c语言的结构体能存放函数吗,在C语言结构体中添加成员函数

    我们在使用C语言的结构体时,经常都是只定义几个成员变量,而学过面向对象的人应该知道,我们定义类时,不只是定义了成员变量,还定义了成员方法,而类的结构和结构体非常的相似,所以,为什么不想想如何在C语言结 ...

  9. ARM汇编语言实现peek()_ARM汇编之访问C语言结构体数据

    前言 本文的写作目的在于装逼,没有要产生实际价值的意思. 前几天在做编译器的项目,有一个项目团队成员一直在问我ARM汇编能不能读C语言的结构体.我心想,我这生成ARM汇编的代码是用C++写的呀,又不是 ...

最新文章

  1. Earth to developers: Grow up!
  2. 数据库索引-基本知识
  3. YARN的内存和CPU配置优化
  4. php docker开发环境,使用Docker的PHP开发环境
  5. minheight能继承吗_继承人放弃继承遗产继承并做出公证还能反悔吗?
  6. 【转帖】WEB架构师成长之路之一-走正确的路
  7. PHP生成条形码 之一 条形码介绍
  8. t检验及python代码实现
  9. UE4_UE5制作3DUI-跟随相机朝向(附工程)
  10. neso n810 i7 android 4.4,搭载64位英特尔芯 NESO N810 i7平板电脑发布
  11. 3D激光雷达SLAM算法学习02——3D激光雷达传感器
  12. Excel数据导入Matlab绘图
  13. Cindy Message/MessageRecognizer interface
  14. CodeForces1214A
  15. 2022面试相关 - react相关原理
  16. Unity urp2d ShaderGraph 实现一个黑白转彩色的场景渐变效果 设计思路
  17. 违章查询源码 php,php车辆违章查询数据详解
  18. [迷题]你真的属于那仅有的2%的聪明人吗?
  19. 如何阻止随时自动弹出的各种网页
  20. slf4j-api、slf4j-log4j12以及log4j之间什么关系?

热门文章

  1. play 框架_用于Play框架分布式应用程序的Init.d Shell脚本
  2. java 调试 工具_Java调试器–权威的工具列表
  3. java8 linq4j_Java 8仍然需要LINQ吗? 还是比LINQ更好?
  4. Spring Boot 2应用程序和OAuth 2 –传统方法
  5. 为了简单起见,Arquillian Chameleon
  6. 投资银行对Java进行的二十大核心面试问答
  7. 使用Java 8 CompletableFuture和Rx-Java Observable
  8. 在Window上使用Jenkins自动发布Java工件
  9. 在单元测试中访问私有字段
  10. 防止System.exit调用