【问题标题】:Weird Segmentation fault error in CC中奇怪的分段错误错误
【发布时间】:2015-08-05 01:10:23
【问题描述】:

我在 mac ox 上。我正在尝试编译这个简单的动态数组程序,但是我在 realloc 上遇到了分段错误,我相信当我尝试增加我的数组时

这里是代码

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

enum { MAX_SIZE = 5 };

typedef struct dynamic_array{
    int maxsize;
    int size;
        int* items;
}DArray;

extern int  init(DArray *DAP);
extern void add(DArray *DAP, int val);
extern void addToSize(DArray *DAP,int val);
extern void destroy(DArray *DAP);
extern void print(DArray *DAP);
static int  full(DArray *DAP);
static int  grow(DArray *DAP);

int init(DArray* DAP)
{
    DAP->items = (int*)malloc(sizeof(int) * MAX_SIZE);
    if(DAP->items == NULL)
        {
        printf(" ALLOCATION OF DAP ITEMS NOT SUCCUESSFULL \n ");
        return 0;
    }
    DAP->maxsize = MAX_SIZE;
        DAP->size = 0; //initial size -> 0
    return 1;
}

void print(DArray* DAP)
{
    int i;
    for(i = 0; i < DAP->size; i++)
    {
        int* itemLocation = (DAP->items + sizeof(int) * i);
        printf(" \n ITEM AT LOCATION %d is %d \n ",i,*itemLocation);
    }
}

void add(DArray* DAP,int value)
{
    //add item at the end of the array, we can get the position by size counter?
    if(full(DAP) == 0)
    {
                addToSize(DAP,value);
    }
    else
    {
        printf(" \n ********************* REALLOCATING AS SIZE == MAX SIZE %d %d ********************* \n ",DAP->size, DAP->maxsize);
        int result =  grow(DAP) == 1 ? 1 : 0;
        if(result == 0)
        {
            printf(" \n ********************* GROW NOT SUCCESSFULL ********************* \n " );    
        }else if(result == 1)
        {
            printf(" \n ********************* GROW SUCCESSFULL *************************** \n ");
            addToSize(DAP,value);
        }
        else
            exit(1);
    }
}

int full(DArray* DAP)
{
    int result = DAP->size == DAP->maxsize ? 1 : 0;
    return result;
}

void addToSize(DArray* DAP,int value)
{
        int* location = DAP->items + DAP->size;
        *location = value+1;
        printf(" \n AFTER ADDING TO ITEMS, location, VALUE  %d %d \n ", DAP->size,*location);   
        DAP->size++;
}

int grow(DArray* DAP)
{
    int* temp = (int *)realloc(DAP->items,DAP->maxsize * sizeof(int) * 2);
    if(!temp)
    {
        printf(" ********************* REALLOC NOT SUCCESSFULL ********************* \n ");
        return 0;
    }
    else
    {
        DAP->items = temp;
        DAP->maxsize *= 2;
        //sanity check
        printf(" \n ********************* AFTER REALLOCATION CHECK AGAIN ********************* \n ");
        print(DAP);
        return 1;
    }
}

void destroy(DArray* DAP)
{
    if(DAP != NULL)
    {
        if(DAP->items != NULL)
        {
            free(DAP->items);
              DAP->items = 0;
              DAP->maxsize = 0;
                  DAP->size = 0;
        }
    }
}

int main()
{
    DArray darray;
    if(init(&darray) == 1)
    {
        int i;
        for(i = 0; i < 10; i++)
        {
            add(&darray,i);
        }
    }

    print(&darray);
    destroy(&darray);

    return 0;
}

现在奇怪的部分是在我的第二个参数的 realloc 中,我将 size 元素声明为 -> DAP-&gt;maxsize * sizeof(int) * 2,当调用数组增长时它会引发分段错误。现在奇怪的是,如果我尝试删除其中一个常量来乘以 DAP-&gt;maxsize * sizeof(int) 之类的东西,那么它不会引发分段错误错误。我不确定我的代码或其他地方是否有问题。

********* 发现问题*********

问题出在 addToSize 函数内部。将代码行从 int* location = DAP-&gt;items + (sizeof(int) * DAP-&gt;size); 更改为 int* location = DAP-&gt;items + DAP-&gt;size; 解决了它。显然 sizeof(int) 导致一些垃圾值在 realloc 中传递。感谢艾伦!

【问题讨论】:

  • 您是否通过 gdb 运行您的程序?
  • init 调用中取消引用空指针
  • 标准警告:不要像 malloc 和朋友返回的那样投射 void *。 C 不是 C++。
  • 在您的代码中有很多 (DAP-&gt;items + sizeof(int) * i); 会超出范围。增量使用指针类型,因此 DAP-&gt;items + i; 在这些情况下是您想要的。
  • addToSize(): int* location = DAP-&gt;items + (sizeof(int) * DAP-&gt;size); 中的内存损坏。应该是int* location = DAP-&gt;items + DAP-&gt;size;。稍后可能会导致垃圾值被传递给realloc

标签: c arrays memory-management


【解决方案1】:

我发现了两个问题。先在addToSize

int* location = DAP->items + (sizeof(int) * DAP->size);

指针算法自动知道通过指针大小的增量来增加指针,因此乘以sizeof(int) 会导致您离开数组的末尾,从而导致未定义的行为。你应该这样做:

int* location = DAP->items + DAP->size;

同样在print:

int* itemLocation = (DAP->items + sizeof(int) * i);

应该是:

int* itemLocation = DAP->items + i;

对于此类问题,Valgrind 非常有助于发现它们。

编辑:

当我通过它运行您的代码时,这是 valgrind 显示的内容。第一条消息指出“大小为 4 的写入无效”准确地指出了问题所在。

[dbush@db-centos tmp]$ valgrind --leak-check=full ./x1
==8270== Memcheck, a memory error detector
==8270== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==8270== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==8270== Command: ./x1
==8270== 

 AFTER ADDING TO ITEMS, location, VALUE  0 1 

 AFTER ADDING TO ITEMS, location, VALUE  1 2 
==8270== Invalid write of size 4
==8270==    at 0x80485F6: addToSize (x1.c:78)
==8270==    by 0x8048530: add (x1.c:49)
==8270==    by 0x8048721: main (x1.c:124)
==8270==  Address 0x401a048 is 12 bytes after a block of size 20 alloc'd
==8270==    at 0x4005B83: malloc (vg_replace_malloc.c:195)
==8270==    by 0x8048475: init (x1.c:22)
==8270==    by 0x8048701: main (x1.c:119)
==8270== 
==8270== Invalid read of size 4
==8270==    at 0x80485FB: addToSize (x1.c:79)
==8270==    by 0x8048530: add (x1.c:49)
==8270==    by 0x8048721: main (x1.c:124)
==8270==  Address 0x401a048 is 12 bytes after a block of size 20 alloc'd
==8270==    at 0x4005B83: malloc (vg_replace_malloc.c:195)
==8270==    by 0x8048475: init (x1.c:22)
==8270==    by 0x8048701: main (x1.c:119)
==8270== 


 AFTER ADDING TO ITEMS, location, VALUE  2 3 

 AFTER ADDING TO ITEMS, location, VALUE  3 4 

 AFTER ADDING TO ITEMS, location, VALUE  4 5 

 ********************* REALLOCATING AS SIZE == MAX SIZE 5 5 ********************* 
--8270-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--8270-- si_code=1;  Faulting address: 0x48;  sp: 0x62a01ddc

valgrind: the 'impossible' happened:
   Killed by fatal signal
==8270==    at 0x380348EE: vgPlain_arena_malloc (m_mallocfree.c:244)
==8270==    by 0x380637F7: vgPlain_cli_malloc (replacemalloc_core.c:86)
==8270==    by 0x38002AD3: vgMemCheck_realloc (mc_malloc_wrappers.c:423)
==8270==    by 0x3806420B: do_client_request (scheduler.c:1370)
==8270==    by 0x380659CE: vgPlain_scheduler (scheduler.c:1061)
==8270==    by 0x3808E9F8: run_a_thread_NORETURN (syswrap-linux.c:91)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable
==8270==    at 0x4005C82: realloc (vg_replace_malloc.c:476)
==8270==    by 0x804864B: grow (x1.c:85)
==8270==    by 0x804855C: add (x1.c:54)
==8270==    by 0x8048721: main (x1.c:124)

【讨论】:

  • 非常感谢!!非常非常非常有帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多