3-malloc链表和栈上的一些比较

47 阅读4分钟

一个最简单的链表

大家一般看到的链表都是在直接使用堆 malloc分配空间然后封装成函数 个人觉得不是很适合初学者 或者说 太突兀了 和之前的内容 间隔过多了 甚至于我每次想要复习链表都要很大的勇气来 翻看那很长一串的代码 很抽象的代码 但是这个是我想出来的最简单的一个链表 这个只能有我们自己使用 长度里面的值都是写死了的 但是 很简洁 没有封装 和一些其他的东西


#include "head.h"
typedef struct node
{
    int value;
    // node_t * next;
    struct node *next;
} node_t;

int main()
{

    node_t head;
    node_t *temp = head.next;

    head.value = -1;
    // NULL 一般作为一个宏出现 是被封装在 stddef里面的
    head.next = NULL;
    node_t n1 = {.next = NULL, .value = 1};
    node_t n2 = {.next = NULL, .value = 2};
    node_t n3 = {.next = NULL, .value = 3};
    node_t n4 = {.next = NULL, .value = 4};
    node_t n5 = {.next = NULL, .value = 5};

    head.next = &n1;
    n1.next = &n2;
    n2.next = &n3;
    n3.next = &n4;
    n4.next = &n5;

    temp = &head;
    for (int i = 0; i < 20; i++)
    {
        printf("%d  ", temp->value);
        temp = temp->next;
        if (temp->next == NULL)
        {
            break;
        }
    }
    
    return 0;
}

一些问题

为什么不用for循环

 for (int i = 0; i < 10; i++)
    {
        node_t new_node = {.next = NULL, .value = i};
        printf("new_node %p \n", &new_node);
        printf("head %p \n", &head);
        node_t *temp = head.next;
        printf("temp %p \n", temp);
        // temp.next = new_node;
        head.next = &new_node;
        new_node.next = temp;
        /* code */
    }

这个是一个for循环的 链表 但是这个我测试了几次都是 报错 出来的内容很抽象 然后我就看了一下 就是 c语言在一个作用域里面 生成的变量分配的 地址是相同的 即 我每次 生成 new_node 都是相同的地址 根本无法生成 链表

同样也就无法使用 函数封装了 函数里面也是 创建的都是相同的 但是虽然这个有这么多的弊端 还是感觉这个很适合初学者 或者说 拾起来这部分内容的

2 malloc和正常方式

好了,我们现在对比 一下malloc 和正常的方式 分配的内存有什么区别

    for (size_t i = 0; i < 10; i++)
    {
        // 1-使用正常的方式 在栈中开辟空间
        node_t new_1;
        node_t *new = &new_1;
        // 2-使用malloc创建
        // node_t *new = (node_t *)malloc(sizeof(node_t));
        new->value = 10;
        new->next = NULL;
        printf(" new %p\n", new);
    }

1输出

可以看到 第一种栈上的方式分配出来的每个地址都是相同的 那么 这个肯定是我发创建链表的 或者说 封装成一种 函数 在一定的作用域里面 将这部分抽象出来的

 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0

2-输出

可以看到malloc 开辟出来的每个地址空间都是不同的 这个就可以满足需求了 将这部分封装起来

 new 0x555555756260
 new 0x555555756690
 new 0x5555557566b0
 new 0x5555557566d0
 new 0x5555557566f0
 new 0x555555756710
 new 0x555555756730
 new 0x555555756750
 new 0x555555756770
 new 0x555555756790

3 malloc main创建链表

1-正常使用malloc创建链表

这种方式是可以使用重复的变量名字创建链表的 即 可以使用 for循环添加数据


#include "head.h"
typedef struct node
{
    int value;
    struct node *next;
} node_t;

int main()
{

    node_t head;
    node_t *temp;

    head.value = -1;
    // NULL 一般作为一个宏出现 是被封装在 stddef里面的
    head.next = NULL;
    
    for (size_t i = 0; i < 10; i++)
    {
        // 1-使用正常的方式 在栈中开辟空间
        // node_t new_1;
        // node_t *new = &new_1;
        // 2-使用malloc创建
        node_t *new = (node_t *)malloc(sizeof(node_t));
        new->value = i;

        new->next=head.next;
        head.next=new;
        printf(" new %p\n", new);
    }

    temp = &head;
    for (int i = 0; i < 20; i++)
    {
        printf("%d  ", temp->value);
        temp = temp->next;
        if (temp->next == NULL)
        {
            break;
        }
    }

    return 0;
}

结果正常

 new 0x555555756260
 new 0x555555756690
 new 0x5555557566b0
 new 0x5555557566d0
 new 0x5555557566f0
 new 0x555555756710
 new 0x555555756730
 new 0x555555756750
 new 0x555555756770
 new 0x555555756790
-1  9  8  7  6  5  4  3  2  1  [1]

2-测试 栈上开辟空间

这种方式无法正常创建链表


#include "head.h"
typedef struct node
{
    int value;
    struct node *next;
} node_t;

int main()
{

    node_t head;
    node_t *temp;

    head.value = -1;
    // NULL 一般作为一个宏出现 是被封装在 stddef里面的
    head.next = NULL;
    
    for (size_t i = 0; i < 10; i++)
    {
        // 1-使用正常的方式 在栈中开辟空间
         node_t new_1;
         node_t *new = &new_1;
        // 2-使用malloc创建
        //node_t *new = (node_t *)malloc(sizeof(node_t));
        new->value = i;

        new->next=head.next;
        head.next=new;
        printf(" new %p\n", new);
    }

    temp = &head;
    for (int i = 0; i < 20; i++)
    {
        printf("%d  ", temp->value);
        temp = temp->next;
        if (temp->next == NULL)
        {
            break;
        }
    }

    return 0;
}

结果错误


 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
 new 0x7fffffffdec0
-1  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9

3-malloc数组类型转链表


#include "head.h"
typedef struct node
{
    int value;
    struct node *next;
} node_t;

int main()
{

    node_t head;
    node_t *temp;

    head.value = -1;
    // NULL 一般作为一个宏出现 是被封装在 stddef里面的
    head.next = NULL;
    int arr[10] = {5, 2, 0, 1, 3, 1, 4};
    for (size_t i = 0; i < 10; i++)
    {
        node_t *new = (node_t *)malloc(sizeof(node_t));
        new->value = arr[i];
        new->next = head.next;
        head.next = new;
        printf(" new %p\n", new);
    }

    temp = &head;
    for (int i = 0; i < 20; i++)
    {
        temp = temp->next;
        printf("%d  ", temp->value);
        if (temp->next == NULL)
        {
            break;
        }
    }

    return 0;
}