1

我想了解为什么我在下面的代码的指定行(出现于:<<<SEGFAULT OCCURS HERE)中获得段错误。我从this post获得了很多灵感。试图了解此分段错误

我认为这是一个内存分配问题,但考虑到即使我将一个Event实例的指针传递给enqueue函数,它仍然存在段错误。考虑到C是按值传递的,即使当我将main中的事件地址(&event未显示在此处的代码中)传递给enqueue函数时,它应该指向存在于main中的事件实例的地址,对不对?所以我很难理解为什么发生分段错误。

请注意我正在寻找更多的原因为什么这是发生的,而不仅仅是一个问题的解决。毕竟,我正在努力提升C语言。 :)

相关的代码:

typedef struct Event_ Event; 
struct Event_ { 
    char action[4]; 
    long timestamp; 
    char* path; 
    char hash[9]; 
    Event *nextEvent; // pointer to next Event instance in Queue 
};  

    // Enqueues newEvent into queue. Returns 1 on success, 0 otherwise. 
int enqueue(Event newEvent, Event **head, Event **tail) { 
    if (head != NULL) { 
     // make the old head point to the newly inserted Event, 
     // and the new Event to point to NULL (nothing comes before head): 
     (*head) -> nextEvent = &newEvent; 
     newEvent.nextEvent = NULL; 
    } else { 
     // first element being added to queue. 
     *tail = &newEvent; //<<<SEGFAULT OCCURS HERE 
    } 
    // designate the new Event as the new head: 
    *head = &newEvent; 

    return 1; 
} 

// Parse line and return an Event struct. 
Event parseLineIntoEvent(char* line) { 
    Event event = {0}; 
    char* lineSegment; 

    int i = 0; 
    lineSegment = strtok(line, " "); 
    while (lineSegment != NULL) { 
     if (i > 3) { 
      printf("WARNING: input format error!\n"); 
      break; 
     } 
     if (i == 0) 
      strncpy(event.action, lineSegment, sizeof(event.action)-1); 
     else if(i == 1) 
      event.timestamp = atoi(lineSegment); 
     else if(i == 2) { 
      event.path = malloc(sizeof(char) * (strlen(lineSegment) + 1)); 
      strcpy(event.path, lineSegment); 
     } else if(i == 3) 
      strncpy(event.hash, lineSegment, sizeof(event.hash)-1); 
     lineSegment = strtok(NULL, " "); 
     i++; 
    } // while 
    return event; 
} // parseLineIntoEvent() 

int main (int argc, const char * argv[]) { 
    //... 
    Event **head = NULL; 
    Event **tail = NULL; 
    for (; numLines > 0; numLines--) { 
     char *line = getLineFromStdin(); //malloced char array being returned 
     printf("%s\n",line); 
     Event event = parseLineIntoEvent(line); 
     if(!enqueue(event, head, tail)) 
      printf("An error occurred when attempting to enqueue an Event.\n"); 
     event = dequeue(head, tail); 
     //... 
     free(event.path); 
     free(line); 
    } 

    return 0; 
} 

提前感谢!

+0

'enqueue'函数被打破。您通过值传递'newEvent',这不会修改您传递的事件。 – pmr 2012-01-17 23:39:27

回答

3
Event **tail = NULL; 

tailNULL,和你提领它在你标记的代码行。它需要做出指向一个Event*之前,你可以取消对它的引用:

要么

Event *ev; 
Event **tail = &ev; 

或者

Event** tail = malloc(sizeof(Event*)); 

... 

free(tail); 

虽然,我觉得你的意思是刚才的指针Event ,并按值传递其地址:

Event *tail = NULL, *head = NULL; 

... 

enqueue(event, &head, &tail); 

因此,0123在enqueue内修改了和tail

+1

问题标有'C';所以'新'是不合适的。 – Dave 2012-01-17 23:44:01

+0

@Dave抱歉,我总是忘记我是哪个标签。对于这样的愚蠢错误,请随时编辑我的答案。 – 2012-01-18 00:25:20

0

您正在取消引用空指针。

int main (int argc, const char * argv[]) { 
    //... 
    Event **head = NULL; 
    Event **tail = NULL; 
    for (; numLines > 0; numLines--) { 
     //... 
     if(!enqueue(event, head, tail)) // head and tail are NULL here 
     //... 
    } 
} 

int enqueue(Event newEvent, Event **head, Event **tail) { 
    if (head != NULL) { // head is NULL, else path will be executed 
     //... 
    } else { 
     // first element being added to queue. 
     *tail = &newEvent; //<<<SEGFAULT OCCURS HERE because tail is null. 
    } 
} 
0

你的代码包含至少两个错误:

  1. 正如其他人你传递一个NULL指针尾巴和非关联化将导致段错误
  2. 您在newEvent按值传递指出。这意味着结构的副本将被制作并放入堆栈。在函数内部,你可以执行*head = &newEvent,它接收堆栈中的对象地址并将其放入队列中。从入队函数返回后,堆栈将被清理,并指向垃圾。您需要将eneueue更改为int enqueue(Event *newEvent, Event **head, Event **tail)并传递指向该事件的指针。

我不知道为什么你使用指针的指针,也是你的队列中显得语义破(头通常是开始和enqueue通常在年底追加的东西)

int enqueue(Event *event, Event **head, Event **tail) 
{ 
    if (*head != NULL) 
    { 
     // we do have a head: point next to current head 
     event->nextEvent = *head; 
    } 
    else 
    { 
     // no head so we also should have no tail 
     *tail = event; 
     event->nextEvent = NULL; 
    } 

    // newly enqueued event is now head 
    *head = event; 

    return 1; 
} 

使用它:

Event *head = NULL; 
Event *tail = NULL; 

... 

Event newEvent = parseLineIntoEvent(char* line); 
enqueue(&newEvent, &head, &tail); 

虽然你应该考虑把newEvent堆上通过返回从parseLineIntoEventEvent *(使用malloc到异体为它记忆内存)