将项目推送到链接列表(C)

时间:2018-02-07 19:11:46

标签: c linked-list double-pointer

我目前正在尝试将结构推送到列表,我不得不在不使用标准库的情况下执行此操作(因此没有malloc或calloc等)。因此我有点挣扎,这是我到目前为止所做的。

typedef struct node node_t;
struct node{
    int val;
    node_t *next;
    node_t *prev;
};

node_t nodes[10];
node_t blocked[10];



void init(){
    for(int i = 0; i < 10; i++){
        nodes[i].val = i;
        if(i == 0){
            nodes[i].next = &nodes[i+1];
            nodes[i].prev = NULL;
        }
        else if(i == 9){
            nodes[i].next = NULL;
            nodes[i].prev = &nodes[i-1];
        }else{
            nodes[i].next = &nodes[i+1];
            nodes[i].prev = &nodes[i-1];
        }
    }
}


node_t *push(node_t **arr, node_t node){

node_t *newhead = &node;
printf("%d\n", newhead->val);
newhead->next = (*arr);
printf("%d\n", (*arr)->val);

return newhead; 
}

int main(){


    init();
    node_t *head = &nodes[0];


    node_t *blockhead = &blocked[0];
    blockhead = push(&blockhead,nodes[3]);
    blockhead = push(&blockhead,nodes[4]);


    return 0;
}

我遇到的问题是该列表只跟踪我添加到列表中的最后一个元素,如果尝试访问列表中的下一个值,则会崩溃,这可能意味着我正在尝试访问NULL指针,但据我所知,一切似乎都是正确的,但也许我错过了一些非常明显的东西? &#34; push&#34;作为一个整体的功能是简单地将节点添加到列表的前面,而不是其他所有节点。

1 个答案:

答案 0 :(得分:1)

您的直接问题是node之前没有声明:

node_t *newhead = &node;

你正在接受一些不存在的东西的地址 - 这绝不是一个好主意(并调用未定义的行为,通常是一个SegFault)。

nodes无需全局声明 ,根本不需要blocked(基于您当前的代码)。避免使用全局变量。在main()中声明变量,并根据需要将变量(或指针)传递给任何函数。

如果您使用类型node_t的数组作为没有分配的链接列表,然后查找"push"(例如,在开头添加新的node_t作为新的列表地址),那么您基本上只需要让你newnode.next指向你的nodes数组(因为数组的地址只是指向其第一个成员的指针),你需要array[0].prev指向地址newnode

从我可以从你的问题中收集到的内容,代码的目的是指针理解。无论您是处理存储在堆栈中的列表还是全局分配的列表,如果更改列表中的第一个节点,您将更改列表地址(因为列表的开头是第一个节点的地址)要更改函数中的列表地址,必须将地址列表作为参数传递给函数 - 或 - 返回指向新第一个节点的指针并将地址分配给你的列表指针回到调用者。 (两者都显示在下面)

由于您希望"push"本地声明的节点到列表的头部,所以必须以类似的方式将该节点的地址传递给push函数,因此它是如果节点本身作为参数传递给push函数,则使用该节点的实际地址而不是创建的节点副本的地址。您可以使用类似于以下内容的方法执行此操作,以通过推送到列表头部的新节点处理作为列表的节点数组:

/* push takes address of array and address of node as parameters */
node_t *push (node_t **arr, node_t *node)
{
    node->next = *arr;              /* next for new node is list address */
    (*arr)[0].prev = node;          /* prev for list is new node address */
    *arr = node;                    /* new node address is new list address */

    return node;                    /* return pointer to new 1st node */
}

您只需将newnode->next设置为当前列表地址,然后将list->prev设置为指向新节点,然后将列表地址设置为newnode的地址(还返回指向该地址的指针,可以根据需要在调用者中分配回来。)

其余的更改实际上只是对您所拥有的内容进行清理,根据需要为您的函数添加参数,以便nodesmain()正确声明prn并添加#define用于打印列表的函数。此外,节点中的代码中没有使用幻数。如果您需要常量enum一个(或更多),或使用全局#include <stdio.h> #define LMAX 10 /* if you need a constant, define one */ typedef struct node { int val; struct node *prev, *next; } node_t; void init (node_t *nodes) { for (int i = 0; i < LMAX; i++){ nodes[i].val = i; if (i == 0) nodes[i].prev = NULL; else { nodes[i-1].next = &nodes[i]; nodes[i].prev = &nodes[i-1]; } } } /* push takes address of array and address of node as parameters */ node_t *push (node_t **arr, node_t *node) { node->next = *arr; /* next for new node is list address */ (*arr)[0].prev = node; /* prev for list is new node address */ *arr = node; /* new node address is new list address */ return node; /* return pointer to new 1st node */ } /* simple print list */ void prn (node_t *list) { for (; list; list = list->next) printf (" %d", list->val); putchar ('\n'); } int main (void) { node_t nodes[LMAX], /* array of nodes */ *head = nodes, /* list pointer */ singlenode = { .val = LMAX }; /* new node to push */ init(head); /* init list */ prn (head); /* print list */ push (&head, &singlenode); /* push new node to list */ prn (head); /* print new list */ return 0; } 来定义它们(这是对全局的有效使用)。

完全放弃,您可以执行以下操作:

$ ./bin/lldblstatic
 0 1 2 3 4 5 6 7 8 9
 10 0 1 2 3 4 5 6 7 8 9

示例使用/输出

throw Promise

仔细看看,注意地址和指针的使用。如果您还有其他问题,请不要犹豫。