R
R
Roman Isadchenko2018-06-30 23:04:32
C++ / C#
Roman Isadchenko, 2018-06-30 23:04:32

Working with different data types in C?

Write in C language an implementation of an abstract data type - a "polymorphic" collection based on a dynamic array. The data structure must support working with elements of various types (generally speaking, arbitrary, if they satisfy certain conditions).
- Integers -
Real numbers -
Complex numbers
I can't figure out how to organize work with different types in C

Answer the question

In order to leave comments, you need to log in

4 answer(s)
V
Vitaly, 2018-07-01
@ZUBlK

You can use the good old way: a structure with two fields: enum and union. Union can be read differently depending on the value of the enumeration.
Well, or void *, instead of union. Or your vtable implementation.

D
Denis Zagaevsky, 2018-07-01
@zagayevskiy

Here, IMHO, there is only one option. void*

W
Wundarshular, 2018-07-01
@Wundarshular

Generally speaking, the set of complex numbers includes real numbers, and those, in turn, include integers. A complex number is a number of the form "a+bi", where a is the real part expressed as a real number, b is the coefficient of the imaginary part expressed as a real number, i = the imaginary unit.
Based on this, you can try to use an array of structures, where each element is a structure that expresses a complex number. For real numbers, the fields b and i will be equal to zero, for integers, when calculating, the fractional part will have to be ignored.

4
4rtzel, 2018-07-01
@4rtzel

There are many ways to implement a polymorphic collection in C, and each implementation has its pros and cons. The most popular and simplest of them is probably through void*. Although it is suitable for most cases, it still has the disadvantage of inconsistent data layout in memory and type safety. So here are a couple more possible implementations that might suit you better:
By stuffing the entire implementation of an array into a macro, you can declare the necessary, type-safe arrays if necessary.

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

#define ARRAY_DECLARE(type) \
struct array_##type {       \
    size_t size;            \
    size_t capacity;        \
    type* data;             \
};                          \
\
struct array_##type* array_##type##_create(size_t init_cap) {       \
    struct array_##type* self = malloc(sizeof(struct array_##type));\
    self->capacity = init_cap;                                      \
    self->data = calloc(init_cap, sizeof(type));                    \
}                                                                   \
\
void array_##type##_push_back(struct array_##type* self, type value) {  \
    if (self->size == self->capacity) {                                 \
        type* temp = calloc(self->size + 1, sizeof(type));              \
        memmove(temp, self->data, self->size * sizeof(type));           \
        free(self->data);                                               \
        self->data = temp;                                              \
    }                                                                   \
    self->data[self->size++] = value;                                   \
}

ARRAY_DECLARE(int);
ARRAY_DECLARE(float);

int main(void) {
    struct array_int* iarr = array_int_create(1);
    array_int_push_back(iarr, 42);
    array_int_push_back(iarr, 1337);
    for (int i = 0; i < 2; ++i) {
        printf("%d\n", iarr->data[i]);
    }

    struct array_float* farr = array_float_create(1);
    ...
    return 0;
}

Through "inheritance".
/* Где-то в array.h */
struct array {
    size_t size;
    size_t capacity;
    void* data;

    void (*push_back)(struct array* self, void* value);
    void* (*get)(struct array* sefl, size_t index);
};

/* Где-то в arra_int.h */
void array_int_push_back(struct array* self, void* value) {
    if (self->size == self->capacity) {
        int* temp = calloc(self->size + 1, sizeof(int));
        memmove(temp, self->data, self->size * sizeof(int));
        free(self->data);
        self->data = temp;
    }
    int* int_data = (int*)self->data;
    int_data[self->size++] = *(int*)value;
}
void* array_int_get(struct array* self, size_t index) {
    return ((int*)self->data) + index;
}
struct array* array_int_create(size_t init_cap) {
    struct array* self = malloc(sizeof(struct array));
    self->push_back = array_int_push_back;
    self->get = array_int_get;
    self->capacity = init_cap;
    self->data = calloc(init_cap, sizeof(int));
    return self;
}

int main(void) {
    struct array* arr = array_int_create(1);
    int value = 42;
    arr->push_back(arr, &value);
    value = 1337;
    arr->push_back(arr, &value);
    for (int i = 0; i < 2; ++i) {
        printf("%d\n", *((int*)arr->get(arr, i)));
    }
    return 0;
}

You can also pay attention to the new _Generic keyword .
All the code above is for demonstration purposes only and certainly contains bugs :) I
also advise you to look at how such structures are implemented in large projects:
1. Glib
2. Linux
3. Postgres
4. There are plenty of other links on the Internet.
I hope this will help you choose the right implementation for your task.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question