链表之节点插入、删除节点、遍历打印、遍历释放,static 全局变量

本文介绍static全局变量的作用域限制,并通过一个链表操作的例子展示了如何在单个文件中使用static全局变量进行节点的插入、遍历打印及删除等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       static关键字声明的全局变量只有本文件内的函数可以引用,其它文件(模块)只能通过该模块提供的接口函数来访问这个static全局变量,而不能直接对其进行操作。   

   对于一个存储类别声明为static的全局变量而言,其生命周期并没哟发生改变,在整个程序执行过程中该变量一直存在。但其作用域反而有所减小,只有本文件的函数可以引用该全局变量。

  1 /*
  2  * FILE: p65_linkOperate_list.c
  3  * DATE: 20180107
  4  * --------------
  5  * DESCRIPTION: static全局变量只有本文件内的函数可以引用
  6  * 其它文件(模块)只能通过该模块提供的接口函数来访问这个static全局变量
  7  * insert插入节点,print遍历打印节点,destroy遍历释放节点
  8  */
  9 
 10 #include <stdio.h>
 11 #include <stdlib.h>
 12 
 13 struct node{
 14         int val;
 15         struct node *next;
 16 };
 17 
 18 // static 链表头
 19 static struct node *head;
 20 
 21 /* 插入节点 */
 22 int insert(int val)
 23 {
 24         struct node *p, *q;
 25         p = head;
 26         // 创建新节点
 27         q = (struct node *)malloc(sizeof(struct node));
 28         if(q == NULL)
 29         {
 30                 perror("ERROR: malloc, fail to apply memory");
 31                 return -1;
 32         }
 33         q->val = val;
 34         q->next = NULL;
 35         // 节点链入链表
 36         if(p == NULL)
 37         {
 38                 head = q;       // 注意 此处不是 p=q
 39         }
 40         else
 41         {
 42                 while(p->next != NULL)
 43                         p = p->next;
 44                 p->next = q;
 45         }
 46         return 0;
 47 }
 48 
 49 /* 遍历链表,打印每个节点的值 */
 50 void print()
 51 {
 52         struct node *p = head;
 53         while(p != NULL)
 54         {
 55                 printf("%d\n", p->val);
 56                 p = p->next;
 57         }
 58 }
 59 
 60 /* 遍历链表,释放每一个节点 */
 61 void destroy()
 62 {
 63         struct node *p = head;
 64         while(p != NULL)
 65         {
 66                 struct node *q;
 67                 q = p;
 68                 p = p->next;
 69                 free(q);        // free 释放
 70         }
 71         head = NULL;    // 清空链表的头指针
 72 }
  1 /* FILE: p65_linkOperate_list.h
  2  * DATE: 20180107
  3  * ---------------
  4  */
  5 
  6 extern int insert(int val);
  7 extern void print();
  8 extern void destroy();
  1 /* FILE: p65_linkOperate_main.c
  2  * DATE: 20180107
  3  * --------------
  4  */
  5 
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 
  9 #include "p65_linkOperate_list.h"
 10 
 11 int main(void)
 12 {
 13         int i;
 14         for(i=0; i<5; i++)
 15         {
 16                 if(insert(i) < 0)
 17                         exit(-1);
 18         }
 19         print();
 20         destroy();
 21         return 0;
 22 }
  1 # FILE: Makefile
  2 # DATE: 20180107
  3 # ==============
  4 
  5 OBJECTS = p65_linkOperate_list.o p65_linkOperate_main.o
  6 
  7 build: $(OBJECTS)
  8         gcc -o build $(OBJECTS)
  9 
 10 p65_linkOperate_list.o: p65_linkOperate_list.c
 11         gcc -c p65_linkOperate_list.c
 12 
 13 p65_linkOperate_main.o: p65_linkOperate_list.h p65_linkOperate_main.c
 14         gcc -c p65_linkOperate_main.c
 15 
 16 .PHONY: clean
 17 clean:
 18         rm build $(OBJECTS)

补充删除指定节点函数

 49 /* 删除指定节点 */
 50 int del(int val)
 51 {
 52         struct node *p, *q;
 53         p = head;
 54         if(p == NULL)   // 链表为空
 55         {
 56                 fprintf(stderr, "ERROR: the link-list is empty.\n");
 57                 return -1;
 58         }
 59         if(p->val == val)       // 第一个节点就是要删除的节点
 60         {
 61                 head = p->next;
 62                 free(p);
 63                 return 0;
 64         }
 65         else if(p->next == NULL)        // 只有一个节点,且不是所要删除的
 66         {
 67                 printf("ERROR: delete, nOt found\n");
 68                 return -1;
 69         }
 70         q = p;
 71         p = p->next;
 72         while(p != NULL)
 73         {
 74                 if(p->val == val)
 75                 {
 76                         q->next = p->next;
 77                         free(p);
 78                         printf("SUCCESS: delete.\n");
 79                         return 0;
 80                 }
 81                 q = p;
 82                 p = p->next;
 83         }
 84         printf("ERROR: delete, nOt found\n");
 85         return -1;
 86 }






``` #include"iostream" using namespace std; #define MAX_SIZE 7 const int NO_SPACE = -1; //const int MAX_SIZE=7; typedef struct node { //定义数据域; int data; //定义指向下一个节点的“指针”next,即游标; int next; }StaticNode; StaticNode staticList[MAX_SIZE]; // 备用链表头游标 int avail; /*注意: * 备用链表的作用 动态管理节点: 当需要插入节点时,从备用链表中取出一个空闲节点。 当删除节点时,将节点释放回备用链表。 提高效率: 备用链表通过 avail 指针快速定位空闲节点,避免了遍历整个数组的开销。 总结 备用链表不需要单独创建,它是静态链表初始化时自动生成的一部分。 通过 avail 指针管理备用链表,可以高效地分配和释放节点。 备用链表与静态链表共享同一个数组,节点在主链表和备用链表之间动态切换。 */ void inital_staticList() { /*创建备用链表 初始化数组:定义一个结构体数组, 每个元素包含数据和游标(指示下一个节点的索引)。 设置游标:将所有节点的游标指向下一个节点, 最后一个节点的游标设为-1,表示链表结束。 设置头指针:用一个变量(如avail)指向备用链表的第一个节点。 */ for (int i = 0; i < MAX_SIZE - 1; i++) { staticList[i].data = i+1; /*第一:头节点处理:通常list[0]作为头节点, 其next指向第一个可用位置 */ // 第二:游标域,指向下一个节点的索引 staticList[i].next = i + 1; } staticList[MAX_SIZE - 1].next = -1; avail = 0; cout << "现在已完成静态链表和备用链表的创建。" << endl; } int get_node() { if (avail != -1) { int freeNodeIndex = avail; avail = staticList[avail].next; return freeNodeIndex; //不要像下面一样这样写: /*avail=stasticList[avail].next; return avail; 这样写的话,其实返回的并不是原来备用链表头部对应的下标。 */ } else { return NO_SPACE; } } int Find_the_previous_node(int &insert_Index) { int the_previous_Index =0; while (the_previous_Index != -1) { if (staticList[the_previous_Index].next == insert_Index) { return the_previous_Index; } //写的时候忘记写更新索引这一段了: // 更新索引 the_previous_Index = staticList[the_previous_Index].next; } return -1;// 未找到时返回-1 } void insert_node(int &node_Index,int &insert_Index) { int the_previous_Index; the_previous_Index=Find_the_previous_node(insert_Index); if (the_previous_Index == -1) { cout << "未找到要插入节点对应的上一个结点的下标索引。" << endl; return; } //下面一句是错误的: // staticList[insert_Index].next=staticList[the_previous_Index].next; //insert_Index=staticList[the_previous_Index].next; staticList[insert_Index].next =insert_Index; staticList[the_previous_Index].next=node_Index; } int main() { inital_staticList(); /*nodeIndex 是一个变量,表示从备用链表中取出的空闲节点的索引。 在静态链表中,节点是通过数组实现的,而数组的索引(即下标)用于唯一标识每个节点。 因此,nodeIndex 就是数组中某个节点的位置。*/ int node_Index=get_node(); if (node_Index < 0) { cout << "抱歉,没有多余的备用结点,静态链表的空间已经用尽!" << endl; } else { cout << "现在进行插入节点操作,请输入你要插入的结点位置:" << endl; int insert_Index; cin >> insert_Index; //自己写的时候忘记了下面的if语句: if (insert_Index < 0 || insert_Index >= MAX_SIZE) { cout << "插入位置无效!" << endl; } else { insert_node(node_Index, insert_Index); } } return 0; }```这个代码为什么无法是实现插入新的数据?
03-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值