Home > Software design >  Is there a way to create a dynamic type assignment in C
Is there a way to create a dynamic type assignment in C

Time:03-26

I am working to create a set of functions in C that will allow a dynamically growing array. In this example I have create a struct with a variable titled len that stores the active length of the array, another variable titled size that stores the total length of the array assigned during initialization, and another variable titled array which is a pointer to the memory containing the array data. In this example the variable array is initialized in the struct as an integer. Within the function titled int_array I initialize the array and and return the struct. Within that function I call the init_int_array function that does the heavy lifting. In addition, I have another function titled append_int_array that checks the memory allocation and assigns another chunk of memory if necessary and then appends the array with a new index/variable. As you can see, this example is hard coded for an integer, and I will need to repeat these lines of code for every other data type if I want an array to contain that type of data. There has got to be a way to instantiate the struct so that the variable array can be a different data type so that I do not have to repeat all lines of code for every data type, but I am not sure what that method is. Any help would be appreciated. The code is shown below. NOTE: I also have a function to free the array memory after use, but I am omitting it since it is not relevant to the question.

array.h

#ifndef ARRAY_H
#define ARRAY_H

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

typedef struc
{
    int *array;
    size_t len;
    size_t size;
}Array;

void init_int_array(Array, size_t num_indices);
Array int_array(size_t num_indices);
void append_int_array(Array *array, int item);

#endif /* ARRAY_H */

Array.c

void init_int_array(Array *array, size_t num_indices) {
    /* This function initializes the array with a guess for
       the total array size (i.e. num_indices)
     */
    int *int_pointer;

    int_pointer = (int *)malloc(num_indices * sizeof(int));

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

Array int_array(size_t num_indices) {
    /* This function calls init_int_array to initialize
       the array and returns a struct containing the array
     */
    Array array;
    init_int_array(&array, num_indices);
    return array;
}

void append_int_array(Array *array, int item) {
    /* This function adds a data point/index to the array
       and also doubles the memory allocation if necessary
       to incorporate the new data point.
     */
    array->len  ;
    if (array->len == array->size){
        array->size *= 2;
        int *int_pointer;
        int_pointer = (int *)realloc(array->array, array->size * sizeof(int));

        if (int_pointer == NULL) {
            printf("Unable to reallocate memory, exiting.\n");
            free(int_pointer);
            exit(0);
        }
        else {
            array->array = int_pointer;
            array->array[array->len - 1] = item;
        }
    }
    else
    array->array[array->len - 1] = item;
}

CodePudding user response:

A simple solution is rewrite your header like this:

typedef struct
{
    void *array; // buffer
    size_t len;  // amount used
    size_t elem; // size of element
    size_t size; // size of buffer
} Array;

void init_array(Array *, size_t num_indices, size_t elem);
Array array(size_t num_indices, size_t elem);
void append_array(Array *array, void *item);

The changes to your code would be as follows:

  1. Remove references to int in the name.
  2. Make all inputs be to arbitrary type using void *.
  3. Use array.elem instead of sizeof(int).
  4. The biggest change is that elements to append will be passed by pointer, not by value.
  5. Cast the buffer to whatever type you need to access elements.
  6. Cast the buffer to char * internally to do pointer math on it.

CodePudding user response:

C is a strongly- and statically-typed language without polymorphism, so in fact no, there is no language-supported form of dynamic typing. Every object you declare, every function parameter, every struct and union member, every array element has a specific type declared in your source code.

Some of the things you can do:

  • use a typedef or a preprocessor macro to provide indirection of the data type in question. That would allow you to have (lexically) one structure type and one set of support functions that provide for your dynamically-adjustable array to have any one element type of the user's choice, per program.

  • use preprocessor macros to template the structure type and support functions so that users can get separate versions for any and all element types they want. This might be usefully combined with _Generic selection.

  • define and use a union type for use as the array's element type, allowing use of any of the union's members' types. With a little more work, this can be made a tagged union, so that objects of different types in the same array could be supported. The cost, however, is wasted space and worse memory efficiency when you use members having smaller types.

  • use void * or maybe uintmax_t or unsigned char[some_largish_number] as the element type, and implement conversions to and from that type. This has some of the disadvantages of the union alternative, plus some complications surrounding the needed conversions. Also, there is no type that can be guaranteed large enough to accommodate all other data types. Nor even all built-in data types, though this is a more realistic goal.

  • use void as the formal element type (possible only with dynamic allocation and pointers, not with an array-style declaration). Add a separate member that recoirds the actual size of the elements. Implement wrappers / conversions that support use of that underlying structure in conjunction with various complete data types. This is described in more detail in another answer.

  • Related