2010-09-22 5 views
0

Я пытаюсь реализовать очереди в С. Coming из Java и других управляемых языков, я действительно борюсь с управлением памятью. Вот enqueue() функция:таНоса терпит неудачу Катастрофический

int enqueue(Queue q, int value) { 

    Node newNode = malloc(sizeof(Node)); 
    /*newNode->value = value; 

    if (q->size == 0) 
     q->head = newNode; 
    else 
     q->head->next = &newNode; 

    q->size++;*/ 
} 

Я получаю эту ошибку:

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed. 

FWIW, вот остальная часть кода (это даже не так ли?):

typedef struct NodeStruct *Node; 
struct NodeStruct { 
    Node* prev; 
    Node* next; 
    int value; 
}; 

typedef struct QueueStruct *Queue; 
struct QueueStruct { 
    Node* head; 
    Node* tail; 
    int size; 
    int capacity; 
}; 

Queue newQueue(int size) { 
    Queue q = malloc(sizeof(Queue)); 

    q->capacity = size; 
    q->size = 0; 
    q->head = NULL; 
    q->tail = NULL; 

    return q; 
} 

void printQueue(Queue q) { 
    printf("Queue of size %d, capacity %d", q->size, q->capacity); 
}  

int main() { 
    Queue myQ = newQueue(10); 

    // this seems to work 
    printQueue(myQ); 
    // epic fail 
    enqueue(myQ, 5); 

    return 0; 
} 

Почему это происходит?

+2

Проблемы произошла, как до этого вызова 'malloc', когда вы затерт о прошлом что-то выделено более раннем вызовом' malloc' или с неинициализированным указателем. Удачи вам в этом. –

+0

Несмотря на то, что код закомментирован, я укажу, что 'enqueue' действительно неверно: он сохраняет адрес переменной * local * (который даже не компилируется), и он не инициализирует членов 'Node'. Кроме того, добавление чего-то в очередь обычно связано с добавлением к хвосту, а не к элементу после головы. – jamesdlin

+0

* Всегда * проверяйте результат 'malloc'! Для этого вы можете использовать обертку для этого (поиск по [xmalloc] (http://gcc.gnu.org/onlinedocs/libiberty/Functions.html#index-xmalloc-202) в Интернете). Если это домашнее задание, добавьте тег * homeework * к вопросу. –

ответ

10

Следующая строка, вероятно, дает вам горе:

Node newNode = malloc(sizeof(Node)); 

Node является тип указателя, так что вы только выделить достаточно места для хранения указателя, а не весь NodeStruct. Я думаю, что вы хотите сделать, это:

Node newNode = malloc(sizeof(*newNode)); 

или

Node newNode = malloc(sizeof(NodeStruct)); 

Та же проблема существует для Queue, вы только выделенное пространство для хранения указателя, а не QueueStruct. Что-то еще, что я только что заметил, заключается в том, что в вашихи QueueStruct вы используете тип Node*, который на самом деле NodeStruct **, что, вероятно, не то, что вы хотите, так как Node уже указатель.

+5

Это прекрасный пример того, почему часто считается плохим стилем, чтобы скрыть указатель внутри 'typedef'. – caf

+1

@caf: он мог бы также использовать печально известную [венгерскую нотацию] (http://www.joelonsoftware.com/articles/Wrong.html), например. 'Node' и' pNode'. Это спасло бы ему много неприятностей. –

5

вы намолочено ваша куча

если вы на использование Linux электрический забор или Valgrind, чтобы выяснить, где вы пошли неправильно

редактировать: Вы имеете в виду

Queue q = malloc(sizeof(QueueStruct)); 

и то же самое для узла

Node n = malloc(sizeof(NodeStruct)); 

, и я согласен с другими - его очень в заблуждение называть указатель на NodeStruct узел. Лучше назвать его NodePtr или PNode и вызвать узел структуры.

+0

-1, проблема более фундаментальная, чем это, как отметили dreamlax и caf. –

+0

нет его нет - именование вводит в заблуждение, но исправление одинаков – pm100

+0

Достаточно справедливо. Если вы упомянули, что существует такая же проблема для 'Node' и' NodeStruct', и объясните, почему (помните, что OP приходит с Java), я перейду на +1. –

8

Это часто считается плохим стилем в C, чтобы скрыть указатель в пределах typedef. Это потому, что вы нужно знать, что что-то является указателем его правильно использовать, в любом случае. (Например, даже непрозрачный тип FILE в стандартной библиотеке используется и пропускают вокруг как FILE *).

Это, кажется, привело вас в заблуждение - например, ваши next и prev членов на самом деле являются указателями на указатели, что на самом деле не так, как вы хотите. Я предлагаю:

typedef struct NodeStruct Node; 
typedef struct QueueStruct Queue; 

struct NodeStruct { 
    Node *prev; 
    Node *next; 
    int value; 
}; 

struct QueueStruct { 
    Node *head; 
    Node *tail; 
    int size; 
    int capacity; 
}; 

Queue *newQueue(int size) { 
    Queue *q = malloc(sizeof(Queue)); 

    q->capacity = size; 
    q->size = 0; 
    q->head = NULL; 
    q->tail = NULL; 

    return q; 
} 

int enqueue(Queue *q, int value) { 

    Node *newNode = malloc(sizeof(Node)); 

    newNode->value = value; 
    newNode->next = NULL; 

    if (q->size == 0) 
    { 
     newNode->prev = NULL; 
     q->tail = q->head = newNode; 
    } 
    else 
    { 
     newNode->prev = q->tail; 
     q->tail->next = newNode; 
     q->tail = newNode; 
    } 

    q->size++; 
    return 0; 
} 

void printQueue(Queue *q) { 
    printf("Queue of size %d, capacity %d\n", q->size, q->capacity); 
} 

int main() { 
    Queue *myQ = newQueue(10); 

    printQueue(myQ); 
    enqueue(myQ, 5); 

    return 0; 
} 
+0

Не могу принять более 1 ответа, но +1 – Aillyn

Смежные вопросы