修复C语言中有时出现的分段错误

修复C语言中有时出现的分段错误,c,linked-list,segmentation-fault,C,Linked List,Segmentation Fault,我是一个学习c语言的初学者,对我来说,切分发生过很多次。我还在网上做了一些关于分段错误的研究:一些原因是分配内存问题、空指针或内存访问问题。但我很困惑,为什么有时候代码会工作,但有时候它会说分段错误?下面是我在insertAt和destroplist函数中得到的代码: #include <stdio.h> #include <stdlib.h> typedef struct NODE{ int data; struct NODE* next; } nod

我是一个学习c语言的初学者,对我来说,切分发生过很多次。我还在网上做了一些关于分段错误的研究:一些原因是分配内存问题、空指针或内存访问问题。但我很困惑,为什么有时候代码会工作,但有时候它会说分段错误?下面是我在
insertAt
destroplist
函数中得到的代码:

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

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

node* insertAt(node*, int, int);
void printList(node*);
void destroyList(node*);

node* myList;
int counter = -1;

int main()
{
    myList = NULL;
    int pos, input;

    myList = insertAt(myList, 0, 333);
    myList = insertAt(myList, 0, 555);
    myList = insertAt(myList, 1, 222);
    myList = insertAt(myList, 3, 444);

    printf("My List:\n");
    printList(myList);

    destroyList(myList);

    printf("After Destroy:\n");
    printList(myList);

    return 0;
}

node* insertAt(node* head, int pos, int newData)
{
    node* temp = (node*) malloc(sizeof(node));
    temp->data = newData;
    counter++;

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

    }else if (pos == 0)
    {
        temp->next = head;
        head = temp;
        return head;

    }else if(head != NULL && pos > counter){
        node* current = head;
        node* temp2 = current;
        while(current != NULL){
            temp2 = current;
            current = current->next;
        }
        temp->next = current;
        temp2->next = temp;
        return head;

    }else
    {
        node* current = head;
        while(pos-1>0){
            current = current->next;
            pos--;
        }
        temp->next = current->next;
        current->next = temp;
        return head;
    }
}

void printList(node* head)
{
    node* ptr = head;

    while (ptr != NULL)  {
        printf("%i ", ptr->data);
        ptr = ptr->next;
    }
    printf("\n");
}

void destroyList()
{
    node* temp;
    while(myList){
        temp = myList;
        myList = temp->next;
        free(temp);
    }
}
#包括
#包括
类型定义结构节点{
int数据;
结构节点*下一步;
}节点;
节点*插入(节点*,int,int);
作废打印列表(节点*);
作废销毁清单(节点*);
节点*myList;
int计数器=-1;
int main()
{
myList=NULL;
int pos,输入;
myList=insertAt(myList,0333);
myList=insertAt(myList,0555);
myList=insertAt(myList,1222);
myList=insertAt(myList,3444);
printf(“我的列表:\n”);
打印列表(myList);
销毁清单(myList);
printf(“销毁后:\n”);
打印列表(myList);
返回0;
}
节点*插入(节点*头部、int pos、int newData)
{
node*temp=(node*)malloc(sizeof(node));
临时->数据=新数据;
计数器++;
if(head==NULL){
压头=温度;
回流头;
}否则如果(位置==0)
{
温度->下一步=头部;
压头=温度;
回流头;
}else if(head!=NULL&&pos>计数器){
节点*电流=头部;
节点*temp2=当前;
while(当前!=NULL){
temp2=电流;
当前=当前->下一步;
}
温度->下一步=当前;
temp2->next=temp;
回流头;
}否则
{
节点*电流=头部;
而(位置1>0){
当前=当前->下一步;
pos--;
}
临时->下一步=当前->下一步;
当前->下一步=温度;
回流头;
}
}
无效打印列表(节点*头)
{
节点*ptr=头部;
while(ptr!=NULL){
printf(“%i”,ptr->data);
ptr=ptr->next;
}
printf(“\n”);
}
作废销毁清单()
{
节点*温度;
while(myList){
温度=myList;
myList=temp->next;
免费(临时);
}
}

在gdb下运行程序,如下所示:

$ gdb ./a.out
(gdb) run
...
Segmentation fault
(gdb) bt

这将打印一个回溯,显示代码中导致错误的位置以及调用该错误的任何函数。如果segfault发生在库函数中,请继续查看回溯,直到找到代码,然后查看可以在那里修复的内容。

在gdb下运行程序,如下所示:

$ gdb ./a.out
(gdb) run
...
Segmentation fault
(gdb) bt
这将打印一个回溯,显示代码中导致错误的位置以及调用该错误的任何函数。如果segfault发生在库函数中,请继续查看回溯,直到找到您的代码,然后看看您可以在那里修复什么

我还在网上做了一些关于分段错误的研究:一些原因是分配内存问题、空指针或内存访问问题

分段错误通常表示您的程序试图访问不属于它的内存,或者以不允许访问的方式访问它。您可以将其分解为不同的方式,程序可能会这样做,但一般规则是确保只取消引用有效指针,并且只尝试修改可修改的数据

但我很困惑,为什么有时候代码会工作,但有时候它会说分段错误

C没有指定任何特定的行为都会产生分段错误。该标准甚至不包含“分段故障”一词。然而,它确实谈到了“未定义的行为”——如果您执行的代码不遵守C及其标准库的语义规则,您就会得到这种行为

分段错误是许多系统上未定义行为的一种可能表现形式,但这超出了C的范围。C不承诺在任何特定情况下的任何特定形式的未定义行为——它不能,因为该行为将被定义,而不是未定义。因此,可以看到的其他形式的未定义行为之一是程序员想要的任何行为。事实上,这种情况有时也会出现

此外,可能存在这样的情况,即给定的程序只有在某些条件下(例如对于特定的输入),才具有未定义的行为(可能表现为分段错误)

在任何情况下,您的程序有时甚至总是(在您可以确定的范围内)按预期的方式运行并不能证明它没有未定义的行为


对于特定的代码,其中有几个缺陷可能导致它有时表现出未定义的行为。其中包括:

  • 您可以使用
    malloc()
    的返回值,而不检查它是否为NULL
    malloc()
    通过返回NULL来表示内存分配失败,如果稍后尝试取消引用,则调用未定义的行为

  • 当它将初始节点插入列表并在列表末尾添加节点时,
    insertAt()
    无法设置新节点的
    next
    指针,留下一个不确定的值。当任何函数稍后遍历该列表时,它会计算该不确定值,从而产生未定义的行为。在实践中,如果不确定值被证明是空指针值,则这可能恰好具有预期的行为。这并不能保证,但也并非完全不可能

  • 您的
    main()
    函数将无效的
    myList
    指针传递到
    printList()
    ,尝试在列表在
    destroyList()中解除分配后打印列表

我还在网上做了一些关于分段错误的研究:一些原因是分配内存问题、空指针或内存访问问题

分段错误通常表示程序试图访问内存
$ make
cc -Wall -g    test.c   -o test
$ ./test
foo
$ valgrind ./test
==62034== Memcheck, a memory error detector
==62034== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==62034== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==62034== Command: ./test
==62034== 
==62034== Invalid write of size 1
==62034==    at 0x10043B5C0: _platform_memmove$VARIANT$Nehalem (in /usr/lib/system/libsystem_platform.dylib)
==62034==    by 0x1001B8421: stpcpy (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x10022BBED: __strcpy_chk (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x100000F2C: main (test.c:9)
==62034==  Address 0x100a8f6d3 is 0 bytes after a block of size 3 alloc'd
==62034==    at 0x10000A1B9: calloc (vg_replace_malloc.c:715)
==62034==    by 0x100000F11: main (test.c:7)
==62034== 
==62034== Invalid read of size 1
==62034==    at 0x10000B2C8: strlen (vg_replace_strmem.c:470)
==62034==    by 0x1001EDA4B: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x1002166C0: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x1001EC381: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x1001EA21B: printf (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x100000F42: main (test.c:10)
==62034==  Address 0x100a8f6d3 is 0 bytes after a block of size 3 alloc'd
==62034==    at 0x10000A1B9: calloc (vg_replace_malloc.c:715)
==62034==    by 0x100000F11: main (test.c:7)
==62034== 
foo
==62034== 
==62034== HEAP SUMMARY:
==62034==     in use at exit: 26,553 bytes in 188 blocks
==62034==   total heap usage: 273 allocs, 85 frees, 32,788 bytes allocated
==62034== 
==62034== LEAK SUMMARY:
==62034==    definitely lost: 0 bytes in 0 blocks
==62034==    indirectly lost: 0 bytes in 0 blocks
==62034==      possibly lost: 0 bytes in 0 blocks
==62034==    still reachable: 0 bytes in 0 blocks
==62034==         suppressed: 26,553 bytes in 188 blocks
==62034== 
==62034== For counts of detected and suppressed errors, rerun with: -v
==62034== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 19 from 19)
==62034== Invalid write of size 1
==62034==    at 0x10043B5C0: _platform_memmove$VARIANT$Nehalem (in /usr/lib/system/libsystem_platform.dylib)
==62034==    by 0x1001B8421: stpcpy (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x10022BBED: __strcpy_chk (in /usr/lib/system/libsystem_c.dylib)
==62034==    by 0x100000F2C: main (test.c:9)
==62034==  Address 0x100a8f6d3 is 0 bytes after a block of size 3 alloc'd
==62034==    at 0x10000A1B9: calloc (vg_replace_malloc.c:715)
==62034==    by 0x100000F11: main (test.c:7)