Нечетная проблема с указателем при реализации связанного списка - PullRequest
0 голосов
/ 03 июля 2011

Я пытаюсь реализовать связанный список в C, и я хочу сохранить головной узел в отдельной структуре. Однако создается впечатление, что головной узел каким-то образом переназначается, когда я добавляю другой узел.

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

struct BC_node {
    struct BC_node *next;
    void *data;
};
struct BC_list {
    struct BC_node *head;
    struct BC_node *tail;
};

void
BC_list_push(struct BC_list *list, void *data)
{
    struct BC_node *node = calloc(1, sizeof(struct BC_node));

    if (list->head != NULL)
        printf("head: %d\n", *((int *) (list->head)->data));

    node->next = NULL;
    node->data = data;
    if (list->head == NULL) {
        printf("head is null.\n");
        list->head = node;
    }
    if (list->tail != NULL) {
        (list->tail)->next = node;
    }
    list->tail = node;

    printf("head: %d\n", *((int *) (list->head)->data));
}

int
main(void)
{
    int i;
    struct BC_list *list = calloc(1, sizeof(struct BC_list));

    list->head = NULL;
    list->tail = NULL;
    for (i = 0; i < 3; i++)
        BC_list_push(list, &i);
    return 0;
}

Выход:

head is null.
head: 0
head: 1
head: 1
head: 2
head: 2

Ответы [ 4 ]

6 голосов
/ 03 июля 2011

Ваш элемент data является просто указателем на переменную i в main, поэтому, когда вы печатаете *data, вы просто видите значение счетчика во время этого цикла цикла. Все ваши узлы имеют одинаковое значение данных!

2 голосов
/ 03 июля 2011

Это хуже. & i - это адрес локальной переменной, что означает, что вы ссылаетесь из списка, выделенного в куче, на стек, переменную volatile ... Это совершенно неверно - если вы делаете это в методе, отличном от main, тогда у вас есть локальная переменная исчезнет, ​​и ваш указатель укажет на какое-то случайное место в памяти, возможно, на другие переменные или адреса ... очень плохо.

2 голосов
/ 03 июля 2011

Проблема в этой строке:

BC_list_push(list, &i);

Вы передаете адрес i, который является целым числом, которое вы увеличиваете в цикле (таким образом, значение изменяется). Вам необходимо выделить отдельную память для аргумента data.

for (i = 0; i < 3; i++)
{
    int *d = malloc(sizeof(int));
    *d = i;
    BC_list_push(list, d);
}

Но не забудьте освободить память, когда список уничтожен.

1 голос
/ 20 июля 2011

Вот полный пример с вашей структурой и выделением памяти для данных,

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

struct BC_node{
    void *data;
    struct BC_node *next;
};
struct BC_list{
    struct BC_node *head;
    struct BC_node *tail;
};

struct BC_node *BC_new_node(void *data,size_t szdata)
  {
    struct BC_node *ptr=malloc(sizeof(struct BC_node));
    if(ptr!=NULL){
        ptr->data=malloc(szdata);
        ptr->next=NULL;
        if(ptr->data!=NULL)
            memcpy(ptr->data,data,szdata);
        else free(ptr),ptr=NULL;
    }
    return ptr;
  }

int BC_list_push(struct BC_list *list,void *data,size_t szdata)
  {
    struct BC_node *ptr=BC_new_node(data,szdata);
    if(list!=NULL && ptr!=NULL){
        if(list->tail==NULL){
            list->head=ptr;
            list->tail=ptr;
        } else {
            list->tail->next=ptr;
            list->tail=ptr;
        }
        return 0;
    }
    return 1;
  }

void *BC_new_list(void)
  {
    struct BC_list *ptr=malloc(sizeof(struct BC_list));
    if(ptr!=NULL)
        ptr->head=ptr->tail=NULL;
    return ptr;
  }

void BC_free_list(struct BC_list *list)
  {
    struct BC_node *ptr;
    while(list->head){
        ptr=list->head->next;
        free(list->head->data);
        free(list->head);
        list->head=ptr;
    }
    free(list);
  }

void print_test(struct BC_list *list){
    struct BC_node *ptr=list->head;
    while(ptr){
        printf("%s\n",(char*)ptr->data);
        ptr=ptr->next;
    }
}

int main(void)
  {
    char tab[3][40]={"hello","world","test"};
    struct BC_list *list=BC_new_list();
    if(list!=NULL){
        BC_list_push(list,tab[0],strlen(tab[0])+1);
        BC_list_push(list,tab[1],strlen(tab[1])+1);
        BC_list_push(list,tab[2],strlen(tab[2])+1);
        print_test(list);
        BC_free_list(list);
    }
    return EXIT_SUCCESS;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...