将struct指针元素复制到指针似乎会破坏它

时间:2011-05-30 15:15:40

标签: c

我还在学习C,我必须在某些时候误解指针。

我认为以下行会将l->first存储的内存地址复制到temp。它们都是struct list_el*指针,所以我看不出问题。

struct list_elt * temp;
temp = l->first;

运行我的示例代码给了我一个无限循环:

user@machine:~$ gcc question.c 
user@machine:~$ ./a.out | head
append(): l->first->val: 30, l->first->next == NULL: 1
main()  : l->first->val: 30, l->first->next == NULL: 1
print() : l->first->val: 30, l->first->next == NULL: 1
print() : temp->val: 30, temp->next == NULL: 0
print() : temp->val: 30, temp->next == NULL: 0
print() : temp->val: 30, temp->next == NULL: 0
print() : temp->val: 30, temp->next == NULL: 0
print() : temp->val: 30, temp->next == NULL: 0
print() : temp->val: 30, temp->next == NULL: 0
print() : temp->val: 30, temp->next == NULL: 0

这是question.c。对不起,我无法进一步缩小范围,每次我做这个问题似乎神奇地消失了。

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

struct list_elt {
    int val;
    struct list_elt * next;
};
struct linked_list {
    struct list_elt* first;
};

void print(const struct linked_list * l);
struct linked_list* new_list(void);
void append(struct linked_list* l, int value);


main()
{
    struct linked_list * l;
    l = new_list();
    append(l, 30);
    printf("main()  : l->first->val: %d, l->first->next == NULL: %d\n", l->first->val, l->first->next == NULL);
    print(l);
}

struct linked_list* new_list()
{
    struct linked_list* l;
    l = (struct linked_list*) malloc(sizeof(struct linked_list));
    l->first = NULL;
    return l;
}

void append(struct linked_list* l, int value)
{
    struct list_elt el = {0, NULL};
    el.val = value;
    el.next = NULL;
    if (l->first == NULL) {
        l->first = (struct list_elt*) &el;
        printf("append(): l->first->val: %d, l->first->next == NULL: %d\n", l->first->val, l->first->next == NULL);
    } else {
        printf("append(): Unimplemented\n");
    }
}


void print(const struct linked_list * l)
{
    printf("print() : l->first->val: %d, l->first->next == NULL: %d\n", l->first->val, l->first->next == NULL);
    struct list_elt * temp;
    temp = l->first;
    while (temp != NULL) {
        printf("print() : temp->val: %d, temp->next == NULL: %d\n", temp->val, temp->next == NULL);
        temp = temp->next;
    }
    printf("\n");
}

感谢。

5 个答案:

答案 0 :(得分:5)

您正在append函数的堆栈上分配list_elt。函数返回后该指针无效,不应再引用。

您应该使用malloc来分配元素。

答案 1 :(得分:3)

append()中,您将l->first设置为本地堆栈变量el的地址。但是el一旦append()返回就会超出范围,因此之后任何取消引用l->first的尝试都是未定义的行为

答案 2 :(得分:3)

(以下是一个非常简单的解释,非常简单,以至于它可以说是非常简洁。我只是为了简单,但你可以通过谷歌搜索堆栈和C中的堆来了解更多。)

基本上有两种方法可以创建并将它们存储在内存中:使用堆栈,或者向操作系统请求内存

堆栈是临时内存,用于跟踪当前执行上下文。每次调用函数时,堆栈的一个扇区都用于存储所有局部变量。这就是您在append()中所做的事情:使用位于堆栈中的临时内存来存储新的列表节点

堆栈中的任何内容(任何局部变量)在从函数返回时被视为时间和空间丢失,因为当前执行上下文不再相关,并且该存储器被重用于另一个上下文(例如,下一个函数调用)。这是不可避免的,这是这个内存管理方式的结果,它发生在C的直接范围之外(或者更确切地说,你不应该把它弄乱)。

如果您希望在本地范围之外存储与程序相关的内容,而不仅仅是当前执行上下文,您必须向操作系统请求额外的内存 - 此临时< em> stack 不会这样做。有很多功能 - 请查看最简单的malloc()

希望它有所帮助。干杯!

答案 3 :(得分:1)

您的append功能错误。它在堆栈上分配el,并使用列表中的指针。这样做的问题是,在append之后调用另一个函数时,内存将被垃圾覆盖,在本例中为print。相反,使用malloc进行分配,例如:

int append(struct linked_list* l, int value)
{
    struct list_elt *el = malloc(sizeof(struct list_elt));

    if (el)
    {
        el->val = value;
        el->next = NULL;
        if (l->first == NULL) {
            l->first = el;
            printf("append(): l->first->val: %d, l->first->next == NULL: %d\n",
                   l->first->val, l->first->next == NULL);
        } else {
            printf("append(): Unimplemented\n");
        }

        return 0;
    }
    else
    {
        return 1;
    }
}

答案 4 :(得分:0)

在附加中,您的元素在堆栈上创建并稍后引用:这是错误的。当您的函数退出时,el变量不再存在。你需要malloc你的list_elt。