【问题标题】:leet code problem 2 (add two numbers) runtime error when using mallocleetcode问题2(两个数相加)使用malloc时的运行时错误
【发布时间】:2021-04-07 15:20:09
【问题描述】:

我在运行代码时收到此错误。有人能解释一下原因吗?

第 70 行:字符 15:运行时错误:“struct ListNode”类型的未对齐地址 0xbebebebebebebebe 内的成员访问,这需要 8 字节对齐 [ListNode.c]
0xbebebebebebebebe:注意:指针指向这里

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2)
{
    struct ListNode * head1=l1;
    struct ListNode * head2=l2;
    struct ListNode *toReturn=malloc(sizeof(struct ListNode));

//it is complainig about this temp
    struct ListNode *temp = NULL;
    int carry,total=0;
    
    while(head1 !=NULL || head2!=NULL)
    {
        temp = malloc(sizeof(struct ListNode));  
        
        if(carry==0)
        {
            total = head1->val + head2->val; 
        }
        else if(carry!=0)
        {
            total = head1->val + head2->val+carry;   
        }
      
        if(total ==10)
        {
            total =0;
            carry = 1; 
        }
        else if(total>10)
        {
            total = total -10;
            carry =1;
        }
        toReturn-> val = total;
        toReturn->next = temp;
        
        head1= head1->next;
        head2=head2->next;
    }
    return toReturn;
}

【问题讨论】:

  • 请提供minimal reproducible example 并描述该程序应该做什么以及您实现这一目标的概念是什么。
  • 奇怪的是,您的代码与该讨论中发布的代码不同,但错误消息是相同的,包括行号和列号。
  • 如果//This line is causing runtime error 指的是malloc() 的行,我对此表示怀疑。否则请澄清是指哪一行。
  • @Yunnosch 我再次运行代码,它抱怨 struct ListNode *temp = NULL;错误与它有关

标签: c struct sum singly-linked-list function-definition


【解决方案1】:

警告,正在做

while(head1 !=NULL || head2!=NULL)

head1 或 head2 当您在循环体中取消引用它们以获取 val

时可以为 NULL

你可能想要:

while(head1 !=NULL && head2!=NULL)

第 70 行:字符 15:运行时错误:在未对齐地址 0xbebebebebebebebe 中的成员访问,用于类型“struct ListNode”,需要 8 字节对齐 [ListNode.c] 0xbebebebebebebebe: 注意:指针指向这里

您的函数中的另一个问题是您的函数返回一个未初始化的单元格:

  • 如果 head1 和 head2 在循环之前都为 NULL,则返回一个新分配的 ListNode,其中两个 val和(最坏的)next 未初始化

  • 如果偶然在参数中收到的列表具有相同的长度,则返回两个单元格的列表,其中第二个单元格同时具有 val 和(最差)next 不是初始化。除了最后一个之外,所有通过temp = malloc(sizeof(struct ListNode)); 分配的单元都丢失(内存泄漏)

如果您再次调用该函数并返回一个列表,您将尝试取消引用一个未初始化的字段 next 并使用未定义的行为来解释您的错误


除此之外

你为什么要这样做

struct ListNode * head1=l1;
struct ListNode * head2=l2;

因为您以后不使用 l1 和 l2,所以只需要使用这些变量而不引入新变量。

为什么这么复杂的代码:

if(carry==0)
{
    total = head1->val + head2->val; 
}
else if(carry!=0)
{
    total = head1->val + head2->val+carry;   
}

而不仅仅是

total = head1->val + head2->val + carry; 

显然你在 0 到 9 之间进行十进制加法和 val 值,那么为什么要编写复杂的代码:

if(total ==10)
{
    total =0;
    carry = 1; 
}
else if(total>10)
{
    total = total -10;
    carry =1;
}

而不仅仅是

if (total>10)
{
    total = total - 10;
    carry = 1;
}

你还错过了一个 else 将 carry 重置为 0 :

if (total>10)
{
    total = total - 10;
    carry = 1;
}
else
  carry = 0;

您的算法还必须管理两个列表长度不同的情况,这可以通过多种方式完成,以管理两个列表之一在 while 内为 NULL 的情况或在 while

之后添加代码

【讨论】:

  • @Legend 是的,但无论如何,你不能在列表末尾之后继续
  • @Legend 正如我所说,另一个错误可能是因为您错过了在(至少)一个列表单元格中设置 field
  • @Legend 因为正如我在回答中所说的那样你到达一个非或错误初始化的字段 next 用于你经历的列表之一跨度>
  • 你好布鲁诺。在帮助的真正英勇的努力。但是我担心您自己已经注意到的猜测的需要和OP的不一致信息以及被拒绝的MRE使得在这里回答是徒劳的。我会赞成这项努力,但这个 Q/A 未来的帮助是非常值得怀疑的。祝你好运。
  • 在你的问题中没有关于函数调用的内容,我们对参数中收到的列表一无所知
【解决方案2】:

你的函数有几个严重的问题。

例如,如果传递给函数的指针都是空指针,则函数返回一个指向未初始化节点的指针

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2)
{
    struct ListNode * head1=l1;
    struct ListNode * head2=l2;
    struct ListNode *toReturn=malloc(sizeof(struct ListNode));
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
 
//it is complainig about this temp
    struct ListNode *temp = NULL;
    int carry,total=0;
    
    while(head1 !=NULL || head2!=NULL)
    {
        //...
    }

    return toReturn;
}

所以这个内存分配在函数的开头

struct ListNode *toReturn=malloc(sizeof(struct ListNode));

没有意义。

如果指针head1 或head2 之一等于NULL,则此while 循环

    while(head1 !=NULL || head2!=NULL)
    {
        //...
    }

调用未定义的行为,因为在循环中您正在使用空指针访问内存,例如在此语句中

total = head1->val + head2->val;

你应该在while循环中写下条件

    while(head1 !=NULL && head2!=NULL)
    {
        //...
    }

创建列表的最后一个节点也未初始化

while(head1 !=NULL || head2!=NULL)
{
    temp = malloc(sizeof(struct ListNode));  

    //...

    toReturn-> val = total;
    toReturn->next = temp;
    
    head1= head1->next;
    head2=head2->next;
}

而且你总是在改变指针toReturn指向的同一个节点

    toReturn-> val = total;
    toReturn->next = temp;

所以函数产生了内存泄漏并且列表没有被构建。

许多 if 语句是多余的。例如,而不是

if(carry==0)
{
    total = head1->val + head2->val; 
}
else if(carry!=0)
{
    total = head1->val + head2->val+carry;   
}

你可以只写一个语句

total = head1->val + head2->val+carry;   

当head1 或head2 等于NULL 时,您需要为函数附加一个处理其中一个列表的代码。

如果您认为列表将包含无符号数字,则结构 ListNode 的数据成员 val 的类型也应为 unsigned int,否则您还需要存储已存储数字的符号。

这是一个演示程序,展示了如何编写函数addTwoNumbers。

#include <stdio.h>
#include <stdlib.h>

struct ListNode 
{
    unsigned int val;
    struct ListNode *next;
};

int set( struct ListNode **head, unsigned long long n )
{
    const unsigned int Base = 10;
    
    while ( *head )
    {
        struct ListNode *tmp = *head;
        head = &( *head )->next;
        free( tmp );
    }
    
    int success = 1;
    struct ListNode **current = head;
    
    do
    {
        *current = malloc( sizeof( struct ListNode ) );
        success = *current != NULL;
        
        if ( success )
        {
            ( *current )->val  = n % Base;
            ( *current )->next = NULL;
            current = &( *current )->next;
        }
    } while ( success && ( n /= Base ) );
    
    
    if ( !success )
    {
        while ( *head )
        {
            struct ListNode *tmp = *head;
            head = &( *head )->next;
            free( tmp );
        }
    }
    
    return success;
}

FILE * display( const struct ListNode *head, FILE *fp )
{
    if ( head )
    {
        display( head->next, fp );
        fprintf( fp, "%u", head->val );
    }
    
    return fp;
}

struct ListNode * addTwoNumbers( const struct ListNode *head1, 
                                 const struct ListNode *head2 )
{
    const unsigned Base = 10;

    struct ListNode *result = NULL;
    struct ListNode **current = &result;
    
    unsigned int carry = 0;
    int success = 1;
    
    while ( success && ( head1 ||  head2 ) )
    {
        *current = malloc( sizeof( struct ListNode ) );
        success = *current != NULL;
        
        if ( success )
        {
            ( *current )->next = NULL;
            unsigned int sum = carry + ( head1 ? head1->val : 0 ) + 
                                       ( head2 ? head2->val : 0 );
            
            ( *current )->val = sum % Base;
            carry = !( sum < Base );
            
            if ( head1 ) head1 = head1->next;
            if ( head2 ) head2 = head2->next;
            current = &( *current )->next;
        }
    }
    
    if ( !success )
    {
        while ( result )
        {
            struct ListNode *tmp = result;
            result = result->next;
            free( tmp );
        }
    }
    
    return result;
}

int main(void) 
{
    struct ListNode *head1 = NULL;
    
    set( &head1, 123456789 );
    
    fputc( '\n', display( head1, stdout ) );
    
    struct ListNode *head2 = NULL;
    
    set( &head2, 123456789 );
    
    fputc( '\n', display( head2, stdout ) );

    struct ListNode *sum = addTwoNumbers( head1, head2 );
    
    fputc( '\n', display( sum, stdout ) );

    return 0;
}

程序输出是

123456789
123456789
246913578

如果您希望列表也可以包含负数,则列表的第一个节点可以包含符号:0 - 数字是非负数,1 - 数字是负数。另一种方法是将带符号的数字存储在列表的节点中。

【讨论】:

    猜你喜欢
    • 2022-11-04
    • 2018-08-10
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 2014-04-24
    相关资源
    最近更新 更多