创建链表(图解)

前言

好久没写博客了,寒假在家里都快躺废了。最近打算巩固一下C语言,没想到一个小小的链表竟能奈我何,看来真是学艺不精啊。

代码

为了避免读者头晕,先上简单的,能编译通过的代码,暂时不考虑程序健壮性,毕竟我们只需考虑创建链表的本质,其他细枝末节的可以暂且不管。

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
    int val;
    struct Node* next;
}Node;//创建节点结构体
int main(){
    int i;
    int n=2;//创建3个节点(一个头节点,两个数据节点)
    Node* head = (Node*)malloc(sizeof(Node));//创建头节点
    Node* p=head;
    head->val=666;
    head->next=NULL;
    for(i=0;i<n;i++){
        Node* end=(Node*)malloc(sizeof(Node));//创建尾节点
        p->next=end;
        end->val=i;
        end->next=NULL;
        p=end;
    }
}

图解

首先,创建链表可以大致分为两个过程:1.分配内存 2.移动p指针

1.分配内存

程序执行完,内存里的情况大致可以抽象成以下图像:

从左往右看,左侧的指针和右侧的内存空间形成映射关系

从上往下看,右侧的内存块(节点)前后连接

以上是从结果来看,分配完内存后的情况

注意:其实end指针是一个局部变量,每一次分配内存的end指针变量都是同名但却不同的变量,图中在后面加了一个括号以示区分

2.移动p指针

我们来逐行解释一下代码

Node* head = (Node*)malloc(sizeof(Node));//创建头节点
Node* p=head;

对应以下示意图

head指针和p指针都指向同一块内存地址(地址1)

这里插一句,用malloc分配给head内存空间,那么head指针和地址1之间就形成了“羁绊”,也就是说,要想改变head的指向(实际上就是改变head的内容),就得free(head),这也是为什么需要指针p也指向地址1,因为p可以随意改变指向

for(i=0;i<n;i++){
        Node* end=(Node*)malloc(sizeof(Node));//创建尾节点
        p->next=end;
        end->val=i;
        end->next=NULL;
        p=end;
    }

现在逐行解释以上i=0时的情况,

Node* end=(Node*)malloc(sizeof(Node));//创建尾节点

 p->next=end;

end->next=NULL;
p=end;

以此类推,读者可以自己尝试画剩下的过程图,说真的,一图抵千言

最终代码

完善后的代码如下

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
    int val;
    struct Node* next;
}Node;//创建节点结构体
int main(){
    int i;
    int n=2;//创建2个数据节点(加上头节点,总共有3个节点)

    Node* head = (Node*)malloc(sizeof(Node));//创建头节点
    if (head == NULL) { // 检查malloc是否成功  
    printf("Memory allocation failed for head node.\n");  
    return 1; // 返回非零值表示错误  
}

    Node* current=head;
    head->val=666;
    head->next=NULL;

    for(i=0;i<n;i++){
        Node* end=(Node*)malloc(sizeof(Node));//创建尾节点
        if (end == NULL) { // 检查malloc是否成功  
            printf("Memory allocation failed for node %d.\n", i);  
            // 释放之前已经分配的内存  
            while (current != NULL) {  
                Node* temp = current;  
                current = current->next;  
                free(temp);  
            }  
            
            return 1; // 返回非零值表示错误  
        }  
        current->next=end;
        end->val=i;
        end->next=NULL;
        current=end;
    }
     
      // 遍历并打印链表(可选)  
    current = head;  
    while (current != NULL) {  
        printf("%d ", current->val);  
        current = current->next;  
    }  
    printf("\n"); 

    current= head;  
    while (current != NULL) {  
        Node* temp = current;  
        current = current->next;  
        free(temp);  
    }  
    
    system("pause");
    return 0;
}

运行结果

结语

总结了以下,其实难点还是在于指针,指针理解的不够深刻,在这方面可以多画画示意图可以有助于理解

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋窗7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值