2015-02-12 5 views
1

У меня возникли трудности с обнаружением ошибки сегментации в бит кода для проекта класса (эта часть неклассифицирована). Я реализую очередь для класса ОС, и у меня возникают проблемы с ошибкой сегментации в функции добавления.C Ошибка сегментации программы

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

У меня есть функция тест, который я звоню из другого класса ...

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

Вот функция 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; 
} 

... и здесь является результатом работы программы ...

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

Теперь указатель на голову, который передается в функцию добавления, должен быть NULL, поскольку он отправляется в функцию инициализатора, которая просто устанавливает значение указателя в NULL, поэтому я не думаю, что это вызовет мою проблему.

Я думаю, что следующая строка является один вызывает вопрос ...

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

Вероятно, когда я пытаюсь получить значение полезной нагрузки, либо структура Я пытаюсь получить доступ, не существует больше или так как указатель очереди был перемещен в недопустимое пространство. Любая оценка или подталкивание в правильном направлении были бы оценены.

Боковое примечание: это компилируется в среде Unix-сервера (bash), и на данный момент у меня нет доступа к среде IDE для отладки и просмотра переменных.

+0

Там много кода отсутствует в вашем примере; например, NewItem(). Тем не менее, я говорю: посмотрите на строку «(head-> prev) -> next» в AddItem: вы проверили, что «голова» не является NULL, но не проверила, что «head-> prev» - NULL – haavee

ответ

2

В аргументах C передаются по значению, то есть они скопированы. И изменение копии, конечно, не изменяет оригинал.

Таким образом, в функции AddQueue, переменная head является копия, что вы можете изменить столько, сколько вы хотите, переменная вы изначально передается функции не изменится.

Для того, чтобы изменить аргументы, необходимые , перейдите по ссылке, которой нет C, но его можно эмулировать с помощью указателей. Это, конечно, означает, что для передачи указателя по ссылке вы должны передать указатель на указатель.


Так что для вашего кода было бы как

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

... 

AddQueue(&queue, newElem); 

Что вышеуказанные изменения сделать первый, чтобы сделать AddQueue взять указатель на указатель на QElem, тем самым делая его эмулировать проход в каждом конкретном справочная идиома. Чтобы использовать исходный указатель, вы используете оператор разыменования *, который дает вам значение, указанное указателем (в данном случае исходным указателем). Затем, чтобы фактически передать указатель на указатель, вы должны использовать адрес-оператора & в переменной указателя.

+0

Спасибо @ Joachim благодарю вас за информацию и примеры. Мне потребовалось немного усилий и повторного факторинга, но я смог заставить мой код работать по назначению. Я также нашел этот отличный сайт [link] (http://c.learncodethehardway.org/book/). Я добавлю рефакторизованный код, который работает на мой ответ. Еще раз спасибо, привет! – Dave0

0

head = item не влияет на то, что происходит за пределами функции AddQueue.Если вы передадите нулевой указатель как head в AddQueue, этот указатель будет по-прежнему иметь значение null после завершения AddQueue.

0

Благодаря @Joachim я смог запустить свою очередь, как и предполагалось. См. Ниже реорганизованный код.

Первая функция добавить ...

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

Следующая новая функция товар ...

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

А теперь для теста добавить функцию ...

//////////////////////////////////////////////////////////////////////////////// 
// 
// 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); 

    } 
} 
Смежные вопросы