Работа с различными типами данных в си?

Написать на языке C реализацию абстрактного типа данных – «полиморфной» коллекции на основе динамического массива. Структура данных должна поддерживать работу с элементами различных типов (вообще говоря, произвольных, если они удовлетворяют некоторым условиям).
-Целые числа
-Вещественные числа
-Комплексные числа
Вот немогу понять как организовать работу с различными типами на си
  • Вопрос задан
  • 548 просмотров
Решения вопроса 1
vt4a2h
@vt4a2h
Senior software engineer (C++/Qt/boost)
Можно старый добрый способ: структура, в которой два поля: enum и union. В зависимости от значения перечисления можно по разному читать union.
Ну или void*, вместо union. Или свою реализацию vtable.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
zagayevskiy
@zagayevskiy
Android developer at Yandex
тут, имхо, только один вариант. void*
Ответ написан
Комментировать
@Wundarshular
Обобщённо говоря, множество комплексных чисел включает в себя вещественные числа, а те, в свою очередь, включают в себя целые. Комплексное число - это число вида "a+bi", где а - действительная часть, выраженная вещественным числом, b - коэффициент мнимой части, выраженный вещественным числом, i = мнимая единица.
Исходя из этого, можно попробовать использовать массив структур, где каждый элемент, это структура, выражающая собой комплексное число. У вещественных чисел поля b и i будут равны нулю, у целых, при вычислении, придётся игнорировать дробную часть.
Ответ написан
Комментировать
@4rtzel
Существует множество способов реализации полиморфной коллекции на С и у каждой реализации есть свои недостатки и достоинства. Самый популярный и простой из них, наверно, через void*. Хотя он и подходит для большинства случаев он всё же имеет недостаток в виде непоследовательного размещения данных в памяти и типобезопасности. Так что вот ещё парочка возможных способов реализации, которые могут подойти вам лучше:

Запихнув всю реализацию массива в макрос можно объявлять необходимые, типобезопасные массивы при необходимости.
#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;
}


Через "наследование".
/* Где-то в 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;
}


Ещё можно обратить внимение на новый _Generic keyword.
Весь код выше приведён только в целях демонстрации и, безусловно, содежрит баги :)

Также советую посмотреть как реализованы такие структуры в крупных проектах:
1. Glib
2. Linux
3. Postgres
4. Другие ссылки в интернете коих полно.

Надеюсь это вам поможет выбрать подходящую реалзизацию для вашей задачи.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы