Home > Mobile >  Prepend scalar and arrays to another array in C
Prepend scalar and arrays to another array in C

Time:03-31

I am working on a set of C functions that will allow for dynamically growing arrays of the user definition. I have been able, with the help of some on this site to develop functions that act as an array initialize,and another function that can append a scalar to the array or append an array to the array. I am using a struct titled Array which acts as a container for the array array, the active length of the array len, the total allocated size of the array size, and the memory per indice elem.

The first function initialize_array allocates the memory and initializes the array, and the function init_array is a wrapper for initialize_array that pre-formats some information and returns an Array data type. Finally I have a function append_array that can take a scalar or an array and can append the array within the Array struct using a memcp method that is cast to a char to assist in pointer arithmetic. I am trying to recreate the append_array function with a prepend_array function that will add the scalar or array passed in *items in the very first indices and push the other indices to the left. I am a bit lost on how to do this, any suggestions would be helpful.

array.h

#ifndef ARRAY_H
#define ARRAY_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
    void *array; // Container for array
    size_t len;  // Active length of array
    size_t size; // Size of allocated memory
    int elem;    // Memory consumption per element
} Array;

void initiate_array(Array *array, size_t num_indices);
Array init_array(int size, size_t num_indices);
int append_array(Array *array, void *items, size_t count);
int prepend_array(Array *array, void *items, size_t count);

#endif /* ARRAY_H */

array.c

#include "array.h"

void initiate_array(Array *array, size_t num_indices) {
    void *pointer;

    pointer = malloc(num_indices * array->elem);

    if (pointer == NULL) {
        printf("Unable to allocate memory, exiting.\n");
        free(pointer);
        exit(0);
    }
    else {
        array->array = pointer;
        array->len = 0;
        array->size = num_indices;
    }
}

Array init_array(int size, size_t num_indices) {
    Array array;
    array.elem = size;
    initiate_array(&array, num_indices);
    return array;
}

int append_array(Array *array, void *items, size_t count) {
    if (array->len   count > array->size) {
        size_t size = (array->len   count) * 2;
        void *pointer = realloc(array->array, size * array->elem);
        if (pointer == NULL) {
            return 0;
        }
        array->array = pointer;
        array->size = size;
    }
    memcpy((char *)array->array   array->len * array->elem, items, count * array->elem);
    array->len  = count;
    return 1;
}

int prepend_array(Array *array, void *items, size_t count) {
    if (array->len   count > array->size) {
        size_t size = (array->len   count) * 2;
        void *pointer = realloc(array->array, size * array->elem);
        if (pointer == NULL) {
            return 0;
        }
        array->array = pointer;
        array->size = size;
    }
    // Not sure how to handle this with memcp like was used for append_array
    array->len  = count;
    return 1;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "array.h"

int main(int argc, char** argv)
{
    int i, j;
    float ii = 0.0;
    size_t indices = 20;
    Array float_test = init_array(sizeof(float), indices);
    Array int_test = init_array(sizeof(int), indices);
    // Populate both arrays
    for (i = 0; i < 30; i  ) {
        ii  = 1.1;
        append_array(&int_test, &i, 1);
        append_array(&float_test, &ii, 1);
    }

    int a[3] = {10, 9, 8};
    prepend_array(&int_test, a, 3);
    // Print int array values
    for (i = 0; i < int_test.len; i  )
    {
        printf("Value: %d Size:%zu \n",((int *) int_test.array)[i], int_test.len);
    }
    return (EXIT_SUCCESS);
}

CodePudding user response:

To prepend elements to the array, after allocating additional memory, you'll first need to move the existing elements.

When the destination and source memory has the possibility of overlapping, we use memmove to safely move our data around1.

After moving our existing elements, we then copy the new elements into place.

Visualized:

A is [11, 22, 33, 44, 55]
V is [99, 88, 77]

resize(A):      [11, 22, 33, 44, 55, __, __, __]
move(A   3, A): [__, __, __, 11, 22, 33, 44, 55]
copy(A, V):     [99, 88, 77, 11, 22, 33, 44, 55]

Based on your code, this would look something like:

memmove(
    ((char *) array->array)   count * array->elem,
    array->array,
    array->len * array->elem);

memcpy(array->array, items, count * array->elem);

1. The use of memcpy to copy to and from overlapping memory is Undefined Behavior, and a source of many bugs.

  • Related