我在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这个!
答案 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)