[gelöst] std::list<struct>
-
Hi,
ich will eine std::list verwenden, deren Inhalt structs sind. Leider funktioniert es nicht richtig. So sieht mein Code aus:
struct item { char type; char name[8]; char file[8]; std::list<item> childs; }; std::list<item> menuTree; void create(char* str, item* is) { int i = 0; while (str[i] == '-') { i++; } item x; x.file[0] = ' '; x.file[1] = ' '; x.file[2] = ' '; x.file[3] = ' '; x.file[4] = ' '; x.file[5] = ' '; x.file[6] = ' '; x.file[7] = ' '; x.type = str[i]; if (i == 1) { menuTree.push_back(x); } else { is[i-2].childs.push_back(x); } is[i-1] = x; int j = i + 2; while (str[j] != ',') { x.name[j-i-2] = str[j]; j++; } i = j + 1; j++; while (str[j] != '\0') { x.file[j-i] = str[j]; j++; } MessageBox ( NULL, menuTree.back().file, menuTree.back().file, MB_OK); }Die Funktion bekommt ein char-array (z.b. "-K,test,test.bmp") und ein array von 5 item-s übergeben. Aus dem char-array werden jetzt 4 daten ausgelesen und in dem neuen struct x gespeichert. Danach soll dieser Im falle dass i == 1 ist, in die menuTree-Liste gesetzt werden. Das dieser Fall eintritt habe ich mittels einer Messagebox getestet.
Aber die MessageBox am ende zeigt nur leerstrings an.Also irgendwie funktioniert das Abspeichern und/oder auslesen net so recht. Ich tippe mal auf einen Pointerfehler oder sowas. Aber ihr wisst das sicherlich, oder?^^
Mfg
DerBaer
-
1. Abgesehen von
std::listist das der reinste C Code.
2. Es ist sogar ein hässlicher C Code. Schon mal was vonmemsetgehört?
3.std::findundstd::copywürden hier auch ein paar Dinge lesbarer machen.
4.nameundfilehaben keine Nullterminierung. Wenn du diese an MessageBox übergibst, kann das ganz böse Folgen haben.
5. Für sowas gibt es Debugger, da kann man das Programm Schritt für Schritt durchgehen.
6. Kein Wunder das es nicht geht. Du speicherst eine Kopie inmenuTree, bevor du überhaupt irgendetwas in das Objekt reingeschrieben hast, ausser ein paar Leerzeichen und den Typ.
7. Man hat das Gefühl, da fehlen seeeehr viele C++ Kenntnisse.Grüssli
-
danke für die Antwort.
Ich glaube auch, dass mir da etwas Wissen fehlt, aber so "kann" ichs halt und diese Zusatzfunktionen eigne ich mir nach und nach an. Und von Memset hab ich schonmal was gehört, aber auch, dass es zu problemen führen kann^^
Zum Problem:
Wenn iich das speichern ans ende der funktion setzte klappt alles wunderbar, danke. Ich bins von java gewöhnt das sowas funktioniert. in C müsste ich die Liste vom typ item* machen und &x hinzufügen?Mfg DerBaer
btw. hab ich gesagt dass mein programm in C++ geschrieben ist? Und die Liste is ja der Hauptteil hierbei, auch wenn der Fehler woanders lag)
-
Du solltest dich erst einmal entscheiden, ob du C oder C++ programmieren willst. Auch wenn sie ab und zu in einen Topf geworfen werden, handelt es sich bei den beiden um verschiedene Programmiersprachen. Die Konzepte unterscheiden sich grundlegend, in C++ hat man zum Beispiel mehr Abstraktionsmöglichkeiten.
Solltest du dich für C++ entscheiden, würde ich
char-Arrays vorerst bei Seite lassen und die komfortable Klassestd::stringverwenden. Du wirst noch genügend Gelegenheiten haben, dich mit Überbleibseln aus C zu beschäftigen. In C müsstest du aufstd::listund sonst einige Dinge verzichten.
-
DerBaer schrieb:
btw. hab ich gesagt dass mein programm in C++ geschrieben ist?
Du verwendest
std::listund die kommt aus C++, existiert in C nicht. Zudem hast du einen Beitrag im C++ Forum verfasst, wir haben ein eigenes C Forum. Daher nahm ich schon an, dass du C++ programmieren willst
Ich empfehle dir allerdings, wie es Nexus gesagt hat, dich zwischen C und C++ zu entscheiden. Wenn du ein C mit Klassen programmieren willst, dann führt das zu keinem guten Ergebnis.
Wenn du dich für eine Sprache entschieden hast, können wir dir auch Material nennen, womit du die Sprache lernen kannst

Grüssli
-
BTW: childs hört sich schrecklich an :p
-
ich entscheide mich für C++.
Werde dann wohl doch noch mal ein Tutorial durchgehen müssen
Das mit memset klappt doch prima.
Nullterminiert sind meine Arrays jetzt auch
find und copy will noch net ganz(bin aber schon nah dran)
childs werde ich umbenennen (mir fehlt da immer die Idee wie ichs am besten nenne. außerdem war es erst so eine versuchsskript. wenn alles läuft schreib ich es verständlich und übersichtlich)Vielen dank nochmal für eure zahlreichen und schnellen Antworten. Ich melde mich morgen wieder, wenn ich weiter bin(oder versagt habe)
Mfg
DerBaer
-
Ich glaube, du hast mich nicht ganz verstanden. Ich hab nichts gegen Kinder, dieser Name wird häufig verwendet. Ich hab noch nicht mal deinen Code durchgelesen, um beurteilen zu können, ob der Name hier gut gewählt ist. Aber http://wiki.answers.com/Q/Plural_for_child

-
DerBaer schrieb:
ich entscheide mich für C++.
Werde dann wohl doch noch mal ein Tutorial durchgehen müssen
Ohne kommst du ganz sicher nicht durch. C++ ist eine sehr komplexe Sprache und hat nur seeeehr wenig mit Java zu tun. Vergiss Java wenn du C++ lernst.
Wenn es dein Geldbeutel erlaubt, dann würde ich dir auch zu einem Buch raten. Viele C++ Tutorials sind sehr schlecht (leider auch viele Bücher) und das Thema ist sehr komplex, wodurch es fast nicht in ein Tutorial passt, wodurch diese oft sehr oberflächlich sind. Ein oft empfohlenes Buch ist der C++ Primer. Es gibt eine deutsche Übersetzung davon, empfohlen wird aber oft die Sache in Englisch zu lesen. Man sollte sich in der Informatik sowieso an diese Sprache gewöhnen. Falls du an Englisch gewöhnt bist und dein Geldbeutel knapp ist, so gäbe es noch Thinking in C++ 1&2. Dieses Buch kann man gratis herunterladen.
DerBaer schrieb:
Das mit memset klappt doch prima.
Wenn du bei C++ bleiben willst, empfiehle ich hier noch std::fill anzuschauen, the C++ way

DerBaer schrieb:
außerdem war es erst so eine versuchsskript. wenn alles läuft schreib ich es verständlich und übersichtlich
Damit wäre ich seeehr vorsichtig. Wenn man Code schreibt, dann belässt man ihn meistens so, wie er ist. Wir Programmierer sind faul, dazu muss man stehen, daher muss man auch so arbeiten, dass man diese Tatsache berücksichtigt. Zudem läufst du Gefahr dir einen schlechten Stil anzugewöhnen und den bekommt man nur schlecht wieder weg. Probiere immer guten Code zu schreiben sogar bei Versüchen. Es hilft dir, dich daran zu gewöhnen. Und in C++ kann ein schlechter Stil halt auch schnell zu sehr bösen Fehlern führen, da bist du nicht mehr durch einen netten Garbage Collector und einer VM geschützt

Grüssli
-
Ansonsten kann man sich auch Bücher aus Bibliotheken ausleihen, wenn man kein Geld ausgeben möchte (wobei die Bücher im Allgemeinen ja nicht wahnsinnig teuer sind und einen immerhin eine recht lange Zeit unterstützen können). Das ist meines Erachtens immer noch um einiges sinnvoller als sich sein Wissen aus mehreren Internettutorials zusammenzuklauben.
-
so jetzt steig ich hier gar nicht mehr durch.
Ich habe versucht, meine Item-Liste nur noch mit Pointern zu füllen (ist das überhaupt sinnvoll?), also std::list<item*> menuTree;
Ich fülle die dann mititem x; menuTree.push_back(&x);Das scheint auch soweit zu funktionieren.
Am ende meiner funktion create() iteriere ich dann einmal durch die liste durch und gebe mir die Werte in einer Messagebox aus. Das funktioniert auch^^. Dann habe ich(weil es eine Windows-Anwendung wird) diese "CALLBACK WndProc()" Methode mit WM_PAINT. dort will ich die Liste wieder auslesen und entsprechende bilder anzeigen(ich verwende genau die gleiche schleife). Das funktioniert auch ;). ABER wenn ich dann aus der create() funktion die messagebox entferne, wird die file variable der items irgendwie auf "" gesetzt. Was ist da los???Und ein zweites Problem. Wie kann ich von dem übergebenen char-array str die Länge ermitteln? bei sizeof(str) erhalte ich immer 4. Momentan löse ich das problem mit konstanter länge, aber das kanns ja wohl nicht sein.
Mfg
DerBaerPS.: eigentlich kenn ich children. Keine Ahnung wieso ich das nicht geschrieben hab. Aber danke für den Hinweis^^
-
DerBaer schrieb:
so jetzt steig ich hier gar nicht mehr durch.
Ich habe versucht, meine Item-Liste nur noch mit Pointern zu füllen (ist das überhaupt sinnvoll?), also std::list<item*> menuTree;Wahrscheinlich nicht.
struct item { char type; char name[8]; char file[8]; std::list<item> childs; };ist streng genommen nicht zulässig - allerdings würde ich es einem Anfänger durchgehen lassen, weil es praktisch i.d.R. funktionieren wird. Standardtemplates dürfen, soweit nicht etwas anderes ausdrücklich spezifiziert ist, nicht mit unvollständ definierten Typen instantiiert werden: das ist hier aber der Fall. ein std::list<item*> ist ein möglicher Ausweg, erfordert dann aber in Folge große Aufmerksamkeit. Eine andere Alternative wäre std::list<item>* - wenn man will, kann man auch ganz zu pimpl wechseln. So oder so isr es erforderlich, Copy-ctor, Copy-Zuweisung und Destruktor für item zu implementieren.
item x; menuTree.push_back(&x);Da x vermutlich lange vor der Liste zerstört wird, wird das so nicht funktionieren.
Und ein zweites Problem. Wie kann ich von dem übergebenen char-array str die Länge ermitteln? bei sizeof(str) erhalte ich immer 4. Momentan löse ich das problem mit konstanter länge, aber das kanns ja wohl nicht sein.
strlen.
-
so bin jetzt wieder von der Pointerliste zurückgetreten und jetzt klappt alles perfekt.
So sieht die Funktion jetzt aus:void create(char *str, item *is) { int len = strlen(str); item x; char* type = std::find(str, str+len, ','); char* name = std::find(type+1, str+len, ','); char* file = std::find(name+1, str+len, ','); x.type = *(type+1); x.name = (char*) malloc(file-name); std::copy (name, file, x.name); x.name[file-name] = '\0'; x.file = (char*) malloc(str+len-file-1); std::copy (file+1, str+len, x.file); x.file[str+len-file-1] = '\0'; menuTree.push_back(x); }vielen dank nochmal an alle.
Mfg
DerBaer
-
das was du hier anstellst hat aber wenig mit c++ zu tun...
auch solltest du dir const correctness angewöhnen:
void create(const char *str, item *is)je nach geschmack sollte man für is eine referenz statt eines pointer nehmen...
(ich seh gerade, dass du is gar nirgendwo verwendest?)(char*) malloc(file-name);->
new char[file-name];evtl solltest du create auch nur ein item zurückgeben lassen und beim aufruf das zurückgegebene objekt in den container einfügen...
wenn es keinen grund dafür gibt, darauf zu verzichten, solltest du auch mal std::string angucken...
raii ist auch noch ein stichwort, was du nachschlagen könntest...ich finde den code zumindest unsicher, unübersichtlich und schwer wiederverwendbar...
strlen ist btw auch im namespace std und gibt einen std::size_t und keinen int zurück.
und allg. gibt es hierfür auch einen konstruktor oder streaming-operatoren...bb