Каков наилучший способ переписать эту общую функцию, которую я написал в C ++ в C?

//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. Если вы попытаетесь написать на другом языке, вы получите всевозможные ужасные вещи, подобные этому.