文章如果有写的不对的地方,欢迎指正^^

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。双链表wiki

通过双链表可以快速的了解c语言中的指针和内存的关系

细节

指针变量存储的是内存的地址,可以理解为一个存储内存地址的符号

声明的是类型,定义的是变量。声明的时候不分配内存,int i;属于定义。

结构体声明时不分配内存,定义变量的时候才分配struct linked_list link_1;

指针变量相互赋值,传递的是所代表的内存地址

函数接受字符串的时候,形参要用char *来代表字符串数组的首地址

-> 用来表示调用结构体指针所代表的变量的域,如果用.则代表结构体变量调用自己的域

判断一个指针是否为空,用== NULL

链表实现方案

/*

describe linked_list

_

| |__ _ _ __ _

| '_ \| | | |/ _` |

| |_) | |_| | (_| |

|_.__/ \__,_|\__, |

|___/

*/

#include

#include

struct linked_list {

struct linked_list *next, *prev;

char *title;

};

/* 声明结构体指针变量,会在内存中开辟空间,存储指针 */

struct linked_list * current,* prev, *head;

void list_add(char *);

void list_search();

void list_reverse_search();

int main(void) {

list_add("-");

list_add("--");

list_add("---");

list_add("----");

list_add("-----");

list_search();

list_reverse_search();

}

void list_add(char *title) {

/* 将新申请的内存的首地址给结构体指针变量 */

current = (struct linked_list *)malloc(sizeof(struct linked_list));

/* 初始化当前结构体,新增元素的next始终是NULL */

current->next = NULL;

current->title = title;

/* prev元素是否已经存在了,是否存在前辈元素,来判断是否是首次添加元素*/

if(prev == NULL) {

/* 如果不存在说明,current是第一个添加进来的元素 */

current->prev = NULL;

/* 设置为首元素,这里current和head现在指向的是同一个内存地址 */

head = current;

}else {

/* 如果存在前辈元素,将当前元素的prev设置为前辈元素的地址,并且将前辈元素的next设置为当前元素的地址 */

current->prev = prev;

prev->next = current;

}

/* 将当前指针所代表元素的地址,交给prev指针符号 ,现在head和prev指向同一个地址*/

prev = current;

/* 首次添加元素head是没有next的,第二次添加的时候,prev 的next设置为了新增元素地址,所以head的next也发生了改变 ( 添加第2个元素的时候,才会重写上个元素的next值)*/

}

/* 链表正序搜索 */

void list_search() {

while(head) {

printf("%s\n", head->title);

head = head->next;

}

}

/* 倒序搜索 */

void list_reverse_search() {

while(current) {

printf("%s\n", current->title);

current = current->prev;

}

}

终端向链表添加元素

我们来强化一下,通过终端来不停地向链表中添加元素。并且每次回车之后,都打印出整个列表的元素。

要点

声明定义字符串数组的时候,值不能用变量

我们要求每次都要保存填写的元素值,所以每次都需要重新开辟一个内存空间,给新的struct,由于个struct中都保存的是title的指针,所以新增加的元素的title也需要重新开辟内存空间来存储。

由于每次都需要进行打印链表,所以head要注意不能被覆写。所以重新定义一个struct linked_list变量来做一个中间变量。

#include

#include

#include

struct linked_list {

struct linked_list *next, *prev;

char *title;

};

struct linked_list *head,*current,*above;

struct linked_list head_cp;

void list_add(char *);

void list_search();

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

char title[10];

while(scanf("%s",title) > 0) {

list_add(title);

/* 每次添加到链表之后,都会进行打印整个链表 */

list_search();

}

/*

这样初始化是错误的

error: array initializer must be an initializer list or string literal

“数组的初始化,必须是一个列表或者是字面的字符串”

char title[] = *(argv+1);

*/

}

void list_add(char *t) {

/* 分配内存 */

current = (struct linked_list *)malloc(sizeof(struct linked_list));

/* title 是一个内存空间的首地址,这里重新分配内存的原因是,每次scanf都会重写t指针下的内容,导致整个链式里面所有的title都发生变化 */

char *title = (char *)malloc(sizeof(*t));

/* 将t指针指向的内容copy到title指针指向的内存中 */

strcpy(title,t);

/* 初始化结构体域 */

current->prev = NULL;

current->next = NULL;

/* 指向新内存中的title */

current->title = title;

if(above == NULL) {

head = current;

}else {

current->prev = above;

above->next = current;

}

above = current;

}

void list_search() {

/* 这将head指向的内容赋值给新开辟的结构体变量,这里不是给的地址,给的是内容 */

head_cp = *head;

while(head_cp.title) {

printf(">>%s\n", head_cp.title);

if(head_cp.next != NULL) {

head_cp = *(head_cp.next);

}else {

return;

}

}

}

操作结果

1 /* 回车 */

>>1

2 /* 回车 */

>>1

>>2

3 /* 回车 */

>>1

>>2

>>3

4 /* 回车 */

>>1

>>2

>>3

>>4

能不能不手动分配title的内存空间呢?

当然可以。下面代码中我们修改了struct的结构将原来的char *title修改为char title[10],这样每次定义结构体变量的时候,内存作为struct的一部分一起分配好了。

那么我们在add元素的时候,就需要将scanf获取到的变量,通过strcpy(current->title,title)的方式,写入到char title[10]开辟的内存空间中。

还需要修改list_search方法中的while判断,不能再判断指针是否为NULL的方式来判断是否存在title内容,而是要判断字符串的长度strlen(head_cp.title) == 0。

但是最后一种修改结构体的方式无法动态分配内存,每次生成的字符串的长度都是10,会浪费内存。

#include

#include

#include

struct linked_list {

struct linked_list *next, *prev;

char title[10];

};

struct linked_list *head,*current,*above;

struct linked_list head_cp;

void list_add(char *);

void list_search();

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

char title[10];

while(scanf("%s",title) > 0) {

list_add(title);

/* 每次添加到链表之后,都会进行打印整个链表 */

list_search();

}

/*

这样初始化是错误的

error: array initializer must be an initializer list or string literal

“数组的初始化,必须是一个列表或者是字面的字符串”

char title[] = *(argv+1);

*/

}

void list_add(char *title) {

/* 分配内存 */

current = (struct linked_list *)malloc(sizeof(struct linked_list));

/* 初始化结构体域 */

current->prev = NULL;

current->next = NULL;

/* 这里current->title是字符串数组的首地址,是个指针 */

strcpy(current->title,title);

if(above == NULL) {

head = current;

}else {

current->prev = above;

above->next = current;

}

above = current;

}

void list_search() {

/* 这将head指向的内容赋值给新开辟的结构体变量,这里不是给的地址,给的是内容 */

head_cp = *head;

while(strlen(head_cp.title) != 0) {

printf(">>%s\n", head_cp.title);

if(head_cp.next != NULL) {

head_cp = *(head_cp.next);

}else {

return;

}

}

}

c语言链表与字符结合,C语言实现双链表的(终端)添加和查询相关推荐

  1. C语言怎么判断字符YN,c语言中的宏_详解(转)

    1. 简单宏定义 简单的宏定义有如下格式: [#define指令(简单的宏)] #define 标识符替换列表 替换列表是一系列的C语言记号,包括标识符.关键字.数.字符常量.字符串字面量.运算符和标 ...

  2. C语言丨线性表(三):双链表

    线性表是由数据类型相同的个数据元素组成的有限序列,通常记为: 其中n为表长,n=0时称为空表:下标i表示数据元素的位序. 线性表的特点是组成它的数据元素之间是一种线性关系,即数据元素"一个接 ...

  3. c 语言中双向链表逆转编程题,C/C++ 双链表之逆序的实例详解

    C/C++ 双链表之逆序的实例详解 一.结点结构 双向链表的数据结构定义如下: typedef struct node { ElemType data; struct node *prior stru ...

  4. [C语言实现]带你手撕带头循环双链表

    目录 什么是双链表? 带头结点的优势: 双链表的实现: 什么是循环双链表? 众所周知,顺序表的插入和删除有时候需要大量移动数据,并且每次开辟空间都可能会浪费大量内存和CPU资源,于是我们有了链表,我们 ...

  5. 将搜索二叉树转换为链表_将给定的二叉树转换为双链表(DLL)

    将搜索二叉树转换为链表 Given a Binary tree and we have to convert it to a Doubly Linked List (DLL). 给定二叉树,我们必须将 ...

  6. java中的列表栈链表_Java数据结构(栈,队列,双链表)

    (1)栈package ChapterOne; public class Stack { //栈数组 long stackArr[]; //栈的大小 int maxSize; //栈的顶部 int t ...

  7. c语言格式化输入字符型,C语言——字符串和格式化输入/输出

    今天,学习了C Primer Plus的第四章.本章讲解了一些简单的C预处理器的知识,一些字符.字符串以及数组等相关概念以及输入输出函数的使用. 现将知识点总结如下: 字符串:一个或多个字符的序列(双 ...

  8. c语言设置输出字符大小_C语言中常用的几个头文件及库函数

    点击上方"C语言中文社区",选择"设为星标★" 技术干货第一时间送达! 来源:https://www.jb51.net/article/124594.htm 这 ...

  9. c语言c判断字符数字,c语言问题求教 利用函数判断字符串中是否全为数字

    c语言问题求教 利用函数判断字符串中是否全为数字 答案:4  信息版本:手机版 解决时间 2018-12-22 19:42 已解决 2018-12-22 08:52 c语言问题求教 利用函数判断字符串 ...

最新文章

  1. MaxScale:实现MySQL读写分离与负载均衡的中间件利器
  2. P1800 software_NOI导刊2010提高(06)
  3. getparameter的使用
  4. python学习(函数)
  5. python中元组可以比较大小吗_python元组比较
  6. WinCE系统的编译过程详解
  7. 计算机技术中的常见概念
  8. java 实现二分法
  9. 你经历过最奇特的梦境是怎样的?
  10. js改变style中的值
  11. sql语句练习(1) 含问题,答案,数据库表,数据
  12. 惠普电脑怎么用access_惠普笔记本电脑怎么分区
  13. title属性,显示出提示文字;alt属性,在浏览器无法显示图片的时候,用alt中的文字替代。不要把title和alt的作用混乱了~
  14. Android 应用内部打开PDF文件
  15. 游戏本自动掉帧_玩游戏掉帧怎么办?
  16. 计算广告-商业化体系
  17. 2022年全球20大国际航运中心榜单公布,上海蝉联第三,与新加坡伦敦差距缩小 | 美通社头条...
  18. BUUCTF Reverse/findKey
  19. Excel 自动调整行高后增加高度
  20. Flip Flop和DoOnce

热门文章

  1. hibernate07--关联映射
  2. D - 小Y上学记——要迟到了!
  3. PHP实现同服务器多个二级域名共享 SESSION
  4. c# namespace不能和class的name 相同
  5. 元对象我所理解的设计模式(C++实现)——享元模式(Flyweight Pattern)
  6. iframe 的一点经历
  7. WCF开发框架形成之旅--WCF应用常见问题处理
  8. 安装SQL Server2008错误解决方案
  9. win32应用程序_电脑打不开exe程序|Win10提示exe不是有效32应用程序
  10. n阶完全图边和顶点关系。_正N边型的完全图被分割成几个多边形