Используя гетерогенный массив в C - PullRequest
0 голосов
/ 22 сентября 2019

Я ищу использовать массив с несколькими типами - строки и числа (int).Вот что у меня есть:

int main(int argc, char *argv[]) {

    int number = 2;
    void * array[] = {"helo", &number, "watkins"};
    int array_len = sizeof(array)/sizeof(array[0])

    for (int i=0; i<array_len; i++) {
        void *value = array[i];

        // how to do this in C?
        if (type(value) == char)
            printf("The string is: %s", value);
        else
            printf("The number is: %d", value);

    }

}

Как мне проверить тип или сделать что-то эквивалентное в C?

Ответы [ 2 ]

2 голосов
/ 22 сентября 2019

Мне нравится ответ Нейта, так что не меняйте свой выбор, но есть небольшая вариация с использованием анонимного объединения, которое позволит вам обращаться к членам союза напрямую, без необходимости использовать тег объединения дляссылка на элемент.

Это было введено со стандартом C11 в 6.7.2.1 Спецификаторы структуры и объединения (p13) .Это просто обеспечивает немного синтаксического сокращения.Например, используя анонимный союз в структуре, например,

typedef struct {    /* struct containing tag and union between int/char[] */
    int tag;
    union {                 /* anonymous union allow you to refer  */ 
        char str[MAXC];     /* to members as members of the struct */
        int number;
    };
} mytype;
...
    mytype array[] = {{ISSTR, {"helo"}}, {ISINT, {{2}}}, {ISSTR, {"watkins"}}};

Ваш доступ к членам объединения будет:

            printf ("The string is: %s\n", array[i].str);

или

            printf ("The number is: %d\n", array[i].number);

(снет тега объединения между array[i] и str или number)

Если поместить его в целом, ваш пример будет:

#include <stdio.h>

#define MAXC 16     /* if you need a constant, #define one (or more) */

enum { ISSTR, ISINT };  /* enum can provide global constants as well */

typedef struct {    /* struct containing tag and union between int/char[] */
    int tag;
    union {                 /* anonymous union allow you to refer  */ 
        char str[MAXC];     /* to members as members of the struct */
        int number;
    };
} mytype;

int main (void) {

    mytype array[] = {{ISSTR, {"helo"}}, {ISINT, {{2}}}, {ISSTR, {"watkins"}}};
    int array_len = sizeof array/sizeof *array;

    for (int i=0; i<array_len; i++) {
        // how to do this in C?
        if (array[i].tag == ISSTR)      /* if tag ISSTR element is string */
            printf ("The string is: %s\n", array[i].str);
        else if (array[i].tag == ISINT) /* if ISINT, element holds an int */
            printf ("The number is: %d\n", array[i].number);
        else
            fputs ("As Nate put it, things are horribly wrong...\n", stderr);
    }
}

Пример использования / вывода

$ ./bin/structunion
The string is: helo
The number is: 2
The string is: watkins

Имейте в виду, что это было введено в C11, в C99 вы не найдете анонимную структуру или анонимное объединение (хотя некоторые компиляторы предоставили в качестве расширения)

2 голосов
/ 22 сентября 2019

Эта функция не существует в C на уровне языка.Если вы хотите что-то подобное, вы должны создать это самостоятельно.Таким образом, ваши элементы массива должны иметь тип, который может содержать любой тип объекта, такой как структура или объединение.Кроме того, ваш код должен отслеживать, какой тип какой - язык не сделает это за вас.

Таким образом, один из подходов будет выглядеть примерно так:

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

enum my_type { IS_STRING, IS_INTEGER };

struct my_multitype {
    enum my_type t;
    union {
        char *s;
        int n;
    } u;
};

int main(int argc, char *argv[]) {

    struct my_multitype array[] =
        {
         { IS_STRING, { .s = "helo" } },
         { IS_INTEGER, { .n = 2 } },
         { IS_STRING, { .s = "watkins" } }
        };

    int array_len = sizeof(array)/sizeof(array[0]);

    for (int i=0; i<array_len; i++) {
        switch (array[i].t) {
        case IS_STRING:
            printf("The string is: %s\n", array[i].u.s);
            break;
        case IS_INTEGER:
            printf("The number is: %d\n", array[i].u.n);
            break;
        default:
            printf("Something is horribly wrong\n");
            abort();
            break;
        }
    }
}

Обратите внимание, чтомы используем обозначенные инициализаторы для инициализации правильного члена объединения в каждом случае.

Вы также можете использовать void *, как вы пытались, но тогда вы должны сохранить информацию о типе вотдельный массив или что-то, и это неудобно.Также неудобно инициализировать массив таких вещей, опять же, как вы видели с целым числом, где вам пришлось вводить вспомогательную переменную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...