简体   繁体   中英

C Program Segmentation Fault

I am having difficulty locating a segmentation fault in a bit of code for a class project (this portion is ungraded). I am implementing a queue for an OS class and am having trouble with a segmentation fault in the add function.

void AddQueue(QElem * head, QElem * item) {
    printf("WHERE\n");
    if(head == NULL){
        printf("THE\n");
        head = item;
        //item->next = item;
        //item->prev = item;
    }
    else{
        printf("$^&*\n");
        (head->prev)->next = item;
        printf("ARE\n");
        item->prev = (head->prev);
        printf("YOU\n");
        item->next = head;
        printf("FAILING\n");
        head->prev = item;
    }
    printf("!?!?!?\n");
}

I have a Test function which I am calling from a different class...

void TestAddQueue()
{
    printf("********************************************\n");
    printf("Begin testing the add test function\n");
    printf("********************************************\n");

    QElem * queue;
    InitQueue(queue);


    for(int i = 0; i < 10; i++)
    {
        printf("Adding element %d\n", i+1);
        QElem * newElem = NewItem();
        printf("Changing payload value\n");
        newElem->payload = i+100;
        printf("Adding to the queue\n");
        AddQueue(queue, newElem);
        printf("Item added, payload value = %d\n", queue->payload);
        printf("The previous payload = %d\n", queue->prev->payload);

    }
    for(int i = 0; i < 10; i++)
    {
        printf("Rotating list", i+1);
        RotateQ(queue);
        printf("Printing element %d\n", i+1);
        printQElem(queue);
    }
}

Here is the NewItem function...

QElem * NewItem()
{
    // just return a new QElem struct pointer on the heap
    QElem * newItem = calloc(1,sizeof(QElem));
    newItem->next = newItem;
    newItem->prev = newItem;
    newItem->payload = -1;
    return newItem;
}

...and here is the output of running the program...

********************************************
Begin testing the add test function
********************************************
Adding element 1
Changing payload value
Adding to the queue
WHERE
THE
!?!?!?
Segmentation fault

Now the head pointer which is passed into the add function should be NULL as it sent to an initializer function which just sets the value of the pointer to NULL, so I dont think this would cause my problem.

My guess is that following line is the one causing the issue...

printf("Item added, payload value = %d\n", queue->payload);

Probably when I attempt to get the payload value, either the struct I am attempting to access doesn't exist anymore or somehow the queue pointer got moved to an invalid space. Any feedback or nudges in the right direction would be appreciated.

Side Note: This is being compiled in a Unix server environment (bash) and at the moment I do not have access to an IDE to debug and view variables.

In C arguments are passed by value , meaning they are copied . And changing a copy does of course not change the original.

So in the AddQueue function, the variable head is a copy that you can change as much as you want, the variable you originally passed to the function will not change at all.

To be able to change arguments you need pass by reference , which C doesn't have, but it can be emulated by using pointers. That of course means that to pass a pointer by reference, you must pass a pointer to the pointer.


So for your code it would be like

void AddQueue(QElem ** head, QElem * item) {
    if(*head == NULL){
        *head = item;
    }
    ...
}

...

AddQueue(&queue, newElem);

What the above changes do is first to make AddQueue take a pointer to a pointer to QElem , thereby making it emulate the pass-by-reference idiom. To use the original pointer you use the dereference operator * which gives you the value pointed to by a pointer (in this case the original pointer). Then to actually pass a pointer to a pointer, you have to use the address-of operator & on the pointer variable.

head = item does not have any effect on what goes on outside the AddQueue function. If you pass a null pointer as head to AddQueue , that pointer will still be null after AddQueue completed.

Thanks to @Joachim i was able to get my queue running as intended. See below the refactored code.

First the add function...

////////////////////////////////////////////////////////////////////////////////
//
//  Add Queue
//
//      Adds a queue item, pointed to by `item`, to the end of the queue pointed
//      to by `head`.
//
//      Note: Tested 2-12-2015 using proj_1.c tests. PASSED -Dave
//
////////////////////////////////////////////////////////////////////////////////
int AddQueue(QElem ** head, QElem ** item) {

    //If the queue is empty...
    if(*head == NULL){
        //Point the head to the item.  The new item's next/prev were initialized
        //to point to itself already.
        *head = *item;
    }
    //If there are already elements in the queue...
    else{
        // insert the new element at the end of the list (just to the left
        // of the head) setting the next and previous values of the
        // appropriate nodes to the new values.
        ((*head)->prev)->next = *item;
        (*item)->prev = ((*head)->prev);
        (*item)->next = *head;
        (*head)->prev = *item;
    }
    return TRUE;
}

Next the new item function...

////////////////////////////////////////////////////////////////////////////////
//
//  New Item
//
//      Returns a pointer to a new queue element created in heap memory.
//
//      Note: Calloc is a more precise way of allocating, but is basically the
//      same as malloc, the 1 denotes how many of the item to reserve mem for.
//      -Dave
//
//      Note: Tested 2-12-2015 using proj_1.c tests. PASSED -Dave
//
////////////////////////////////////////////////////////////////////////////////
QElem * NewItem()
{
    // just return a new QElem struct pointer on the heap with values initialized
    QElem * newItem = calloc(1,sizeof(QElem));
    newItem->next = newItem;
    newItem->prev = newItem;
    newItem->payload = -1;
    return newItem;
}

And now for the test add function...

////////////////////////////////////////////////////////////////////////////////
//
//  A test function for the add function.  It will create a queue of items
//  and attempt to iterate through them and print the value of the payload
//
////////////////////////////////////////////////////////////////////////////////
void TestAddQueue(QElem ** queue){
    printf("********************************************\n");
    printf("Begin testing the add test function\n");
    printf("********************************************\n");

    InitQueue(&(*queue));

    for(int i = 0; i < 10; i++)
    {
        printf("Adding element %d\n", i+1);
        QElem * newElem = NewItem();
        printf("Changing payload value\n");
        newElem->payload = i+100;
        printf("Adding to the queue\n");
        AddQueue(&(*queue), &newElem);
        printf("Item added, payload value = %d\n", newElem->payload);
        printf("The previous payload = %d\n", (*queue)->prev->prev->payload);

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM