2016-01-15 6 views
0

У меня трудное время, обертывающее мою голову вокруг C. Я пытаюсь реализовать связанный с FIFO список, где у меня есть ссылка на хвост списка для легкого доступа при добавлении элементов. Захват пустого списка отлично работает, когда голова и тыл будут тем же узлом. Однако, когда я вхожу в очередь во второй раз, задняя часть - это правильно новый узел, но голова также обновляется, что должно оставаться неизменным. Любые мысли о том, что я могу делать неправильно? Я заранее извиняюсь за однострочное условие, если его трудно прочитать.Неполадка добавления к задней части очереди FIFO в C со ссылкой на последний элемент

typedef struct node { 
    PCB *pcb; 
    struct node *next; 
}Node; 

typedef struct queue { 
    Node *head, *rear; 
    int size; 
}Queue; 

Queue * enqueue (Queue *queue, PCB *pcb) { 

    // Ready a new node to add to list: 
    Node node = {pcb, NULL}; 

    // Node becomes head in empty list, otherwise appended to rear. 
    queue->size == 0 ? (queue->head = queue->rear = &node) : (queue->rear = &node); 

    // Keep track of list size 
    queue->size++; 

    return queue; 
} 

ОБНОВЛЕНО:

Queue * enqueue (Queue *queue, PCB *pcb) { 


    // Ready a new node to add to list: 
    Node *node = malloc(sizeof(Node)); 
    node->pcb = pcb; 
    node->next = NULL; 

    // Node becomes head in empty list, otherwise appended to rear. 
    queue->size == 0 ? (queue->head = queue->rear = node) : (queue->rear->next = node); 

    // New node always becomes the new rear node 
    queue->rear = node; 

    // Keep track of list size 
    queue->size++; 

    return queue; 
} 
+3

Сохраняется адрес локальной переменной в вашей очереди. 'node' выйдет за пределы области после возврата из' enqueue' и оставит указатели на очередь, указывающие на недопустимую память. –

+0

Пожалуйста, покажите [MCVE] (http://stackoverflow.com/help/mcve). –

+0

Дополнение к комментарию M Oehm: если вы объявляете 'static Node node = {pcb, NULL}; ваш код может работать, потому что тогда' node' будет существовать во время всего выполнения вашей программы, а не только внутри 'enqueue' function' –

ответ

0

Попробуйте

#include <stdlib.h> 
typedef struct node { 
    PCB *pcb; 
    struct node *next; 
} Node; 

typedef struct queue { 
    Node *head, *rear; 
    int size; 
} Queue; 

Queue *enqueue (Queue *queue, PCB *pcb) { 
    if (queue->size == 0) { 
    queue->head = queue->rear = malloc(sizeof(Node)); 
    } 
    else { 
    queue->rear->next = malloc(sizeof(Node)); 
    queue->rear = queue->rear->next; 
    } 
    queue->rear->pcb = pcb; 
    queue->rear->next = NULL; 
    queue->size++; 
    return queue; 
} 

Но с помощью C++ было бы гораздо проще и безопаснее. И запомните free() ваши заметки позже.

Для документации (см. Комментарии): Ошибка первого подхода в вопросе заключается в сохранении указателя локальной переменной. Он находится в стеке, но действует только до тех пор, пока функция не завершится. После завершения это указатель на местоположение в стеке. Это место будет перезаписано, как только будет вызвана следующая функция, используя достаточные локальные переменные. Решение распределяется по куче.

+0

Прежде чем я увидел это сообщение, я исправился с моим кодом после того, как понял, что мой код не правильно правильно назначил следующие узлы. Но я действительно люблю твою лучше. Благодаря! –

+0

Посмотрите на C++ и контейнеры STL. Это упрощает создание динамических структур данных. Повеселись. – Kellerspeicher

+0

Приложение: Я сделал ошибку, чтобы написать этот пример C с использованием компилятора C++. Таким образом, если вы не используете бросок, вы получите недопустимое преобразование из «void *» в «node *». Но если вы напишете C, вы будете использовать компилятор C. И в этом случае это лучше и безопаснее ** не бросать ** (например, см. [Здесь] (http://stackoverflow.com/questions/605845) почему). Поэтому я обновил ответ. – Kellerspeicher

0

Ваш обновленный код не совсем прав, когда первый узел добавлен в очередь, потому что строка queue->head->next = queue->rear; устанавливает node->next = node вместо того, чтобы оставить ее равной NULL. Кроме того, новый rear всегда будет новым узлом и может быть установлен за пределами инструкции if/else.

Queue * enqueue (Queue *queue, PCB *pcb) { 

    // Ready a new node to add to list: 
    Node *node = calloc(1, sizeof(Node)); 
    node->pcb = pcb; 
    node->next = NULL; 

    // Node becomes head in empty list, otherwise appended to rear. 
    if (queue->size == 0) { 
     queue->head = node; 
    } else { 
     queue->rear->next = node; 
    } 
    queue->rear = node; 

    // Keep track of list size 
    queue->size++; 

    return queue; 
} 
+0

Тогда это должно быть вместо 'queue-> head = queue-> rear = node'? –