C 程序段错误
C Program Segmentation Fault
我很难在 class 项目的一段代码中找到分段错误(这部分未分级)。我正在为 OS class 实现队列,但在添加函数中遇到分段错误问题。
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");
}
我有一个测试函数,我从另一个 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);
}
}
这是 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
现在传递给 add 函数的头指针应该是 NULL,因为它被发送到一个初始化函数,该函数只是将指针的值设置为 NULL,所以我认为这不会导致我的问题。
我的猜测是下一行是导致问题的原因...
printf("Item added, payload value = %d\n", queue->payload);
可能当我尝试获取负载值时,我尝试访问的结构不再存在,或者队列指针以某种方式移动到无效 space。任何正确方向的反馈或推动将不胜感激。
旁注:这是在 Unix 服务器环境 (bash) 中编译的,目前我无法访问 IDE 来调试和查看变量。
在 C 中,参数通过 按值 传递,这意味着它们是 复制的 。更改副本当然不会更改原始文件。
所以在AddQueue
函数中,变量head
是一个copy,你想怎么改就怎么改,你原来传的那个变量到函数根本不会改变。
为了能够更改参数,您需要按引用传递,C 没有,但可以使用指针来模拟。那当然意味着要通过引用传递一个指针,你必须传递一个指向该指针的指针。
所以对于你的代码来说,它就像
void AddQueue(QElem ** head, QElem * item) {
if(*head == NULL){
*head = item;
}
...
}
...
AddQueue(&queue, newElem);
上面所做的更改首先是使 AddQueue
接受指向 QElem
的指针,从而使其模拟引用传递习惯用法。要使用原始指针,您可以使用取消引用运算符 *
,它会为您提供指针指向的值(在本例中为原始指针)。然后要实际将指针传递给指针,您必须在指针变量上使用寻址运算符 &
。
head = item
对 AddQueue
函数之外发生的事情没有任何影响。如果将空指针作为 head
传递给 AddQueue
,该指针在 AddQueue
完成后仍将为空。
多亏了@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);
}
}
我很难在 class 项目的一段代码中找到分段错误(这部分未分级)。我正在为 OS class 实现队列,但在添加函数中遇到分段错误问题。
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");
}
我有一个测试函数,我从另一个 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);
}
}
这是 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
现在传递给 add 函数的头指针应该是 NULL,因为它被发送到一个初始化函数,该函数只是将指针的值设置为 NULL,所以我认为这不会导致我的问题。
我的猜测是下一行是导致问题的原因...
printf("Item added, payload value = %d\n", queue->payload);
可能当我尝试获取负载值时,我尝试访问的结构不再存在,或者队列指针以某种方式移动到无效 space。任何正确方向的反馈或推动将不胜感激。
旁注:这是在 Unix 服务器环境 (bash) 中编译的,目前我无法访问 IDE 来调试和查看变量。
在 C 中,参数通过 按值 传递,这意味着它们是 复制的 。更改副本当然不会更改原始文件。
所以在AddQueue
函数中,变量head
是一个copy,你想怎么改就怎么改,你原来传的那个变量到函数根本不会改变。
为了能够更改参数,您需要按引用传递,C 没有,但可以使用指针来模拟。那当然意味着要通过引用传递一个指针,你必须传递一个指向该指针的指针。
所以对于你的代码来说,它就像
void AddQueue(QElem ** head, QElem * item) {
if(*head == NULL){
*head = item;
}
...
}
...
AddQueue(&queue, newElem);
上面所做的更改首先是使 AddQueue
接受指向 QElem
的指针,从而使其模拟引用传递习惯用法。要使用原始指针,您可以使用取消引用运算符 *
,它会为您提供指针指向的值(在本例中为原始指针)。然后要实际将指针传递给指针,您必须在指针变量上使用寻址运算符 &
。
head = item
对 AddQueue
函数之外发生的事情没有任何影响。如果将空指针作为 head
传递给 AddQueue
,该指针在 AddQueue
完成后仍将为空。
多亏了@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);
}
}