Hallo Community, ich habe mich im Moment mit Listenprogrammierung in C beschäftigt. Dabei habe ich mich bis jetzt immer auf eine Liste beschränkt. Jetzt, da ich gerne etwas komplexere Übungen machen möchte, steh ich vor folgendem Problem: Wenn ich mit verschiedenen structs arbeite, müsste ich mit meinem aktuellen Wissensstand für jede Liste eine extra Funktion schreiben, um ihre Elemente zu bearbeiten(Add, delete, Show, usw...), da die verschiedenen Listen i.d.R. aus verschiedenen Datentypen bestehen. Gibt es eine Möglichkeit, für verschiedene Listen jeweils eine Funktion für die bereits erwähnten Bearbeitungen, zu schreiben? Also jeweils eine Funktion für das Hinzufügen von Listenelementen, eine zum Löschen, usw. Meine Idee wäre, einer Funktion einen Typunabhängigen Pointer auf den Anfang einer Liste zu übergeben. Wenn nun ein definierter Zusammenhang der Adressen zwischen struct-Typ und Listen-TypEN besteht, kann ich mir doch ohne Probleme über nen Algorithmus alle Datentypen nacheinander abfragen, oder?! Ob diese Idee so umsetzbar ist und ob es keine bzw. eine einfachere Lösung gibt, weiß ich nicht. Deswegen an euch nun die Frage, ob es möglich ist und wie es i.d.R. umgesetzt wird, bzw. wie ihr es umsetzen würdet. Vielen Dank schon mal!
U.a. deswegen gibt es C++, dort kann man das nämlich mit templates sauber und sicher (ohne gefährliche casts) machen. Die Standard Bibliothek enthält sogar bereits Listen und andere solche Daten Strukturen, aber es ist eine sehr gute Übung die selber zu implementieren. m.M.n. lohnt es wenig, das in C zusammen zu fummeln wenn man das in C++ auch richtig machen kann. In C kann man sich mit Makros behelfen, oder als Listenelement Typ immer void* nutzen und beim Zugriff immer umcasten. Rogerger92 schrieb: > Wenn nun ein definierter Zusammenhang der Adressen zwischen struct-Typ > und Listen-TypEN besteht, kann ich mir doch ohne Probleme über nen > Algorithmus alle Datentypen nacheinander abfragen, oder?! In C ist so etwas aber nicht definiert, und daher nicht erlaubt (obwohl es meistens vermutlich funktioniert) .
Warum brauchst du mehr als ein Listen Type? Der Trick hier ist eine generische Liste zu schreiben und dann die Konkreten Datentypen da einzuhängen. Im Trivialfall schreibst du dir eine Liste mit einen Pointer auf void und hängst an den void Pointer die jeweiligen Daten, der C Standard garantiert dir das du jeden Pointer zu void * und zurück casten kannst ohne Eigenschaften zu verlieren.
1 | struct dlist { |
2 | struct dlist *next; |
3 | struct dlist *prev; |
4 | void *ctx; // hier ein Pointer auf deine Struktur dranhängen. |
5 | }
|
die angerissen struct ist deine generische liste und an den ctx (context) hängst du nun einfach die jeweilige Struktur welche du brauchst. dann kannst du für die dlist alle möglichen Operationen bereitstellen und musst die Liste nur einmal Implementieren. Nachteil dieser Implementierung du kannst in die liste alles hängen und somit einfach Apfel mit Birnen vergleichen. Du musst also etwas beim Implementieren acht geben. Alternativ gibt es noch andere Möglichkeiten eine generische Listen zu erstellen, mir Persönlich gefällt die des Linux Kernel, aber die ist etwas Komplexer da sie mit C Makros und etwas Pointerarithmetik arbeitet und ist IMHO daher nicht für Anfänger zu empfehlen, obwohl sie sehr bequem zu benutzen ist.
Dr. Sommer schrieb: > U.a. deswegen gibt es C++, dort kann man das nämlich mit templates > sauber und sicher (ohne gefährliche casts) machen. Casts als solche sind nicht gefährlich. Sie sind nur dann gefährlich, wenn man einen Fehler bei ihrem Einsatz macht. Das gilt aber für praktisch jedes andere Sprachelement einer Hochsprache ganz genauso. Übrigens auch im RL: wenn man einem Dreijährigen eine Flex in die Hand drückt, wird eher selten was Gutes bei rauskommen. Also gib's für Dreijährigen eben besser nur Quietsche-Entchen... Aber: manche Leute werden irgendwann erwachsen und können dann eben auch mit einer Flex korrekt umgehen. Andere Leute bubbeln lieber bis in alle Eqigkeit mit ihrem Quietsche-Entchen... Wobei C++ im Rahmen dieses Vergleiches eher ein Quietsche-Entchen mit verstecker Flex mit nahezu unberechenbarem Schalter ist. Aber Hauptsache schön bunt und quietscht beim Bussy...
c-hater schrieb: > Dr. Sommer schrieb: > >> U.a. deswegen gibt es C++, dort kann man das nämlich mit templates >> sauber und sicher (ohne gefährliche casts) machen. > > Casts als solche sind nicht gefährlich. Sie sind nur dann gefährlich, > wenn man einen Fehler bei ihrem Einsatz macht. Autorennen ist an sich auch nicht gefährlich. Nur wenn man dabei in die Wand fährt, ist es gefährlich. Und wenn man von einem Turm springt, ist das auch völlig ungefährlich. Erst der Aufprall birgt eine gewisse Gefahr. > Aber: manche Leute werden irgendwann erwachsen und können dann eben auch > mit einer Flex korrekt umgehen. Die lernen aber auch, eine Flex nur dann zu benutzen, wenn man sie auch braucht und nicht z.B. um sich die Fingernägel zu schneiden, wenn dafür ein besser geeignetes Werkzeug zur Verfügung steht.
c-hater schrieb: > Casts als solche sind nicht gefährlich. Sie sind nur dann gefährlich, > wenn man einen Fehler bei ihrem Einsatz macht Genau so ist es. C++ templates und die davon ermöglichte Typsicherheit hilft einem, diese Fehler zu vermeiden, indem der Compiler die Typen überprüft und Fehler Meldungen ausgibt. Ohne diese Hilfe muss man diese Fehler durch Debuggen finden, was ganz schön lästig sein kann. Der perfekte Programmierer macht natürlich keine Fehler, aber die meisten sind eben nicht perfekt...
Der TO hat aber nach C gefragt. Ja C++ ist schoen und wenn man die Wahl hat eine gute Sache welche vieles leichter macht. Aber das ist Python auch nur wird das nie vorgeschlagen da es kein Ersatz fuer C ist. Aber jedesmal wenn hier jemand mit C kommt, fangt die Diskussion an nimm doch besser C++ wegen $TOLLES_FEATURE. Das mal kurz anzusprechen finde ich auch Okay, aber es kann Grunde geben warum der TO nach C fragt, sei es eine Legacy Codebase oder akademische. Denn TO ist jedenfalls nicht gehofen wenn bei jeden C Thread reflexartig die Antwort kommt nimm C++ das ist besser. Das ist Pyhthon auch und das kann duck typing, nur das nutz denn TO nicht bei sein C Problem.
> Das ist Pyhthon auch und das kann duck typing, nur das nutz denn TO > nicht bei sein C Problem. Doch: Python ist OpenSource UND in C implementiert - der TO kann also in den Quellcode von Python versinken und sehen wie es da gemacht ist.
Man kann auch einen generischen Strukturkopf definieren, den man dann wiederverwertet:
1 | struct item_data_t { |
2 | struct item_t *next; |
3 | struct item_t *previous; |
4 | };
|
5 | |
6 | struct item_t { |
7 | struct item_data_t item_data; |
8 | };
|
9 | |
10 | void insert(struct item_t *pos, struct item_t *item) { |
11 | item->item_data.next = pos; |
12 | /* ... */
|
13 | }
|
14 | |
15 | |
16 | |
17 | |
18 | struct mein_item_t { |
19 | struct item_data_t item_data; |
20 | |
21 | int mein_integer; |
22 | double mein_array[17]; |
23 | /* ... */
|
24 | };
|
25 | |
26 | |
27 | struct mein_item_t *a = malloc(sizeof(struct mein_item_t)); |
28 | struct mein_item_t *b = malloc(sizeof(struct mein_item_t)); |
29 | /* ... */
|
30 | insert(a, b); |
Das spart dann halt eine Indirektion. Die glib macht das ziemlich exzessiv so.
Nase schrieb: > struct mein_item_t { > struct item_data_t item_data; Setzt aber voraus dass die struct item_data_t item_data; immer als erstes in der Struktur definiert ist. Ansonsten geht der implizite cast (item_t) mein_item_t schief und du hast vermeintliche Pointer wild in den Speicher zeigen.
imonbln schrieb: > Nase schrieb: >> struct mein_item_t { >> struct item_data_t item_data; > > Setzt aber voraus dass die struct item_data_t item_data; > immer als erstes in der Struktur definiert ist. Ja natürlich, das ist ja auch der ganze Trick dabei.
Rogerger92 schrieb: > Wenn ich mit verschiedenen structs arbeite, müsste > ich mit meinem aktuellen Wissensstand für jede Liste eine extra Funktion > schreiben Nein, du musst gar keine Funktion schreiben. Du kannst einfach einen Befehl nach dem anderen ausführen. Es gibt sogar einen Geheimtip, der nennt sich for-loop, damit kannst du mit einem Statement die gesamte Liste bearbeiten. Ändere mal deinen Wissensstand und komm in 1-2 Jahren wieder. Viel Erfolg!
B. Stroustrup schrieb: > Ändere mal deinen Wissensstand und komm in 1-2 Jahren wieder. Du hast das Problem überhaupt nicht verstanden. Setzen, 6.
imonbln schrieb: > Der TO hat aber nach C gefragt. > > Ja C++ ist schoen und wenn man die Wahl hat eine gute Sache welche > vieles leichter macht. Aber das ist Python auch nur wird das nie > vorgeschlagen da es kein Ersatz fuer C ist. Genau, der TO hat nach C gefragt - und er hat das Problem ja auch erkannt, dass er eigentlich generischen Code schreiben muss/möchte! Super: er hat über den C-Tellerrand hinausgeblickt! Das ist ein Chance ... Andererseits ist es ja das Schöne an C++, dass es eine Multiparadigmen-Sprache ist. Der TO muss also weder objektorientiert noch objektbasiert programmieren, in diesem Fall reicht es ja aus, wenn er sich mit der generischen Programmierung (templates) befasst (rein prozedural). Und dann wird der TO erkennen, welch ein mächtiges Werkzeug er da kennengelernt hat. Vor allem hat er damit sehr viel Sicherheit gewonnen, da die meisten Fehler das Programm gar nicht erst wohlgeformt machen und damit nicht compilierbar! Leider provozieren die meisten Threads hier ein Gegeneinander von C und C++. Dabei sollte man m.E. ein gutes Miteinander fördern: für bestehende Projekte wie beim TO führt das zu einem selektiven Feature-Picking. Und bei neuen Projekten sollte man gleich mit C++ beginnen: auch wenn es vielleicht "nur" aus dem (gelegentlichen) Einsatz von Funktionstemplates oder domänen-spezifischen Datentypen besteht (was m.E. ein ganz grosser Schritt nach vorne bedeutet) oder dem Verbannen von nicht-typsicheren, nicht ge-scoped-ten Präprozessormacros besteht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.