【问题标题】:Can't determine cause of segmentation fault无法确定分段错误的原因
【发布时间】:2017-04-24 18:46:28
【问题描述】:

我的程序的一部分是错误的,导致分段错误。所以我想出了一个程序,它可以读取大量关于学生记录的数据,比如 ID,以及他们相应的成绩和学分。此数据存储在文本文件中。然后,在读入数据时,我的程序会创建一个学生记录的链接列表,按唯一 ID 排序。由于该学生的ID可能在文本文件中再次重复,所以我创建了一个搜索重复的函数,该函数在某处不正确,导致分段错误。这是函数:

struct SR *findDuplicate ( struct SR *head, int ID )
    {
        struct SR *temp = NULL;
        temp = malloc ( sizeof ( head ) );
        temp = head;
        while ( temp->ID != ID )
        {
            if ( temp->next != NULL )
            {
                temp = temp->next;
            }
            else 
            return NULL;
        }
        return temp;
    }

所以当我运行调试器时,它会返回以下错误消息:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400deb in findDuplicate (head=0x7fffffffe540, ID=5304) at HW7.c:101
101                     while ( temp->ID != ID )

我不知道 while 循环出了什么问题。在程序中的某个地方,我将 head.ID 初始化为 -1(因为文本文件中学生的 ID 永远不会是负数)并且 head.next 为 NULL。我无法弄清楚这段代码的逻辑有什么问题。

编辑 1:我已经像这样初始化了 head(在 main 中):

struct SR head;

    head.ID = -1;
    head.next = NULL;
    head.ID = 0;head.GPA = 0;head.numCredits = 0;head.numCoursesTakenSoFar = 0; 
    head.GPApoints = 0;

这个函数是从另一个从main调用的函数中调用的:

我这样调用这个函数:

ind_1 = findDuplicate ( first, a ); 

ind_1 被声明为指向结构的指针。

调用findDuplicate的函数是processInput函数,所以a是从文本文件中读入学生ID的变量。

编辑 2:从 main 我调用一个名为 processInput 的函数,它的一部分看起来像这样(直到第一次调用 findDuplicate ):

void processInput ( struct SR *first, char str [50] )
{
    char ch;    
    int a, b, x=0;
    struct SR *ind_1;
    FILE *fp;               
    fp = fopen ( str, "r" );
    if ( fp == NULL )
    {       printf("Can't open file\n");            
        exit ( 1 );                                 
    }
    while ( fscanf ( fp, "%d %d %c", &a, &b, &ch ) != EOF )     
    {
        ind_1 = findDuplicate ( first, a );         

在 main 中,processInput 是这样调用的:

processInput ( &head, argv [i+1] );

我希望这是足够的信息。程序真的很长,我不想放太多代码。因此,first是指向head的指针,head的地址是从main传递给processInput的。

【问题讨论】:

  • malloc 电话的意义何在?它所做的只是泄漏内存。您还确定head 指向有效内存吗?
  • 在 main 中,我将 head 声明为一个结构变量,并初始化了它的所有相应成员。应该会解决的,对吧?
  • memcpyheadtemp?为什么要使用malloc?分配的内存大小错误:您选择指针的大小,而不是结构。
  • 函数的前 3 行可以简化为 struct SR *temp = head;(这也将消除您现在的内存泄漏)。所以你需要展示你如何初始化head以及你如何调用函数,错误很可能在那里
  • 调试器告诉你段错误是由评估while谓词引起的。仅当temp 的当前值不是有效指针时才有意义。您提供的代码中没有任何内容可以解释为什么会这样,如果您需要进一步的帮助,请提供minimal reproducible example

标签: c struct segmentation-fault


【解决方案1】:

所以问题可能是这样的。

基本上看 head 只是一个指向某个内存位置的指针。您必须确保 head 指向链表的合法节点。如果 head 为 NULL,则 head->id 或 temp->id 将非法生成核心转储。另请注意, temp 也只是一个指针,您不需要对其进行 malloc。只是简单地将其分配给 head 。 见下文:

struct SR *findDuplicate ( struct SR *head, int ID )
    {
        struct SR *temp = NULL; // Pointer 4 bytes
        
        temp = head; // Assign value(address) of head to temp
        while ( temp && temp->ID != ID ) // Check if temp is NULL first
        {
            if ( temp->next != NULL )
            {
                temp = temp->next;
            }
            else 
            return NULL;
        }
        return temp;
    }

【讨论】:

    【解决方案2】:

    正如其他人评论的那样,您正在从代码中的 malloc 泄漏内存。

    这就是说,按如下方式运行您的示例代码对我来说不会崩溃。为了清楚起见,我认为 findDuplicate 的这种实现并不好(它会泄漏内存,而且过于冗长)。然而,它本身并不是不正确的(尽管内存泄漏):您正在为指针分配空间,设置该指针,然后取消引用该指针。

    #include <stdio.h>
    #include <stdlib.h>
    
    struct SR {
        struct SR *next;
        int ID;
    };
    
    struct SR *findDuplicate ( struct SR *head, int ID )
    {
        struct SR *temp = NULL;
        temp = malloc ( sizeof ( head ) );
        temp = head;
        while ( temp->ID != ID )
        {
            if ( temp->next != NULL )
            {
                temp = temp->next;
            }
            else
                return NULL;
        }
        return temp;
    }
    
    int main(int argc, char **argv)
    {
        struct SR head = { .next = NULL, .ID = -1 };
        struct SR *found = findDuplicate(&head, 42);
        free(found);
        return 0;
    }
    

    因此,我建议问题中的 processInput sn-p 中的 while 循环可能是罪魁祸首。如果 findDuplicate 返回 NULL,我想你正在使用“first”做某事,这可能会破坏列表。

    我认为您可能需要检查程序中的内存处理方法。我不明白为什么 findDuplicate 需要分配内存——如果 findDuplicate 在链表上找不到现有的 ID 条目,我会期望为 struct SR 分配内存。

    如果您发布完整的示例代码并输入数据,这将有助于缩小您的确切问题范围。

    【讨论】:

    • 只有靠着上帝的恩典,以及 Undefined Behavior 的虚假性质,它才不会让您崩溃。让我猜猜……您还没有通过valgrind 或类似的内存错误检查程序运行可执行文件进行检查——是吗?什么作为第一个参数传递给findDuplicate? (提示:一个指针)。 sizeof (head) 是什么? (提示:sizeof (a pointer)sizeof (a pointer) 是否有足够的内存来存储 两个 pointerint? (我会让你回答那个......)
    • @DavidC.Rankin 回答你的最后一个问题:不,sizeof(a pointer) 没有足够的内存来存储指针和 int。在findDuplicate 中,temp 指向sizeof(a pointer) 字节,然后设置为head(同样是一个指针)。然后它被取消引用。所以我看不到UB,只是其他人指出的内存泄漏。我并不是说这个实现很好。我已经从 OP 的帖子中复制了它,以演示它在没有段错误的情况下运行,并作为如何提供完整且有用的代码 sn-p 供其他人尝试的示例。我确实通过 valgrind 运行了我的程序。
    • Chuckling..,汤姆,我很抱歉,我的评论有点生硬,无意冒犯,但我想带你了解显示错误所在的思考过程简洁明了的方式。这就是未定义的行为(就像一盒巧克力)的模糊之处,你永远不知道你会得到什么。这就是为什么它必须受到如此彻底的保护。 valgrind 将清楚地显示尝试的 writeread 0-bytes 超出分配的 8-bytes 块。无法保证段错误的原因是该空间可能没有冲突 - 但
    • 谢谢大卫,没有冒犯。我已将您的推理读为“您正在尝试将struct SRcontents 存储在分配的空间中”,而代码没有这样做。这就是说我对 UB 持更广泛的看法,在这种情况下,我理解这是由于 struct SR *temp 指向一个指针大小的内存块,而不是 struct SR 的大小。我认为这是 Violating Type Rules 的一个例子:blog.llvm.org/2011/05/what-every-c-programmer-should-know.html。无论如何,再次感谢您的评论,我很感激。
    猜你喜欢
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    相关资源
    最近更新 更多