programing

display()가 C의 링크 리스트를 사용하여 큐에 세그멘테이션에러를 발생시키는 이유

yoursource 2022. 12. 1. 23:37
반응형

display()가 C의 링크 리스트를 사용하여 큐에 세그멘테이션에러를 발생시키는 이유

다음으로 링크 리스트를 사용한 큐의 실장을 나타냅니다.

에서main()기능.dequeue()의 이름을 따서 부른다.enqueue(2)세그먼트 에러가 발생합니다.
단, 만약dequeue()의 이름을 따서 부른다.enqueue(5)에러가 발생하지 않습니다.

기능.display()에서 1과 2를 인쇄한 후 세그먼트 오류가 발생합니다.temp -> data

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

struct queue
{
    int data;
    struct queue *next;
};
struct queue *QueueNode, *front = NULL, *rear = NULL, *temp;

void enqueue();
void dequeue();
void display();

int main()
{
    enqueue(1);
    enqueue(2);
    dequeue();
    enqueue(3);
    enqueue(4);
    enqueue(5);
    display();

    return 0;
}

void enqueue(int value)
{
    QueueNode = (struct queue *)malloc(sizeof(struct queue));
    QueueNode->data = value;

    if (front == NULL && rear == NULL)
    {
        front = rear = temp = QueueNode;
    }
    else
    {
        temp->next = QueueNode;
        temp = rear = QueueNode;
    }
}

void dequeue()
{
    if (front == NULL && rear == NULL)
    {
        printf("Queue is empty\n");
    }
    else if (front == rear)
    {
        temp = front;
        front = rear = NULL;
        free(temp);
    }
    else
    {
        temp = front;
        front = front->next;
        free(temp);
    }
}

void display()
{
    printf("Displaying queue : \n");
    if (front == NULL && rear == NULL)
    {
        printf("Queue is empty\n");
    }
    else
    {
        temp = front;
        rear->next = NULL;
        while (temp != NULL)
        {
            printf("%d\n", temp->data);
            temp = temp->next;
        }
    }
}

할 필요가 없다QueueNode또는temp함수 외부에 선언됩니다.이러한 변수는 함수에 대해 로컬이어야 합니다.

enqueue질문의 루틴이 설정되지 않는다temp에 사용하기 전에temp->next = QueueNode;. 다른 루틴에 대한 이전 호출에서 생성된 값 또는 상태를 가집니다.언제dequeue이전에 호출되었습니다.enqueue, 이것은 당신의 프로그램에 재앙입니다 왜냐하면dequeue사용하다temp릴리스하고 있는 노드를 가리키면 실행됩니다.free(temp);그럼, 언제?enqueue라고 불리고 있습니다.temp는 불확정 상태입니다.(C 표준에 따르면 포인터가 가리키는 메모리가 해방되면 포인터 자체가 무효가 됩니다.)비록 포인터가 C 추상 모델에서 유효하더라도, 그리고 실제로는 단순한 프로그램에서 포인터는 해방된 메모리를 가리킬 것입니다.하지만 이 시점에서enqueue를 설정합니다.next큐 내의 마지막 노드의 멤버이며,next삭제한 노드의 멤버.이 설정은 실패합니다.next마지막 노드의 멤버입니다.나중에 언제display큐를 통해 반복을 시도하고 초기화되지 않은 큐를 사용하려고 합니다.next큐에 추가된 노드의 멤버.세그먼트 결함으로 이어집니다.

데이터 구조에 노드를 추가할 때는 항상 노드의 모든 멤버를 초기화하십시오(노드의 다른 부분이 현재 사용되지 않음을 나타내는 옵션 값 등 값을 갖지 않는 것이 의미가 있는 멤버는 제외).의 코드enqueue는 표시되지 않습니다.next새 노드의 멤버입니다.여기 작업물이 있습니다.enqueue:

void enqueue(int value)
{
    /*  Use local variable to point to new node.

        Use "sizeof *NewNode" instead of "sizeof (struct queue)" so that we
        always get enough memory for the thing the pointer points to even if
        its type is changed in future code edits.

        In C, do not cast the result of malloc.  It will automatically be
        converted to the type of the pointer being assigned or initialized, and
        casting can conceal certain code errors.
     */
    struct queue *NewNode = malloc(sizeof *NewNode);

    //  Set all members of the new node.
    NewNode->data = value;
    NewNode->next = NULL;

    /*  Something "before" the new node should point to it.  That might be
        a prior node or it might be the front-of-queue pointer.
    */
    if (front)
        rear->next = NewNode;
    else
        front      = NewNode;

    //  Update the rear-of-queue pointer.
    rear = NewNode;

    /*  Observe that this routine, excepting comments, is shorter and simpler
        than the original enqueue.
    */
}

개선도 할 수 있습니다.dequeue그리고.display를 삭제합니다.QueueNode그리고.temp변수:

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


struct queue
{
    int data;
    struct queue *next;
};


struct queue *front = NULL, *rear = NULL;


void enqueue();
void dequeue();
void display();


int main(void)
{
    enqueue(1);
    enqueue(2);
    dequeue();
    enqueue(3);
    enqueue(4);
    enqueue(5);
    display();

    return 0;
}


void enqueue(int value)
{
    /*  Use local variable to point to new node.

        Use "sizeof *NewNode" instead of "sizeof (struct queue)" so that we
        always get enough memory for the thing the pointer points to even if
        its type is changed in future code edits.

        In C, do not cast the result of malloc.  It will automatically be
        converted to the type of the pointer being assigned or initialized, and
        casting can conceal certain code errors.
     */
    struct queue *NewNode = malloc(sizeof *NewNode);

    //  Set all members of the new node.
    NewNode->data = value;
    NewNode->next = NULL;

    /*  Something "before" the new node should point to it.  That might be
        a prior node or it might be the front-of-queue pointer.
    */
    if (front)
        rear->next = NewNode;
    else
        front      = NewNode;

    //  Update the rear-of-queue pointer.
    rear = NewNode;

    /*  Observe that this routine, excepting comments, is shorter and simpler
        than the original enqueue.
    */
}


void dequeue()
{
    struct queue *OldNode = front;

    /*  We do not need to check both front and rear.  If there is no front node
        in the queue, it is empty.
    */
    if (!OldNode)
        printf("Queue is empty\n");
    else
    {
        //  Update the front-of-queue pointer.
        front = OldNode->next;

        /*  If there is no node in the queue now, update the rear-of-queue
            pointer.
        */
        if (!front)
            rear = NULL;

        //  Release the node.
        free(OldNode);
    }
}


void display()
{
    printf("Displaying queue: \n");
    if (!front)
        printf("Queue is empty\n");
    else
        /*  Iterate through the queue using a simple for loop:

                Start at the front.

                Continue as long as there is a node.

                After each iteration, proceed to the next node.
        */
        for (struct queue *Node = front; Node; Node = Node->next)
            printf("%d\n", Node->data);
}

조금 「힘들지만」이라고 생각되는 기능의 리비전을 다음에 나타냅니다.

중요한 것은 글로벌 변수가 존재하지 않고(및 여러 큐를 동시에 실행할 수 있는 기회), 단일 구조체의 주소를 파라미터로 "서비스 공급자" 함수에 전달하는 것입니다.

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

// Use typedef to reduce verbiage
typedef struct queue {
    int data;
    struct queue *next; // datatype not yet encountered. Need "struct name"
} queue_t; // Conventional naming using "_t" suffix

// Combine two pointers into one 'object' (Could add counter, if desired)
typedef struct {
    queue_t *head; // use conventional names
    queue_t *tail;
} oneQueue_t;

// for brevity, this trio of functions deliberately omit checking *q != NULL
void enqueue( oneQueue_t *q, int value ) {
    // use calloc for reliable initialisation to nulls
    // it's too easy to add a member and forget to initialize a value
    queue_t *pn = calloc( 1, sizeof *pn );
    if( pn == NULL ) { // ALWAYS test return codes
        // deal with allocation error
        exit( EXIT_FAILURE );
    }
    pn->data = value; // assign known data; the rest is/are NULL'd

    if( q->tail ) // always append to the tail, so test the tail
        q->tail = q->tail->next = pn;
    else
        q->tail = q->head = pn; // first node; assign head too
}

void dequeue( oneQueue_t *q ) {
    if( q->head == NULL ) // report where "soft error" occurred
        printf( "dequeue() -- queue is empty\n" );
    else {
        queue_t *del = q->head; // "del" winks in-and-out of existence
        if( ( q->head = q->head->next ) == NULL ) // last entry??
            q->tail = NULL;
        free( del );
    }
}

void display( oneQueue_t *q ) { // simple traversal
    printf( "Displaying queue...\n" );
    for( queue_t *pn = q->head; pn; pn = pn->next )
        printf( "%d\n", pn->data );
    printf( "End of Queue\n" );
}

// put code for "service functions" ahead of invocations
// definition is then the "func prototype". less maintenance
int main() {
    oneQueue_t q = { NULL, NULL }; // one initialised queue. could have multiple

    dequeue( &q ); // test "illicit" operation
    display( &q ); // test with empty queue
    enqueue( &q, 1 );
    enqueue( &q, 2 );
    display( &q ); // test with two items
    dequeue( &q );
    enqueue( &q, 3 );
    enqueue( &q, 4 );
    enqueue( &q, 5 );
    display( &q ); // penultimate test

    while( q.head ) // memory leaks are bad
        dequeue( &q );

    display( &q ); // final test
    dequeue( &q ); // test "illicit" operation

    return 0;
}

산출량

dequeue() -- queue is empty
Displaying queue...
End of Queue
Displaying queue...
1
2
End of Queue
Displaying queue...
2
3
4
5
End of Queue
Displaying queue...
End of Queue
dequeue() -- queue is empty

main()여러분들을 긴장시키고 있습니다. 여기 그 본문이 있습니다.main()체면을 위해 여분의 포인터를 사용합니다.

{
    oneQueue_t q = { NULL, NULL }, *qp = &q; // one initialised queue. could have multiple

    dequeue( qp ); // test "illicit" operation
    display( qp ); // test with empty queue
    enqueue( qp, 1 );
    enqueue( qp, 2 );
    display( qp ); // test with two items
    dequeue( qp );
    enqueue( qp, 3 );
    enqueue( qp, 4 );
    enqueue( qp, 5 );
    display( qp ); // penultimate test

    while( qp->head ) // memory leaks are bad
        dequeue( qp );

    display( qp ); // final test
    dequeue( qp ); // test "illicit" operation

    return 0;
}

언급URL : https://stackoverflow.com/questions/73594522/why-display-is-throwing-a-segmentation-error-in-a-queue-using-a-linked-list-in

반응형