2013-07-16 16 views
5

Jestem stosunkowo nowy w języku programowania C, i staram się dowiedzieć, jak utworzyć funkcję, która może przyjmować różne typy danych jako parametry. Funkcja ma liczyć i zwracać liczbę elementów w tablicy znaków lub liczb całkowitych. Mam już dwie osobne funkcje, które to wykonają, ale naprawdę chciałbym móc użyć jednej funkcji dla obu zadań. Czy jest sposób, aby to zrobić w C?Utwórz funkcję C, która akceptuje parametry różnych typów danych

Z góry dzięki!

Odpowiedz

5

Nie ma przeciążenia funkcji standardowej w C (nie ma też szablonów), ale prawdopodobnie można zajrzeć do funkcji "podobnych do drukowania" (lub variadic functions) i być może mogą one zrobić to, czego potrzebujesz. Jeśli cokolwiek, pozwalają na elastyczną listę parametrów.

Istnieje przykład takiej funkcji, która pobiera tablicę liczb całkowitych o zmiennej wielkości.

Może masz podpis funkcji, takiej jak void iterate(const char* format, ...); które można wykorzystać w następujący sposób:

iterate("char", some_char_array); // for char arrays/strings 

Albo

iterate("int", some_int_array); // for integer arrays 

Aniket sprawia, że ​​dobry punkt jednak, w jaki sposób liczyć Państwo elementy w tablicy całkowitej? Jeśli przekażesz tablicę int jako argument, musisz również przekazać rozmiar, który pokonuje cel liczenia elementów w tablicy (jak już wiesz, że to jest rozmiar).

Zakładam, że nie znasz rozmiaru, ale masz wartość terminatora w tablicy (np. -1).

Zrobiłem coś szybko, robiąc to, czego potrzebujesz, mając na uwadze powyższe założenie.

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

int iterate(const char* format, ...) 
{ 
    va_list ap; 
    va_start(ap, format); 

    if (strcmp(format, "char") == 0) 
    { 
     char* array = va_arg(ap, char*); 

     return strlen(array); 
    } 
    else if (strcmp(format, "int") == 0) 
    { 
     int j = -1; 
     int* int_array = va_arg(ap, int*); 
     while (int_array[++j] != -1) 
        ;  
     return j; 
    } 
    return 0; 
} 

int main() 
{ 
    printf("%d\n", iterate("char", "abcdef")); 
    int arr[] = {5, 4, 3, 2, 1, 0, -1}; 
    printf("%d\n", iterate("int", arr)); 

    return 0; 
} 

Drukuje:

$ ./a.out 
6 
6 
+0

co to jest "rozmiar int"? –

+0

Rozmiar tablicy? Wyjaśnię to, ponieważ wydaje się to nie być jasne. – Nobilis

+0

cóż, jeśli zna rozmiar tablicy przed ręką, dlaczego użyje super takiej funkcji, aby automatycznie wnioskować o typie i wywołać odpowiednią funkcję do obliczenia długości tablicy? :-) –

1

Powinieneś sprawić, aby argumenty funkcji przyjmowały typ void *. W ten sposób możesz przekazać różne typy danych i wpisać je do tego, który chcesz. Trzeba jednak uważać, ponieważ nie ma zagwarantowanego sposobu prawidłowego odgadnięcia typu, który wskazuje na void*.

2

W obu przypadkach trzeba będzie jakiś system typu wnioskowania, aby poinformować kompilator C, który funkcję, aby zadzwonić. Co oznacza, że ​​będziesz musiał wcześniej znać rodzaj tablicy, którą możesz wysłać jako parametr tej "superfunkcyjnej" twojej.

W języku C nie ma "automatycznego wywołania typu", które pozwala na zastanowienie się nad typem danych w czasie wykonywania. Co więcej, być może trzeba będzie napisać własne środowisko uruchomieniowe.

Nieco trywialne hackish sposobem, aby to zrobić:

#include <stdio.h> 

size_t GetLengthOfArray(size_t sizeOfOneElementInArray, size_t sizeOfTheArrayInBytes) 
{ 
    return sizeOfTheArrayInBytes/sizeOfOneElementInArray; 
} 
int main(int argc, char *argv[]) 
{ 
    char cArr[10] = {'A','B','C','D','E','F','G','H','I','J'}; 
    int iArr[5] = {10,20,30,40,50}; 
    printf("%d is the length of cArr\n%d is the length of iArr",GetLengthOfArray(sizeof(cArr[0]),sizeof(cArr)), 
                   GetLengthOfArray(sizeof(iArr[0]),sizeof(iArr))); 
    return 0; 
} 
+0

C11 ma "_Generic". – jxh

2

Więc załóżmy swoje dwie funkcje są nazywane sizeof_char_array i sizeof_int_array.

W C11, pojawiła się nowa funkcja o nazwie „generic wybór”, który pozwoli Ci zrobić to, co chcesz ze stosunkowo prostego makra:

#define sizeof_array(X) \ 
    _Generic (*(X), \ 
       char: sizeof_char_array, \ 
       default: sizeof_int_array) (X) 

(ja nie mam nawet wdrożenie C11 do przetestowania to przeciwko, więc uwaga opór!)

Przed C11, czasami było to realizowane za pomocą makra używającego regularnie nazwanych funkcji. Można zdefiniować makro, które będzie zadzwonić jedną funkcję lub inny w zależności od skali makro argumentu podpowiedź:

#define sizeof_array(xtype, x) sizeof_ ## xtype ##_array(x) 

int a[] = { 1, 2, 3, 4, -1 }; 
char b[] = "abc"; 

sizeof_array(int, a); /* macro expands to sizeof_int_array(a) */ 
sizeof_array(char, b); /* macro expands to sizeof_char_array(b) */ 

Jeśli argument wejściowy jest naprawdę tablicą, można użyć makra, aby obliczyć swój rozmiar bezpośrednio:

#define ARRAY_SZ(x) (sizeof(x)/((void *)x == &x ? sizeof(x[0]) : 0)) 

W przypadku tablicy następujące wyrażenie jest spełnione:

(void *)arr == &arr 

Ponieważ adres tablicy ma takie samo położenie w pamięci jako adres jej pierwszym elementem.

Tak więc makro oblicza: sizeof(arr)/sizeof(arr[0]). Ponieważ operator sizeof zgłasza rozmiar w bajtach swojego argumentu, obliczone wyrażenie powoduje liczbę elementów w tablicy. Jeśli jednak do obliczenia długości używany jest wskaźnik, makro ARRAY_SZ spowoduje, że rozmiar będzie większy niż długość znaleziona przez tablicę dla sentinela.

W przypadku, gdy argument nie jest tablicą, wyrażenie powoduje dzielenie przez wyjątek 0.

+0

mówiąc ściśle :-P, OP chce wywoływać dwie różne funkcje z jednej funkcji w zależności od rodzaju danych, które posiada wskaźnik. –

+0

Sądzę, że chce jakiegoś systemu inferencyjnego. Tylko moja myśl na ten temat. –

+0

@Aniket: Nie ma to dla mnie większego sensu, ponieważ nie można wywnioskować długości tablicy po przekazaniu jej do funkcji. Długość tablicy musi zostać przekazana do funkcji (chyba, że ​​wnioskowanie odbywa się za pomocą wartości wartownika). – jxh

2

Odpowiedź jest dość prosta. Do wykonania tego zadania potrzebna jest funkcja. Po prostu wypróbuj ten kod

#define len(array) sizeof(array)/sizeof(array[0]) 

i to wszystko.

Powiązane problemy