【问题标题】:Getting a SIGSEGV error. Cant find the pointer responsible收到 SIGSEGV 错误。找不到负责的指针
【发布时间】:2019-06-30 17:14:48
【问题描述】:

我刚开始研究 C 中的链表,我似乎在打印部分遇到了一个无限循环,尝试修复所有松散的末端仍然遇到同样的问题。我已经尝试过多次调试,它总是一个 SIGSEGV 错误。我使用过 DEV C++ 和 GCC 4.9.2。

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

typedef struct node {
    int data;
    struct node *next;
}node;

void print();
node *clist(int n);
node *head = NULL;

int main() 
{
    int n;
    printf("Input the number of nodes for the Linked List.\n");
    scanf("%d", &n);

    clist(n);
    print();

    return 0;
}

void print() 
{
    node *show = NULL;
    show = head;
    while (show != NULL) {
        printf("%d => ", show->data);  
        show = (show->next);
    }

    printf("NULL");

}

node *clist(int n) 
{
    node *temp = NULL;
    node *p = NULL;
    int i;

    for (i = 0; i<n; i++)
    {
        temp = (node*)malloc(sizeof(node));

        printf("Enter the element %d of the list", i + 1);
        scanf("%d", &temp->data);

        if (head == NULL)
        {
            head = temp;

        }

        else { 
      p = head; 
      while( p->next ) 
           { 
              p = p->next; 
            } 
            p->next = temp; //UPDATE: SIGSSEGV ERROR HERE NOW 
            }
              }
    return head;
}

【问题讨论】:

  • 我对您的 clist 方法以及它如何实际创建大小为 n 的链表感到有些困惑。您是否尝试过使用调试器(即 gdb)来精确定位 SIGSEGV 的来源?
  • 看一眼你有两个continue 语句意味着p-&gt;next = temp 永远不会被执行。
  • OT:为了便于阅读和理解:1)请始终缩进代码:在每个左大括号“{”后缩进。在每个右大括号 '}' 之前取消缩进。建议每个缩进级别为 4 个空格。 2) 使用有意义的变量(和参数)名称。像:1p1 和 n 这样的名称是没有意义的,即使在当前上下文中也是如此。 3)单独的代码块:forifelsewhiledo...whileswitchcasedefault通过单个空行,4)通过2或3个空行分隔函数(保持一致)
  • OT:关于:temp = (node*)malloc(sizeof(node)); 1) 在 C 中,返回的类型是 void*,可以分配给任何指针。强制转换只会使代码混乱,使其更难以理解、调试等 2) 在调用任何堆分配函数时:malloc()calloc()realloc(),始终检查 (!=NULL) 返回值确保操作成功。
  • 您已经更改了之前的代码。就目前而言,它正在崩溃,因为您正在取消引用一个空指针(当 p 为空时,您试图使用 p->next = temp)。确保您显示的代码正是您正在运行的代码。

标签: c data-structures linked-list segmentation-fault


【解决方案1】:

以下建议的代码:

  1. 干净编译
  2. 执行所需的功能
  3. 正确检查和处理错误
  4. 一致缩进
  5. 自行清理
  6. 避免语句中的冗余,例如:if( head == NULL )
  7. 消除未使用的返回值
  8. 正确声明不带参数的函数原型
  9. 为了便于阅读,使用适当的水平间距

现在,建议的代码:

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

typedef struct snode
{
    int data;
    struct snode *next;
} node;

// prototypes
void  print( void );
void  clist( int n );
void  cleanup( void );

node *head = NULL;


int main( void )
{
    int n;

    printf( "Input the number of nodes for the Linked List.\n" );
    if( scanf( "%d", &n ) != 1 )
    {
        fprintf( stderr, "scanf for number of data points failed\n" );
        exit( EXIT_FAILURE );
    }

    clist( n );
    print();
    cleanup();
    return 0; // << optional in modern C
}


void print()
{   
    node *show = head;

    while( show )
    {
        printf( "%d => ", show->data );
        show = show->next;
    }

    puts( "" );
}


void clist( int n )
{
    node *temp = NULL;
    node *p = NULL;

    for( int i=0; i<n; i++ )
    {
        temp = malloc( sizeof( node ) );
        if( !temp )
        {
            perror( "malloc failed" );
            cleanup();
            exit( EXIT_FAILURE );
        }

        // EDIT:
        temp->next = NULL;
        // end EDIT:

        printf( "Enter the element %d of the list", i+1 );
        if( scanf( "%d", &temp->data ) != 1 )
        {
            fprintf( stderr, "scanf for a data failed\n" );
            cleanup();
            exit( EXIT_FAILURE );
        }

        if( !head )
        {  // list empty
            head = temp;
        }

        else
        {  // list already contains some nodes
            p = head;

            while( p->next )
            {
                p = p->next;
            }
            p->next = temp;
        }
    }
}


void cleanup()
{
    node *temp = head;
    node *current;

    while( temp )
    {
        current = temp;
        temp = temp->next;
        free( current );
    }
}

这是程序简单运行的输出:

Input the number of nodes for the Linked List.
2
Enter the element 1 of the list1
Enter the element 2 of the list2
1 => 2 => 

建议在用户输入之前为输出中的节点数据值放置一个空格

【讨论】:

    【解决方案2】:

    我已经修改了您的代码并在行中添加了解释性 cmets:

    node *clist(int n)
    {
        node *temp = NULL;
        node *p = NULL;
        node *prePtr=NULL; //define this to keep track of previous node
        int i;
    
        for (i = 0; i<n; i++)
        {
            temp = (node*)malloc(sizeof(node));
    
            printf("Enter the element %d of the list", i + 1);
            scanf("%d", &temp->data);
            //temp->next=NULL;
            if (head == NULL)
            {
                head = temp;
                head->next=NULL; //Make head OR above Temp next pointer NULL
            }
    
            else {
          p = head;
          //while( p->next ) This is not condition
            while( p!=NULL )//Check for a condition that became false eventually.
            {
                   prePtr=p;//to keep track of the previous location
                            //because you cannot add another node if you are 
                            //already ahead of that node.
                  p = p->next;//this make you ahead of the node where you want
                             //to insert node when wile condition became false.
                //}
            }
                //p->next = temp; //UPDATE: SIGSSEGV ERROR HERE NOW
                //above line try to add a node on next while it's already NULL.
                    prePtr->next=temp;//this take previous node and add a temp to its next node
                    temp->next=p;//here you assign temp->next=p which is NULL
                }
        }
        return head;
    }
    

    【讨论】:

    • 关于://while(p->next) 这不是条件 实际上,如果'next' 包含NULL,则这是一个'条件',那么while()循环将退出。否则while() 循环将再次迭代
    • 为了便于阅读和理解,请始终缩进代码。在每个左大括号“{”后缩进。在每个右大括号 '}' 之前取消缩进。建议每个缩进级别为 4 个空格
    • 请阅读关于 OPs 问题的评论,关于从 malloc() 转换返回值
    猜你喜欢
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多