C中的奇怪分段错误错误

时间:2015-08-05 01:10:24

标签: c arrays memory-management

我在Mac牛。我正在尝试编译这个动态数组的简单程序,但我在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元素声明为 - &gt; DAP->maxsize * sizeof(int) * 2,它会在调用数组增长时抛出分段错误。奇怪的是,如果我尝试删除其中一个常数来乘以像DAP->maxsize * sizeof(int)这样的东西,那么它就不会抛出分段错误错误。我不确定我的代码或其他地方是否有问题。

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

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

1 个答案:

答案 0 :(得分:2)

我发现了两个问题。首先是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所展示的内容。第一条消息说明&#34;无效写入大小4&#34;准确指出问题所在。

[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)