C 调整动态数组的大小



我正在为 C 类创建一个动态数组数据结构。我已经实现了几乎所有内容,现在我正在测试它。它目前在调整大小期间卡住了。我已经使用 printf 来跟踪这个问题。看起来调整大小正在工作,但是当我在调整大小后添加下一个项目时,它就停在那里了。

我认为这可能与我的内存分配或我在调整大小期间指向和释放数组的方式有关。我是C的新手,所以这些是我的症结所在。

#include <assert.h>
#include <stdlib.h>
#include "dynArray.h"
#include <stdio.h>
struct DynArr
{
    TYPE *data;     /* pointer to the data array */
    int size;       /* Number of elements in the array */
    int capacity;   /* capacity of the array */
};

/* ************************************************************************
    Dynamic Array Functions
************************************************************************ */
/* Initialize (including allocation of data array) dynamic array.
    param:  v       pointer to the dynamic array
    param:  cap     capacity of the dynamic array
    pre:    v is not null
    post:   internal data array can hold cap elements
    post:   v->data is not null
*/
void initDynArr(DynArr *v, int capacity)
{
    assert(capacity > 0);
    assert(v!= 0);
    v->data = (TYPE *) malloc(sizeof(TYPE) * capacity);
    assert(v->data != 0);
    v->size = 0;
    v->capacity = capacity; 
}
/* Allocate and initialize dynamic array.
    param:  cap     desired capacity for the dyn array
    pre:    none
    post:   none
    ret:    a non-null pointer to a dynArr of cap capacity
            and 0 elements in it.       
*/
DynArr* newDynArr(int cap)
{
    assert(cap > 0);
    DynArr *r = (DynArr *)malloc(sizeof( DynArr));
    assert(r != 0);
    initDynArr(r,cap);
    return r;
}
/* Deallocate data array in dynamic array. 
    param:  v       pointer to the dynamic array
    pre:    none
    post:   d.data points to null
    post:   size and capacity are 0
    post:   the memory used by v->data is freed
*/
void freeDynArr(DynArr *v)
{
    if(v->data != 0)
    {
        free(v->data);  /* free the space on the heap */
        v->data = 0;    /* make it point to null */
    }
    v->size = 0;
    v->capacity = 0;
}
/* Deallocate data array and the dynamic array ure. 
    param:  v       pointer to the dynamic array
    pre:    none
    post:   the memory used by v->data is freed
    post:   the memory used by d is freed
*/
void deleteDynArr(DynArr *v)
{
    freeDynArr(v);
    free(v);
}
/* Resizes the underlying array to be the size cap 
    param:  v       pointer to the dynamic array
    param:  cap     the new desired capacity
    pre:    v is not null
    post:   v has capacity newCap
*/
void _dynArrSetCapacity(DynArr *v, int newCap)
{   
    DynArr* newArr = newDynArr(newCap);     //Create new array with new cap
    int x;
    for(x = 0; x < sizeDynArr(v); x++){
        addDynArr(newArr, v->data[x]);      //copy data
    }
    freeDynArr(v);                  //free old v
    v->capacity = newCap;
    v->size = newArr->size;
    v = newArr;                 //point v to new array
}
/* Get the size of the dynamic array
    param:  v       pointer to the dynamic array
    pre:    v is not null
    post:   none
    ret:    the size of the dynamic array
*/
int sizeDynArr(DynArr *v)
{
    return v->size;
}
/*  Adds an element to the end of the dynamic array
    param:  v       pointer to the dynamic array
    param:  val     the value to add to the end of the dynamic array
    pre:    the dynArry is not null
    post:   size increases by 1
    post:   if reached capacity, capacity is doubled
    post:   val is in the last utilized position in the array
*/
void addDynArr(DynArr *v, TYPE val)
{
    /* Check to see if a resize is necessary */
    printf("size: %dtcap: %dn", v->size, v->capacity);
    if(v->size >= v->capacity) {
        printf("in resize..");
        _dynArrSetCapacity(v, 2 * v->capacity);
    }
    v->data[v->size] = val;         //after a resize this doesn't happen.
    v->size++;
}
/*  Get an element from the dynamic array from a specified position
    param:  v       pointer to the dynamic array
    param:  pos     integer index to get the element from
    pre:    v is not null
    pre:    v is not empty
    pre:    pos < size of the dyn array and >= 0
    post:   no changes to the dyn Array
    ret:    value stored at index pos
*/
TYPE getDynArr(DynArr *v, int pos)
{
    /*returns data element at specified position within the array*/
    assert(pos < sizeDynArr(v) && pos >= 0);        //value is between zero and size
    return v->data[pos];                            //returns deferenced int value at position
}
/*  Remove the element at the specified location from the array,
    shifts other elements back one to fill the gap
    param:  v       pointer to the dynamic array
    param:  idx     location of element to remove
    pre:    v is not null
    pre:    v is not empty
    pre:    idx < size and idx >= 0
    post:   the element at idx is removed
    post:   the elements past idx are moved back one
*/
void removeAtDynArr(DynArr *v, int idx)
{
    int i;
    assert(idx < sizeDynArr(v) && idx >= 0);
    for (i = idx; i < sizeDynArr(v)-1; i++){
        v[i].data = v[i+1].data;
    }
    v->size--;
}

/* ************************************************************************
    Stack Interface Functions
************************************************************************ */
/*  Returns boolean (encoded in an int) demonstrating whether or not the 
    dynamic array stack has an item on it.
    param:  v       pointer to the dynamic array
    pre:    the dynArr is not null
    post:   none
    ret:    1 if empty, otherwise 0
*/
int isEmptyDynArr(DynArr *v)
{
    return (sizeDynArr(v) == 0);
}
/*  Push an element onto the top of the stack
    param:  v       pointer to the dynamic array
    param:  val     the value to push onto the stack
    pre:    v is not null
    post:   size increases by 1
            if reached capacity, capacity is doubled
            val is on the top of the stack
*/
void pushDynArr(DynArr *v, TYPE val)
{
    addDynArr(v, val);
}
/*  Returns the element at the top of the stack 
    param:  v       pointer to the dynamic array
    pre:    v is not null
    pre:    v is not empty
    post:   no changes to the stack
*/
TYPE topDynArr(DynArr *v)
{
    return getDynArr(v, sizeDynArr(v)-1);
}
/* Removes the element on top of the stack 
    param:  v       pointer to the dynamic array
    pre:    v is not null
    pre:    v is not empty
    post:   size is decremented by 1
            the top has been removed
*/
void popDynArr(DynArr *v)
{
    removeAtDynArr(v, sizeDynArr(v)-1);
}

int main(int argc, char* argv[]){
    DynArr* myD = newDynArr(5);
    int x;
    addDynArr(myD, 1);
    addDynArr(myD, 2);
    //printf("top: %d", sizeDynArr(myD));
    //printf("size: %dttop: %dn", sizeDynArr(myD), topDynArr(myD));
    for(x = 0; x <= 5; x++){
        addDynArr(myD, x);
        //printf("size: %dttop: %dn", sizeDynArr(myD), topDynArr(myD));
        pushDynArr(myD, x * 2);
        //printf("size: %dttop: %dn", sizeDynArr(myD), topDynArr(myD));
    }

    printf("HI");
    deleteDynArr(myD);
    return 0;   
}

您的函数_dynArrSetCapacity无法按预期工作,问题出在以下几行:

    v->capacity = newCap;
    v->size = newArr->size;
    v = newArr;                 //point v to new array
}

最后一条指令基本上没用。 v是一个指针。更改不会影响 _dynArrSetCapacity 之外的实际使用的指针。因此v->data 0 addDynArr,你会得到一个分段错误:

    _dynArrSetCapacity(v, 2 * v->capacity);
}
v->data[v->size] = val;         //after a resize this doesn't happen.

要么使用 v->data = newArr->data,要么改用指针上的指针。

v = newArr;                 //point v to new array

该行只是将newArr分配给_dynArrSetCapacity收到的指针的副本,它不会修改调用函数中的指针。

为此,您应该传递指针的地址并让_dynArrSetCapacity接收DynArr**

void _dynArrSetCapacity(DynArr **v, int newCap)
{   
    DynArr* newArr = newDynArr(newCap);     //Create new array with new cap
    int x;
    for(x = 0; x < sizeDynArr(*v); x++){
        addDynArr(newArr, (*v)->data[x]);      //copy data
    }
    freeDynArr(*v);                  //free old v
    // v->capacity = newCap;  These are superfluous, since we change the pointer itself
    // v->size = newArr->size; 
    *v = newArr;                 //point v to new array
}

但更好的解决方案是只重新分配阵列,

void _dynArrSetCapacity(DynArr *v, int newCap)
{   
    TYPE *temp = realloc(v->data,newCap * sizeof *temp);
    if (!temp) { // alloc failure
        exit(EXIT_FAILURE);
    }
    v->data = temp;
    v->capacity = newCap;
    v->size = newArr->size;
}

最新更新