【问题标题】:Initializing doubly linked list in for-loop results in crash在for循环中初始化双向链表会导致崩溃
【发布时间】:2016-01-21 22:46:44
【问题描述】:

我正在使用双向链表用 C 语言编写经典的 Snake 游戏,并编写了一个函数来创建指针,为结构分配所需的空间,然后为列表中的下一个指针分配内存等等。最后函数返回指向第一个元素的指针,可以在主函数中赋值给头指针。

开始游戏时,我希望蛇的长度为 3,因此我在函数中有三个 malloc,并使用了指针、指针->下一个、指针->下一个->下一个等等,一切正常。

由于在这个过程中必须重复很多步骤,所以我想把所有这些都放入一个这样的 for 循环中:

#include <stdio.h>
#include <stdlib.h>

typedef struct snake snake;
struct snake {
    int x; /* x coordinate */
    int y; /* y coordinate */
    snake *previous;
    snake *next;
};

snake *initSnake(void) {
    snake *pointer, *tmp1, *tmp2 = NULL;
    /* three iterations, so the snake will have a length of three */
    for( int i = 0; i<3; i++, tmp1 = tmp1->next) {
        if(NULL == (tmp1 = (snake*)malloc(sizeof(snake)))) {
            return NULL;
        }
        /* coordinates */
        tmp1->x = 20;
        tmp1->y = 10 + i;
        /* first previous points to NULL */
        tmp1->previous = tmp2;
        /* temporarily store last pointer to be used for next previous pointer */
        tmp2 = tmp1;
        if(0 == i) {
            /* store first pointer so it can be returned */
            pointer = tmp1;
        }

    }
    /* the last next pointer has to point to NULL */
    tmp1 = NULL;
    /* now return the pointer to the first element in list */
    return pointer;
}


int main() {
    /* pointer to first element in list */
    snake *head = NULL;

    if(NULL == (head = initSnake() ) ) {
        fprintf(stderr, "Not enough memory!\n");
        return EXIT_FAILURE;
    }
    /* here everything works fine */
    printf("%d\n", head->y);
    printf("%d\n", head->previous);
    /* when trying to acces the content of the next element, the program crashes... */
    printf("%d\n", head->next->x);
    /* pause */
    getchar();
}

问题是当我尝试访问主函数内列表的第二个元素时,游戏崩溃了。我怀疑有什么问题 tmp1 = tmp1-&gt;next 在 for 循环中,我并没有真正访问下一个指针,但我不完全确定。

你能帮帮我吗?

【问题讨论】:

  • 可能设置 tmp1->next = NULL 会有所帮助,或者调用 calloc 而不是 malloc。并且不要强制转换 malloc 的返回值。
  • @bruceg 为什么不强制返回 malloc?我很少看到它,但我正在做 C 讲座的教授坚持要这样做。

标签: c for-loop linked-list crash initialization


【解决方案1】:

您有很多错误表明您并不真正了解内存、变量和指针的工作原理。例如,在for 循环的末尾执行tmp1 = tmp1-&gt;next,紧随其后的tmp1 = (snake*)malloc(sizeof(snake)) 会覆盖tmp1 并使之前的操作毫无意义。您的代码中其他地方也存在类似的操作。

要清理它,试试这个:

snake *initSnake(void) {
    snake *head, **current, *prev;

    /* three iterations, so the snake will have a length of three */
    for(int i = 0, prev = NULL, current = &head; i<3; i++) {
        if(NULL == (*current = malloc(sizeof(snake)))) {
            return NULL; /* note that if this happens midway
                  through allocation, nothing gets freed */
        }
        /* coordinates */
        (*current)->x = 20;
        (*current)->y = 10 + i;
        /* next, previous pointers */
        (*current)->next = NULL;
        (*current)->previous = prev;
        prev = *current;
        current = &current->next;
    }

    /* now return the pointer to the first element in list */
    return head;
}

【讨论】:

    【解决方案2】:

    你必须将最后一个 next 指针设置为 NULL:

    /* the last next pointer has to point to NULL */
    tmp1->next = NULL;   // -> next !
    

    因为tmp1 是一个局部变量,在返回之前将其设置为NULL 将无效。

    编辑:

    糟糕,也不要在 for 循环中执行 tmp1 = tmp1-&gt;next:因为在您尝试执行此操作时未设置它。您需要将 next 与 previous 一起设置:

       /* first previous points to NULL */
        tmp1->previous = tmp2;
        if (tmp2) 
            tmp2->next = tmp1; 
    

    Online demo

    【讨论】:

    • 但是 tmp1 已经是列表中的最后一个 -&gt;next pointer,因为我在离开循环之前将 tmp1 设置为 tmp1-&gt;next
    • 在您执行 tmp1 = tmp1->next 的那一刻,您从未设置过 next 的值。查看我的编辑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多