0

文字列 (char ポインター) を要素として受け取るキュー構造体を C で作成しています。私が抱えている問題は、要素の値を一度出力した後、後で null になることです。

以下のコードでは、次の出力が期待されます。

1 Hello
1 Hello
2 World
Hello World
1

しかし、私はこの出力を得ています:

1 Hello
1 (null)
2 World
(null) (null)
1

誰かが私が間違っていることを教えてくれますか?

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

struct Node {
    struct Node *next;
    char* element; 
};
struct Queue {
    int size;
    struct Node *head;
    struct Node *tail;

};

void Enqueue(struct Queue *q, char* str) {
    struct Node newNode = {0,str};
    if(q->size == 0) {
        q->head = &newNode;
    }
    else {
        q->tail->next = &newNode;   
    }
    q->tail = &newNode;
    q->size = q->size + 1;
}
char* Dequeue(struct Queue *q) {
    if(q->size < 0) {   
        return -1;
    }
    char* tbr = q->head->element;
    struct Node* oldNode = q->head;
    q->head = oldNode->next;
    q->size = q->size - 1;
    if(q->size == 0) {
        q->tail = NULL;
    }
    return tbr;
}
int IsEmpty(struct Queue *q) {
    return q->size == 0;
}
char* Peek(struct Queue *q) {
    return q->head->element;
}
int main() {
    struct Queue q = {0};
    Enqueue(&q,"Hello");
    printf("%d %s\n",q.size,q.head->element);
    printf("%d %s\n",q.size,q.head->element);
    Enqueue(&q,"World");
    printf("%d %s\n",q.size,q.head->next->element);
    printf("%s %s\n",Dequeue(&q),Dequeue(&q));
    printf("%d\n",IsEmpty(&q));
    printf("%s %s\n","Hello","World");
    Dequeue(&q);
    return 0;
}
4

2 に答える 2

1

内部Enqueueでは、ローカル変数を使用して新しいノードをキューに挿入することはできません。これは、関数の有効期間外でローカル変数を使用することになり、関数が戻った後にローカル変数が破棄されるためです。

したがって、 から戻るとEnqueue、挿入された要素 ( newNode) は、別の関数を呼び出したときに上書きされる可能性が高い無効なメモリ位置を指しています。すべての賭けはオフです。ノードをより長く存続させたい場合は、動的割り当てを使用する必要があります。

void Enqueue(struct Queue *q, char* str) {
    struct Node *newNode = malloc(sizeof(struct Node));
    newNode->next = NULL;
    newNode->element = str;
    if(q->size == 0) {
        q->head = newNode;
    }
    else {
        q->tail->next = newNode;   
    }
    q->tail = newNode;
    q->size = q->size + 1;
}

freeまた、ノードをデキューするときにノードが必要になることに注意してください。Dequeueになります:

char* Dequeue(struct Queue *q) {
    if(q->size < 0) {   
        return -1;
    }
    char* tbr = q->head->element;
    struct Node* oldNode = q->head;
    q->head = oldNode->next;
    q->size = q->size - 1;
    if(q->size == 0) {
        q->tail = NULL;
    }
    free(oldNode);
    return tbr;
}

内部mainでは、キューが空であるため、 finalDequeueによってセグメンテーション違反が発生し、 ではこのケースをチェックしませんDequeueDequeuewhen が true を返すときに呼び出さないかIsEmpty、 でこのケースをチェックするコードを追加しますDequeue

最後のメモ: のmainこの行:

printf("%s %s\n",Dequeue(&q),Dequeue(&q));

Hello World引数の評価順序は実装定義であるため、必ずしも print とは限りません。たとえば、私のマシンでは、印刷されWorld Helloます。

于 2013-11-02T09:33:49.903 に答える
1

Enqueue()ローカルでのみ有効なスタック上のメモリへの参照を挿入します。

void Enqueue(struct Queue *q, char* str) {
  struct Node newNode = {0,str}; 

関数が戻るとすぐに、このストレージが解放され、アクセスすると未定義の動作が引き起こされます。

これを解決するには、ヒープからメモリを動的に割り当てます。

void Enqueue(struct Queue *q, char* str) {
  struct Node * pnewNode = calloc(1, sizeof(*pnewNode);
  if (NULL == pnewNode)
  {
    perror("calloc() failed");
    exit(EXIT_FAILURE);
  } 

  pnewNode->element = str;

  if(q->size == 0) {
    q->head = pnewNode;
  }
  else {
    q->tail->next = pnewNode;   
  }
  q->tail = pnewNode;
  q->size = q->size + 1;
}

free()動的に割り当てられたメモリを編集する必要があることに注意してください。

于 2013-11-02T09:29:55.590 に答える