2010-09-22 3 views
0

J'essaie d'implémenter une file d'attente dans C. Venant de Java et d'autres langages gérés, je suis vraiment aux prises avec la gestion de la mémoire. Voici la fonction enqueue():malloc échoue de manière catastrophique

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++;*/ 
} 

Je reçois cette erreur:

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, voici le reste du code (est-ce même droit?):

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; 
} 

Pourquoi Est-ce que cela arrive?

+2

Le problème est arrivé bien avant cet appel à 'malloc', lorsque vous mis à mal sur le passé de quelque chose attribué par un appel précédent à' malloc' ou avec un pointeur non initialisé. Bonne chance pour le trouver. –

+0

Même si le code est commenté, je rappellerai que 'enqueue' est vraiment faux: il enregistre l'adresse d'une variable * local * (qui ne devrait même pas compiler), et n'initialise pas les membres de 'Node'. En outre, ajouter quelque chose à une queue implique généralement d'ajouter à la queue, pas à l'élément après la tête. – jamesdlin

+0

* Toujours * vérifier le résultat de 'malloc'! Vous pouvez utiliser un wrapper pour cela (recherchez [xmalloc] (http://gcc.gnu.org/onlinedocs/libiberty/Functions.html#index-xmalloc-202) sur Internet). S'il s'agit d'un devoir, ajoutez le tag * homework * à la question. –

Répondre

10

La ligne suivante est sans doute en vous donnant du chagrin:

Node newNode = malloc(sizeof(Node)); 

Node est un type de pointeur, de sorte que vous êtes seulement allouer suffisamment d'espace pour contenir un pointeur, pas un NodeStruct entier. Je pense que ce que vous voulez faire est:

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

ou

Node newNode = malloc(sizeof(NodeStruct)); 

Le même problème existe pour Queue, vous êtes seulement l'espace alloué pour tenir un pointeur, pas un QueueStruct. Quelque chose d'autre que je viens de remarquer, c'est que dans votre NodeStruct et QueueStruct, vous utilisez le type Node*, qui est en fait NodeStruct **, ce qui n'est probablement pas ce que vous voulez, puisque Node est déjà un pointeur.

+5

Ceci est un parfait exemple de pourquoi il est souvent considéré comme un mauvais style de cacher un pointeur dans un 'typedef'. – caf

+1

@caf: il aurait également pu utiliser la fameuse [notation hongroise] (http://www.joelonsoftware.com/articles/Wrong.html) correctement, par ex. 'Node' et' pNode'. Cela lui aurait sauvé beaucoup d'ennuis. –

5

vous avez saccagé votre tas

si vous êtes sur la clôture électrique d'utilisation de Linux ou valgrind pour savoir où vous êtes allé mal

modifier: Vous voulez dire

Queue q = malloc(sizeof(QueueStruct)); 

et même pour le noeud

Node n = malloc(sizeof(NodeStruct)); 

et je suis d'accord avec d'autres - ses très trompeuse d'appeler un pointeur vers un nœud NodeStruct. Mieux vaut l'appeler NodePtr ou PNode et appeler le noeud struct.

+0

-1, le problème est plus fondamental que cela, comme l'ont noté dreamlax et caf. –

+0

non ce n'est pas - le nom est trompeur, mais le correctif est le même – pm100

+0

Assez juste. Si vous mentionnez que le même problème existe pour 'Node' et' NodeStruct', et expliquez pourquoi (rappelez-vous que l'OP vient de Java), je vais changer en +1. –

8

Il est souvent considéré comme un mauvais style dans C pour masquer un pointeur dans un typedef. C'est parce que besoin pour savoir que quelque chose est un pointeur pour l'utiliser correctement, de toute façon. (Par exemple, même le type opaque FILE dans la bibliothèque standard est utilisé et transmis comme FILE *).

Cela semble vous avoir égaré - par exemple, vos membres next et prev sont en fait des pointeurs vers des pointeurs, ce qui n'est pas vraiment ce que vous voulez. Je suggère:

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

Impossible d'accepter plus de 1 réponse, mais +1 – Aillyn