c - C 中奇怪的段错误

标签 c arrays memory-management

我使用的是 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->maxsize * sizeof(int) * 2,当调用数组增长。现在奇怪的是,如果我尝试删除其中一个常量来乘以 DAP->maxsize * sizeof(int) 之类的东西,那么它不会抛出段错误错误。我不确定我的代码或其他地方是否有问题。

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

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

最佳答案

我发现了两个问题。首先在 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 显示的内容。第一条消息“Invalid write of size 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)

关于c - C 中奇怪的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31821857/

相关文章:

c++ - 扩展精度浮点库 C/C++

c - 长字符串上的段错误 11,在访问字符串之前,仅当字符串 > 14 时

algorithm - 无法理解在外部合并排序中将多大块数据加载到 RAM 中

php - 在 fatal error 发生之前如何处理 "Allowed memory size of X bytes exhausted"?

c - 摆脱警告 : implicit declaration of function ‘fileno’ in flex

c++ - Hook ishellfolder enumobjects

javascript - ng-if 与 JSON feed 数组值

javascript - 有什么简单的方法可以随机打乱 JavaScript 数组但固定为给定的键?

c - 如何在 for 循环中创建一个 char 数组和 2 个 void 18 次,每次都具有不同的名称(数字)?

ios - 使用数据管理器单例管理核心数据对象