首页 > 解决方案 > 列表插入中 strcmp 的分段错误

问题描述

我正在尝试按字母顺序创建一个列表(首先按作者,然后按名称)。我试图通过比较两个字符串来做到这一点,strcmp()但我遇到了分段错误。

我将把 GDB 运行结果和函数留在这里,它是我使用列表制作的第一个程序之一,因此代码可能还有其他错误。

GDB 运行:

Program received signal SIGSEGV, Segmentation fault.                         
0x0000000000400c65 in insert (lPtr=0x7fffffffeb38, isbn_i=978044,            
    name_i=0x7fffffffeb40 "Suzanne Collins",                                 
    author_i=0x7fffffffeb80 "The Hunger Games") at main.c:178                
178             while(strcmp(author_i, currPtr->author) < 0){
typedef struct library{ //struct insertion from stdin
    int isbn;
    char *author;
    char *name;
    int act; //actual books in memory
    int tot; //total books
    struct library *nextPtr; //node
}Lib;

typedef Lib *NodePtr;


//called by a while, receives input from integers and two arrays of char

void insert(NodePtr *lPtr, int isbn_i, char *name_i, char *author_i){  

    NodePtr newPtr = malloc(sizeof(Lib));

    newPtr->isbn = isbn_i;  //scanf insertion in node
    newPtr->author = author_i;
    newPtr->name = name_i;

    newPtr->nextPtr = NULL;
    NodePtr prevPtr = NULL;

    newPtr->act = 1;
    newPtr->tot = 1;

    if(lPtr == NULL){ //empty list
        *lPtr = newPtr;
        return;
    }

    NodePtr currPtr = *lPtr;

    while(strcmp(author_i, currPtr->author) < 0){ //author is different, list slides    
        prevPtr = currPtr;
        currPtr = currPtr->nextPtr;
    }

    if(strcmp(author_i, currPtr->author)== 0){ //same author

        while(strcmp(name_i, currPtr->name) < 0){ //list sliding
            prevPtr = currPtr;
            currPtr = currPtr->nextPtr;
        }

        if(strcmp(name_i, currPtr->name) == 0){ 
            currPtr->act += 1; //updates current counter and returns (to avoid duplicates)
            currPtr->tot += 1;

            free(newPtr);
            return;
        }
    }

    prevPtr->nextPtr = newPtr; //insertion between two nodes
    newPtr->nextPtr = currPtr;
}


标签: cstringlinked-listsegmentation-faultstrcmp

解决方案


在以下代码中:

    while(strcmp(author_i, currPtr->author) < 0){ //author is different, list slides    
        prevPtr = currPtr;
        currPtr = currPtr->nextPtr;
    }

如果您的列表作者仅包含应在您到达末尾而没有找到插入位置的位置排序的作者,则您不检查是否currPtr->nextPtrNULL(在列表的末尾) 。
author_i

示例(为简单起见,省略了无关字段):

currPtr = {author:"Cressida Cowell", nextPtr=NULL};
insert(lPtr = &currPtr, ...,author_i = "Suzanne Collins", ...);
/// insertion location loop
// while loop unrolled
if("Suzanne Collins" > "Cressida Cowell") {
     prevPtr = currPtr ; // prevPtr = {author:"Cressida Cowell", nextPtr=NULL};
     currPtr = currPtr->nextPtr; // currPtr  = NULL
}
// next iteration
if("Suzanne Collins"> NULL->author ) // de-referencing a NULL pointer, causing a Segmentation fault

您可以通过以下修复部分修复代码:

    while(strcmp(author_i, currPtr->author) < 0){ //author is different, list slides    
        prevPtr = currPtr;
        currPtr = currPtr->nextPtr;
        if(currPtr == NULL) {break;} // exit loop if at end of the list
    }

您仍然需要处理currPtr == NULL以避免在currPtr检查标题时取消引用 NULL 指针,我的建议是结合插入位置搜索循环中的条件。

    // implement a node comparison function
    int compareLib(NodePtr lib1, NodePtr lib2) {
        if((lib1 == NULL)||(lib2 == NULL)) return 0;
        int author_compare = strcmp(lib1->author, lib2->author);
        if (author_compare != 0) return author_compare;
        return strcmp(lib1->name, lib2->name);
    }
    ...
    while(compareLib(newPtr, currPtr)){ 
        prevPtr = currPtr;
        currPtr = currPtr->nextPtr;
        if(currPtr == NULL) {break;} // exit loop if at end of the list
    }

currPtr == NULL添加新列表节点时仍然需要处理


推荐阅读