0

I am having problems wrapping my brain around proper use of pointers with arrays in C.

The project I am working on is building a simple Dynamic Array and the functions to go along with it. However I do not seem to be able to find the correct syntax/functions to update the array size dynamically. Here is the relevent code:

Array Creation:

    struct DArray
{
    TYPE *data;     /* pointer to the data array */
    int size;       /* Number of elements in the array */
    int capacity;   /* capacity ofthe array */
};


void initDArray(DArray *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;
}


DArray* createDArray(int cap)
{
    assert(cap > 0);
    DArray *r = (DArray *)malloc(sizeof( DArray));
    assert(r != 0);
    initDArray(r,cap);
    return r;
}

And the problem bit, in its current non-working form:

    void _DArraySetCapacity(DArray *v, int newCap)
{

    TYPE * newptr = createDArray(newCap);
    newptr = (TYPE *) malloc(sizeof(TYPE) * newCap);
    v->capacity = newCap;
    v->data = newptr;

}

My method being to create a temporary pointer with increased memory allocation then copy the existing date to it and point the data pointer at the new location. I suspect I may be looking at the issue in entirely the wrong way.

Any help tips or pointers (pun intended) would be appreciated. Thanks in advance.

4
  • 3
    You may want to read about the realloc function. Also, you should not cast the result of malloc (or realloc). Commented Apr 15, 2015 at 23:55
  • It looks like you are using a C++ compiler to compile C. (struct definitions are not typedefs in C, in C++ they are) Commented Apr 15, 2015 at 23:58
  • so you fixed your assert problem then - did you update the question or accept an answer? Just looked - no you didnt Commented Apr 16, 2015 at 0:06
  • 2
    By the way, don't use assert as a method to check for errors from functions, in "release" builds the assert preprocessor macro does nothing. It might be okay for simple school or book assignments, but using it instead of a proper if check in real life is a big no-no. Better learn it early to get good habits going from the start. Commented Apr 16, 2015 at 0:11

4 Answers 4

1

What about using realloc?

The C library function void *realloc(void *ptr, size_t size) attempts to resize the memory block pointed to by ptr that was previously allocated with a call to malloc or calloc.

Sign up to request clarification or add additional context in comments.

Comments

1

Fortunately, you don't need to move memory around yourself: realloc does that for you.

In your case a typical usage would be:

v->capacity = newCap;
v->data = realloc(v->data, newCap * sizeof *v->data); /* same as sizeof(TYPE) */

Note that you don't have to (and shouldn't) cast the result of malloc/calloc or realloc.

2 Comments

While you're technically correct, assigning back to the original pointer you reallocate can lead to memory leaks. Think about the case when realloc fail, then the original pointer will be lost.
@JoachimPileborg quite right, but as OP is using assert to test his mallocs he can also just use assert on the result of realloc and bail (albeit uncleanly) out of the program entirely.
0

Use realloc()!

See this question and answer to better understand realloc and how its used.

Comments

0

Dynamic generic arrays in C are unexpectedly easy.

Appending/inserting elements:

size_t size = 0, count = 0;
mytype_t *items; // array of mytype_t

mytype_t foo1, foo2, foo3;

carray_grow(items, size, count += 1); // grow to 1
items[0] = foo3;

carray_grow(items, size, count += 2); // grow to 3
carray_insert(items, count, 0, 2); // shift 2 up at 0
items[0] = foo1;
items[1] = foo2;

Removing elements:

carray_remove(items, count, 0, 2); // remove 2 at 0
carray_grow(items, size, count -= 2); // shrink to 1

Free it completely?

carray_grow(items, size, count = 0);

Backend (few defines and single function ahead):

int carray_xgrow(void **datap, size_t *sizep, size_t esize, size_t count);
// 0 or -1/errno(realloc)

#define carray_grow(array, size, count) carray_xgrow((void **)&(array), &(size), sizeof((array)[0]), count)
// 0 or -1/errno(realloc)

#define carray_move(array, from, to, n) memmove(&(array)[to], &(array)[from], sizeof((array)[0]) * (n))
#define carray_insert(array, count, i, n) carray_move(array, i, (i)+(n), (count)-(i)-(n))
#define carray_remove(array, count, i, n) carray_move(array, (i)+(n), i, (count)-(i)-(n))

int
carray_xgrow(void **datap, size_t *sizep, size_t esize, size_t count)
{
    assert(datap != NULL);
    assert(sizep != NULL);
    assert(esize > 0);

    size_t size = *sizep;
    {
        size_t cap = size / esize;

        if (cap >= count * 2) // regrow at 1/2
            cap = 0;

        while (cap < count) // grow by 3/2
            cap = (cap < 2) ? (cap + 1) : (cap * 3 / 2);

        size = cap * esize;
    }

    if (size != *sizep) {
        if (size) {
            void *data = realloc(*datap, size);
            if (data == NULL) return -1;
            *datap = data;
            *sizep = size;
        }
        else {
            free(*datap);
            *datap = NULL;
            *sizep = 0;
        }
    }
    return 0;
}

(Note size in bytes, but cap and count in elements.)

EDIT: removed minor dependencies

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.