Summe der Elemente eines Arrays von einem beliebigen ganzzahligen Datentyp
-
Hallo zusammen,
ich will ein C-Programm schreiben, das die Elemente eines Arrays summiert, wobei diese einen beliebigen ganzzahligen Datentyp (alles von char bis long long) haben sollen.
Und genau darin liegt auch mein Problem: Wenn ich ein Array mit fixem Datentyp hätte, wäre das ganze relativ einfach:int summe (int v [], int laenge) { int i, rueckgabe = 0; for (i=0 ; i < laenge ; i++) { rueckgabe += v[i] ; } return rueckgabe ; }
Aber wie muss ich das verändern, damit man auch andere ganzzahlige Datentypen eingeben kann? Hat da jemand nen Tipp für mich?
-
Generische Funktionen in C, Alptraum aller Programmierer. Sicher, dass du nicht lieber C++ machen möchtest? :p
Nun, die zwei Grundprinzipien sind:
1. Makros
Nachteile: Fehleranfällig (Makroprobleme); umständlich zu benutzen; erstellen keine echte Funktion (außer du schreibst ein Makro eben dafür)2. void-Zeiger
Nachteile: Fehleranfällig (hebeln Typensystem aus); umständlich zu benutzen; Code ist oft langsamer als ein spezialisierter Code (wie zum Beispiel der durch Makros erzeugte)Du hast also die Wahl zwischen zwei nicht so tollen Alternativen (ist dir bekannt, wie die jeweils ungefähr aussehen würden?). Normalerweise würde ich eher zu den void-Zeigern neigen. Bei deinem Problem jedoch stellen sich so Fragen, wie von welchem Typ der Rückgabewert überhaupt sein soll, welche sich leichter mittels Makros klären lassen.
-
Da ich nicht weiß, was Makros sind, würde es wohl auf die Zeiger hinauslaufen. Damit hatte ich auch schon etwas herumprobiert, da mir bekannt ist, dass man z.B. einen void-Zeiger verwenden könnte, da dieser im Prinzip auf einen beliebigen Datentyp zeigen kann. Das Problem dabei ist allerdings, dass man mit einem void-Zeiger weder Zeigerarithmetik betreiben noch ihn dereferenzieren kann. Daher hat mich das nicht sonderlich weit gebracht...
-
Du musst es so machen wie die Funktionen aus der Standardbibliothek, also zum Beispiel qsort. Das heißt du musst alle Aktionen vom Benutzer programmieren lassen, dein Algorithmus arbeitet dann ganz abstrakt mit Funktionszeigern; Längen- und Größenangaben; und den void-Zeigern.
Wenn dein Kenntnisstand noch nie etwas von Makros gehört hat: Vermutlich übersteigt dann auch die void*-Variante dein Können derzeit noch bei weitem und du solltest dich zuerst einmal an etwas einfacherem üben. Das Thema ist schon ganz schön schwierig und man kann bei allen Varianten sehr leicht sehr viel falsch machen und es ist jeweils auch sehr schwer, die Fehler zu finden und zu analysieren.
-
Habs eben nochmal versucht, indem ich einen void-Zeiger verwende, und in der Funktion die Breite des eingesetzten Datentyps anfrage (1 char, 2 short, 4 int, 8 long long) und dann vier if-Abfragen durchführe und jeweils den Zeiger entsprechend caste, dann funktioniert das ganze anscheinend (obwohl der Compiler ne Warnung wegen inkompatibler Zeigertypen ausgibt...). Meine Frage dürfte sich damit erledigt haben - danke für den Denkanstoß.
-
Du kannst auch gleich fünf Funktionen schreiben (für char, short, int, long und long long) und diese aus einer sechsten entsprechend aufrufen.
-
Lithiesque schrieb:
ich will ein C-Programm schreiben, das die Elemente eines Arrays summiert, wobei diese einen beliebigen ganzzahligen Datentyp (alles von char bis long long) haben sollen.
Und genau darin liegt auch mein Problem: Wenn ich ein Array mit fixem Datentyp hätte, wäre das ganze relativ einfach:da gibts kein problem.
nimmsu long long, da passt alles rein: char, int, long, ... longer, .... long long.
-
int generic_sum (const void *base, size_t nmemb, size_t size) { size_t len = nmemb * size; const unsigned char *arr = base; int sum = 0; for (size_t i = 0; i < len; i++) { sum += arr[i] << (CHAR_BIT * (i%size)); } return sum; }
Nicht wirklich portabel, nicht wirklich getestet, nicht wirklich ernst gemeint.
-
...
-
void sum(void* result, void const *array, size_t arrCount, size_t elemSize, void(*pAddFunc)(void* r,void const* a,void const* b));
Aber das Makro klingt irgendwie viel verlockender.
#include <stdio.h> #define SUMME(rueckgabe,v,laenge)\ {\ int i;\ rueckgabe=0;\ for (i=0 ; i < laenge ; i++)\ {\ rueckgabe += v[i] ;\ }\ } int main(){ int arr[5]={1,3,5,7,9,}; long summe; SUMME(summe,arr,5); printf("%ld",summe); return 0; }
-
volkard schrieb:
void sum(void* result, void const *array, size_t arrCount, size_t elemSize, void(*pAddFunc)(void* r,void const* a,void const* b));
Naja, das sieht schlimmer aus als es ist.
void accumulate(const void *base, size_t nmemb, size_t size, void* init, void (*acc)(void *, const void *)){ register char *base_ptr = (char *) base; while(nmemb--){ acc(init, base_ptr); base_ptr += size; } } void acc(void *x, const void *y){ *(int *)x += *(int *)y; } void f(){ int arr[] = { 0,1,2,3,4,5,6,7,8,9 }; size_t N = sizeof(arr) / sizeof(*arr); int result = 0; accumulate(arr, N, sizeof(*arr), &result, acc); }
-
Für sowas wären die C11 type generic macros super.
-
Was besseres als void * und dann beim Aufsummieren ein entsprechender cast nach long long fällt mir dazu allerdings auch nicht ein. Eine unschöne Aufgabenstellung mit den Bordmitteln von C...
-
Generische Programmierung ist noch unhandlicher als in C++. Warum also? Definiere die Funktion, die du brauchst! Loesungen mittels void* etc. sind schlecht im Hinblick auf Performance, da sie alles an Typinfomationen wegschmeisst, die der Compiler verwerten koennte.
-
Mir stellt sich die Frage, welche Anwendungsfälle es für eine "Addition mit unbestimmtem Typ" gibt? Mir ist das noch nicht untergekommmen
Vielleicht eine mathematische Bibliothek...
Vielleicht sollte man auch mal hinterfragen, warum der TE das braucht. Im C++-Bereich hätte man dem TE zunächst einmal konzeptionelle Fehler unterstellt, mal abgesehen davon, dass die hier vorgegebene Aufgabe natürlich in C++ kein Problem darstellt
-
Der Typ ist ja nicht unbestimmt, sondern soll variabel sein
Ein Anwendungsfälle wäre z.B. in der Messdatenverarbeitung.
Du bekommst von Messgeräten die Daten in verschiedenen Typen. z.B vom ADC als 16-Bit (auch wenn er nur 10-Bit Auflösung hat) oder Längenmessung mit 32-Bit oder ...Dann hast du nur eine Funktion die die Berechnung macht.
-
Für gängige int-Bytegrößen baust du dir für den Elementzugriff ein Makro und fertig.
#define iptr(i,a,n) (8==i?n[(long long*)a]:4==i?n[(long*)a]:2==i?n[(short*)a]:n[(char*)a]) long long summe(const void *a,size_t s,size_t n) { long long r=0; assert( (s&15) == s ); while(n--) r+=iptr(s,a,n); return r; } int main() { char a1[3]={-1,0,+4}; short a2[3]={-4,0,+1}; long a3[3]={-3,0,+1}; long long a4[3]={-1,0,+3}; long long r = summe(a1,sizeof*a1,3)+summe(a2,sizeof*a2,3)+summe(a3,sizeof*a3,3)+summe(a4,sizeof*a4,3); assert( r == 0 ); }
-
Wutz schrieb:
#define iptr(i,a,n) (8==i?n[(long long*)a]:4==i?n[(long*)a]:2==i?n[(short*)a]:n[(char*)a])
das ist ein stümperhaftes müll makro mit undefinded behaviour.
-
Ist ja mal total panne die Typentscheidung in der Schleife zu machen.
-
#define GENERIC_SUMMATION(arrayptr, type, count, sum) { \ int i; \ sum = 0; \ for ( i = 0; i < count; i++ ) \ sum += *((type*)arrayptr + i); \ } int main ( void ) { int array[] = {1,2,3}, sum; GENERIC_SUMMATION (array, int, sizeof(array)/sizeof(array[0]), sum); printf ( "%d", sum ); return 0; }