//Prints out a given array template void print(T t) { for(int i = 0; i < t.size(); i++) { cout << t[i] << " "; } cout << endl; }
У меня есть идея, но она включает в себя передачу размера массива. Можно ли это избежать?
* Обновление Спасибо за все ответы / идеи, но эта проблема идет глубже, чем мой snorkeler может справиться. Я хотел переписать свой C ++-код на C, потому что он был ужасно написан и медленным. Теперь я вижу, что у меня есть возможность сделать это еще хуже в C. Я перепишу его с нуля в Python (исполнение будет проклято). еще раз спасибо
Если у вас нет ЭЛЕМЕНТОВ, это
#define ELEMENTS(a) (sizeof(a)/sizeof(*a))
Затем,
#define print_array(a, specifier) print_array_impl(a, specifier, ELEMENTS(a), sizeof(*a)) void print_array_impl(void* a, char* specifier, size_t asize, size_t elsize) { for(int i = 0; i < asize; i++) { // corrected based on comment -- unfortunately, not as general if (strcmp(specifier, "%d") == 0) printf(specifier, ((int*)a)[i]); // else if ... // check other specifiers printf(" "); } printf("\n"); }
Используйте это
print_array(a, "%d") // if a is a int[]
и, должно быть имя массива, а не указатель (иначе ELEMENTS не будет работать)
Вы не можете знать, что такое размер массива, не передавая размер этого массива (кроме работы с sizeof
в статических массивах). Это связано с тем, что указатель на блок памяти будет указывать только на базу блока памяти, из которого вы можете узнать, где начинается массив / блок памяти, но поскольку нет определенного конца, вы не можете определить, где он будет конец.
Вы либо должны установить свою собственную длину для каждого массива, и сохранить ее, и использовать ее с массивом, как описано:
struct _my_array { typename arr [MAX]; int n; } my_array;
ИЛИ ЖЕ
struct _my_array { typename * arr; int n; } my_array;
В этом случае вам необходимо динамически выделять блок памяти с помощью new
или malloc
, а когда закончите освобождать память с помощью delete
или free
(соответственно).
Другой способ – использовать специальное значение терминатора вашего типа массива, которое, если оно будет определено, будет определено как конец массива. В этом случае вам не нужно сохранять размер. Например, строка '\0'
завершена, поэтому все строковые функции знают, что когда символ '\0'
встречается в массиве char
он будет считать, что строка имеет конец.
ОБНОВИТЬ
Поскольку это общая функция, и массив может быть любого типа, одна вещь, которую вы можете сделать, выглядит так:
struct _my_generic_arr { void *arr; int n; int type; } my_generic_arr;
При заполнении этого массива вы можете использовать любой тип. Чтобы определить, какой тип, передайте идентификатор в компоненте type
. Каждое уникальное значение определяет, к какому типу на самом деле указывает указатель arr
(на самом деле это был намеченный тип). n
определит длину. Теперь, в зависимости от разных значений type
создайте switch - case
или лестницу if - else
или гнездо и обработайте массив по мере необходимости.
Невозможно в c отслеживать размер массива в другом блоке. Лучше было бы передавать размер массива вдоль.
Другой вариант – объявить глобальную переменную, имеющую размер и использующую эту переменную внутри функции Eg ,,
int size= void main() { int arr[]; } void print(T t) { for(int i = 0; i < size; i++) { printf("%d ",t[i]) //assuming T as int } printf("\n"); }
В C вам нужно будет передать два дополнительных параметра: размер массива (как вы упомянули) и некоторый способ указания того, как преобразовать t [i] в строку. Чтобы преобразовать t [i] в строку, вы можете создать пользовательский оператор switch для декодирования возможных типов, передать указатель на функцию, которая вернет указатель строки, или вы можете передать спецификатор формата printf (например, «% d» для целое число).
Проблема больше, чем вы думаете. Если у вас есть массив размером 12, как вы знаете, какие данные хранятся в этом массиве? Это может быть 3 char * (на 32-битной системе), 3 int32_t или даже 12 символов. У вас нет способа узнать, как интерпретировать данные. Лучшее, что вы можете сделать, это реализовать собственную версию v-таблицы и поместить в нее функцию print или toString.
typedef struct { void *array; size_t length; int element_width; printer_t to_string; } container;
printer_t
– это тип, который описывает указатель на функцию, который принимает указатель на элемент и возвращает строку (или печатает ее, если вы не хотите free
строку). Это почти никогда не стоит делать в C. Это не значит, что это невозможно. Однако я хотел бы подчеркнуть, что ничто из этого не означает, что это должно быть сделано.
Сама функция будет выглядеть примерно так:
void print(container *thing) { size_t offset; int width; char *stringified; width = thing->element_width; for (offset = 0; offset * width < thing->length; offset += width) { stringified = thing->to_string(thing->array + offset); printf("%s ", stringified); free(stringified); } }
То, что это делает, по существу превращает структуру в class faux с указателем функции для метода. Вы можете быть более объектно-ориентированными и помещать метод в напечатанный тип и сделать его массивом из них. В любом случае, это не очень хорошая идея. C для записи C. Если вы попытаетесь написать на другом языке, вы получите всевозможные ужасные вещи, подобные этому.