简体   繁体   English

C程序分段错误

[英]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. 我正在为OS类实现队列,并且在add函数中遇到段错误。

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... 我有一个Test函数,我正在从另一个类中调用...

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... 这是NewItem函数...

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. 现在,传递给add函数的头指针应该为NULL,因为它发送给初始化函数,该函数只将指针的值设置为NULL,所以我认为这不会引起我的问​​题。

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. 旁注:这是在Unix服务器环境(bash)中编译的,目前,我无权访问IDE来调试和查看变量。

In C arguments are passed by value , meaning they are copied . 在C语言中,参数按值传递,这意味着它们已被复制 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. 因此,在AddQueue函数中,变量head是一个副本 ,您可以根据需要进行任意更改,您最初传递给该函数的变量将完全不会更改。

To be able to change arguments you need pass by reference , which C doesn't have, but it can be emulated by using pointers. 为了能够更改参数,您需要按引用传递 ,C没有该引用 ,但是可以使用指针对其进行仿真。 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. 什么上述变化做的是首先使AddQueue采取指针的指针QElem ,从而模拟传递通过引用成语。 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. head = itemAddQueue函数外部的AddQueue没有任何影响。 If you pass a null pointer as head to AddQueue , that pointer will still be null after AddQueue completed. 如果将空指针作为head传递给AddQueue ,则在AddQueue完成后,该指针仍将为null。

Thanks to @Joachim i was able to get my queue running as intended. 感谢@Joachim,我得以按预期运行队列。 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);

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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