structs in arrays
-
Hallo,
ich kämpfe zur Zeit dank meiner Ausbildung mit C++ und hätte nun eine Frage.
Ich habe ein struct welches folgendermaßen aussieht:struct EventData { char* eventID1; char* eventID2; char* priorityClass; char* obNumber; char* dataIDZ23; char* dataIDZ1; char* suppDataZ11; char* suppDataZ12; char* suppDataZ21; char* suppDataZ22; char* suppDataZ31; char* suppDataZ32; char* eventText; };Jetzt würde ich gerne ein Array der Größe x erzeugen welches dann lauter solche structs enthält. Geht sowas ?
Bei mir macht er bei den beiden Aufrufen:
EventData* daten = new EventData[x]; EventData* daten = new EventData;Genau dasselbe, das versteh ich schon nicht. Andersrum:
EventData[] daten = new EventDaten[x];Bekomme ich Fehlermeldungen das "daten" nicht deklariert wäre.
Kann mir da jmd helfen ? Ich weiß nicht mehr so richtig was ich noch versuchen soll.
-
Gast84 schrieb:
Jetzt würde ich gerne ein Array der Größe x erzeugen welches dann lauter solche structs enthält. Geht sowas ?
Ja.
Bei mir macht er bei den beiden Aufrufen:
EventData* daten = new EventData[x]; EventData* daten = new EventData;Genau dasselbe, das versteh ich schon nicht.
Wie kommst du darauf dass er das selbe macht? Kriegst du zweimal die selbe Fehlermeldung? Oder hast du dir den Assemblercode angeschaut? Dann wäre es wirklich verwunderlich, das macht nämlich nicht das selbe. Das erste erzeugt ein dynamisces Array mit x Elementen vom Typ EventData, das zweite erzeugt ein einziges EventData im Freispeicher.
Andersrum:
EventData[] daten = new EventDaten[x];Bekomme ich Fehlermeldungen das "daten" nicht deklariert wäre.
Die fehlermeldung ist auch korrekt, das ist nämlich kein gültiges C++ was du da versuchst.
Kann mir da jmd helfen ? Ich weiß nicht mehr so richtig was ich noch versuchen soll.
Was du noch versuchen solltest: Im C++-Buch deiner Wahl den Abschnitt über dynamische Arrays nochmal genau durchlesen und verstehen. Mit Herumprobieren kommt man in der Programmierung selten weit.

-
Gast84 schrieb:
struct EventData { char* eventID1; char* eventID2; char* priorityClass; char* obNumber; char* dataIDZ23; char* dataIDZ1; char* suppDataZ11; char* suppDataZ12; char* suppDataZ21; char* suppDataZ22; char* suppDataZ31; char* suppDataZ32; char* eventText; };Das sieht ja schon einmal sehr verdächtig aus (std::string?). Aber ich will mal auf deine eigentliche Frage eingehen:
Jetzt würde ich gerne ein Array der Größe x erzeugen welches dann lauter solche structs enthält. Geht sowas ?
Klar. Du zeigst ja auch schon wie es geht:
Bei mir macht er bei den beiden Aufrufen:
EventData* daten = new EventData[x]; EventData* daten = new EventData;Genau dasselbe, das versteh ich schon nicht.
Wie kommst du da drauf, dass dort das gleiche passiert? Das sollte nicht der Fall sein!
Andersrum:
EventData[] daten = new EventDaten[x];Bekomme ich Fehlermeldungen das "daten" nicht deklariert wäre.
Da hat der Compiler auch recht. Dynamische Arrays funktionieren so nicht. Oben machst du es schon richtig.
Kann mir da jmd helfen ? Ich weiß nicht mehr so richtig was ich noch versuchen soll.
Anstatt selber mit dynamischen arrays zu hantieren, nimm doch einfach std::vector!
-
Falls x eine konstante ist, kannst du es einfach so machen:
EventData data[4];
-
SeppJ schrieb:
Wie kommst du da drauf, dass dort das gleiche passiert? Das sollte nicht der Fall sein!
Wenn ich das debugge und mir dann die 2 variablen ansehe (die eine heißt dann eben daten2) dann sehen die exakt gleich aus und zwar beinhalten beide die Elemnte aus dem Struct.
Sollte das beim Array aber nicht so aussehen das die Variable (angenommen x sei 50) 50 Felder hat und ich dann jedes Feld einzeln aufmachen kann und darin dann das Struct sehe ?
Ich hab leider nur ein C# Beispielprogramm in dem es auch so eine Stelle gibt und wenn ich das debugge dann ist das so wie beschrieben.
Oder ist das bei C++ von der Darstellung eben nur anders ? Weil wie gesagt der Inhalt beider Variablen derselbe ist, nämlich einmal das Struct. Daher dachte ich die sind gleich.
-
Gast84 schrieb:
SeppJ schrieb:
Wie kommst du da drauf, dass dort das gleiche passiert? Das sollte nicht der Fall sein!
Wenn ich das debugge und mir dann die 2 variablen ansehe (die eine heißt dann eben daten2) dann sehen die exakt gleich aus und zwar beinhalten beide die Elemnte aus dem Struct.
Sollte das beim Array aber nicht so aussehen das die Variable (angenommen x sei 50) 50 Felder hat und ich dann jedes Feld einzeln aufmachen kann und darin dann das Struct sehe ?
Ich hab leider nur ein C# Beispielprogramm in dem es auch so eine Stelle gibt und wenn ich das debugge dann ist das so wie beschrieben.
Oder ist das bei C++ von der Darstellung eben nur anders ? Weil wie gesagt der Inhalt beider Variablen derselbe ist, nämlich einmal das Struct. Daher dachte ich die sind gleich.
Nein, die Variable ist ja in beiden Fällen ein Zeiger. In einem Fall zeigt der auf das einzige Element (angesprochen durch
*datenoderdaten[0]), im anderen Fall zeigt er auf das erste Element eines Arrays. Die anderen Elemente kommen danach und können mitdaten[0](erstes Element) bisdaten[x-1](letztes Element) angesprochen werden.Ich würde dir aber wirklich empfehlen, einen der STL Container anstelle eines dynamischen Arrays zu nehmen. Diese bieten wesentlich mehr Komfort ohne Kosten.
-
Hallo,
danke jetzt hab ichs verstanden. Das mit den STL Containern hab ich mir mal angeschaut, kenne mich zwar nicht aus damit sieht aber angenehmer aus, werd ich in Zukunft wohl auch benutzen, wenn auch nicht mehr für diese Programm, das wäre mir zuviel zu ändern.
Habe jetzt noch eine andere Frage, hier mal die Methode:
void GetEventText2(short arrSize, EventData entries[]) { CEventGetter* eventReader = new CEventGetter(); EventData* currentData; currentData = &entries[0]; for (int counter = 0; counter < arrSize; counter++){ if (currentData != NULL) { bool noError = false; noError = eventReader->GetText(currentData); if(noError) { currentData->eventText = eventReader->GetRetrievedText(); } else { currentData->eventText = "ERROR!!"; } } currentData++; } }EventData ist ja das Struct aus dem ersten Post.
Der EventReader ist einfach nur eine andere Klasse die anhand der Werte in dem Struct einen Text aus einer Datenbank sucht. Dieser landet dann im eventText des Structs.
Denke der Code ist nicht wirklich schwer.Am Ende der Schleife hat auch jedes Struct den richtigen Text !
Nur wenn dann die Methode verlassen wird bekomm ich (beim debuggen) eine Meldung das Windows einen Haltepunkt ausgelöst hat weil der Heap kaputt sei.
Hab schon nachgelesen und an verschiedenen Stellen ein ASSERT(AfxCheckMemory()) eingefügt, aber ohne Erfolg, der meldet keinerlei Speicherverletzungen.Das lustige ist, wenn ich das Programm nicht debugge sondern normal laufen lasse bekomme ich keinerlei Fehlermeldungen und er läuft durch. Nur stehen dann in der Ausgabedatei stellenweise falsche Texte.
Also irgendwo muss es da was zerhauen aber ich wüsste nicht wo, der Code ist ja jetzt nicht so komplex...
-
Sieht so aus, als ob ein Java-Programmierer sich mit C++ versucht. Wieso wird der EventReader im Freispeicher angelegt? Wo löschst Du den wieder?
-
krümelkacker schrieb:
Sieht so aus, als ob ein Java-Programmierer sich mit C++ versucht. Wieso wird der EventReader im Freispeicher angelegt? Wo löschst Du den wieder?
Oh das hab ich vergessen, das delete eventReader stand mal ganz am Ende der Methode, da kommt der Fehler aber ebenso und noch noch dazu werden nach dem delete alle Texte die ich vorher ausgelesen habe durch komische Symbole ersetzt.
Aber du hast recht, mit Java komme ich wesentlich besser zurecht, das ist irgendwie angenehmer zu programmieren, hier muss man auf sovieles aufpassen

-
Gast84 schrieb:
Oh das hab ich vergessen, das delete eventReader stand mal ganz am Ende der Methode
Wie gesagt, man muss das Ding nicht im Freispeicher anlegen, wenn es "am Ende" sowieso nicht mehr benötigt wird. Dafür gibt es ja den automatischen Speicherbereich, wo "normale" lokale Variablen auch leben.
void foo() { CEventGetter eventReader; ... eventGetter.GetText(...); ... }oder
void foo() { CEventGetter eventReader (param1, param2, param3, ...); ... }um den "event reader" mit bestimmten Parametern zu initialisieren. Folgendes:
void foo() { CEventGetter eventReader (); ... }ist eine "syntaktische" Falle. Dies kann auf zweierlei Arten interpretiert werden (Funktionsdeklaration und Konstruktoraufruf). Diese Ambiguität muss der Compiler zugunsten der Funktionsdeklaration auflösen. Das ist leider so. (Google "most vexing parse").
Gast84 schrieb:
Aber du hast recht, mit Java komme ich wesentlich besser zurecht
Das ist erstmal normal. Es dauert eine Weile, bis man den Dreh raus hat.

-
Ja, ohne "new" wird er ja wieder zerstört sobald ich die Methode verlasse. Das Problem war ja das wenn ich ihn zerstöre (oder zerstören lasse am Ende der Methode) alle Texte die ich mir über den Reader geholt habe durch kryptische Zeichen ersetzt werden. Daher dacht ich ich lass ihn bis Programmende bestehen und hau ihn dort dann erst weg.
Ich glaub aber ich hab den Übeltäter gefunden, bitte nicht gleich schreien, das war nur zu Testzwecken !
Ich habe diese Zeile:EventData* currentData;Ersetzt durch diese:
EventData* currentData = new EventData;Und am Ende der Methode dann delete currentData; aufgerufen. Da zerhauts den Heap schon dort. D.h. es muss am currentData liegen, ich habe aber keine Ahnung wieso. Ich mach doch nichts wildes mit der Variablen

-
Doch machst du -) Du zerschiesst dir den ganzen Speicher!
Ändere zuersteinmal deine EventData-Struktur ab:
entweder 'std::string' oder aber wenigstens z.B. 'char ...[100]' anstatt "char *", denn für die char-Zeiger müßtest du auch ersteinmal Speicher reservieren bevor du darauf zugreifen kannst (das hatte dir SeppJ ja auch schon geschrieben).Nichts für ungut, aber m.E. solltest du dein Programm noch mal neu strukturieren (und dabei auf jedliche Zeiger zuersteinmal verzichten!!!).
-
Hallo,
okay ich hab mich jetzt mit einem C++ Buch mal mit den CStrings auseinander gesetzt und weiß jetzt immerhin mal warum SeppJ sagte dass das "verdächtig" aussieht...
Dass das so nicht funktioniert wundert mich nicht mehr wirklich.ich hab jetzt <string> eingebunden und das Struct besteht nun aus lauter Strings. Das funktioniert soweit auch, das Problem ist der Einstieg der Methode:
void GetEventText2(short arrSize, EventData entries[])Weil ich hier ein Array lauter solcher Structs übergeben bekomme. Sobald ich mein Struct aber von char* ändere in char ...[100] oder string, kommt hier nur noch Mist an. Da stehen dann bloß noch irgendwelche kryptischen Zeichen drinne (bei char ...[100]) oder es ist alles vertauscht und durcheinander (bei string). Die Übergabe erfolgt aus einen C# Programm und dort ist das Struct mit strings gemacht. Wieso ging das bei dem falschen char* mit dem ich den Speicher zerschieße und wenn ichs richtig mache gehts nicht mehr ?
Je mehr ich mich damit auseinander setze desto mehr wünsche ich mir wieder Java

-
Du kannst Arrays nicht als Parameter übergeben. Deswegen benutzt man auch lieber std::vector oder std::tr1::array.
-
Janjan schrieb:
Du kannst Arrays nicht als Parameter übergeben. Deswegen benutzt man auch lieber std::vector oder std::tr1::array.
Okay, dann übergeb ich stattdessen einen Pointer auf das Array, das geht doch.
der Methodenaufruf sieht so aus:NativeMethods.GetEventText2((short)specializedEntries.Length, specializedEntries);Und die aufgerufene Methode so:
void GetEventText2(short arrSize, EventData* entries)Sowas geht doch normalerweise problemlos. Wieso hier nicht ? Liegt das daran das ich eine DLL aufrufe ? Dürfte laut Internet aber keinen Unterschied machen.
Werd mir jetzt mal den Vector anschauen, nur wenns an der Übergabe an eine DLL liegt wird mir das evt auch nix helfen

-
So, ich definiere meine Frage neu, weil ich glaub langsam wirds unübersichtlich, weil mein Problem nicht mehr bei Pointern oder Speicherverletzungen liegt, das hab ich hinbekommen

Ich hab eine realtiv großes Programm, geschrieben in C#. Darin gibt es irgendwann mal ein Array welches voller Structs ist. Dieses Array muss jetzt an eine DLL übergeben werden, oder eben ein Pointer auf das Array.
Die DLL ist in C++ geschrieben und muss den Pointer auf das Array entgegennehmen, weil die DLL inerhalb der Structs des Arrays Werte ändern muss.
Wenn ein Pointer übergeben wird braucht die DLL ja auch keinen Rückgabewert (wenn ich mein Buch richtig verstanden habe).Das Problem ist jetzt das der Pointer, welcher in der DLL ankommt, zwar auf das erste Arrayfeld und somit das erste Struct zeigt, Werte im Struct aber anders oder vertauscht sind. Mit jedem weiteren ArrayFeld nach hinten wirds schlimmer. Aber Feld 18 stehen in den Structs dann die ersten kryptischen Zeichen bzw. Meldungen wie <Schlechter Pointer>.
Wenn ich in C++ als Test 2 Methoden schreibe die sich so ein Array übergeben dann funktioniert das einwandfrei. Liegt das jetzt also an der Schnittstelle zwischen C# und C++ ? Oder daran weils ne DLL ist ? Laut Internet kann man Werte genauso an eine DLL übergeben wie auch an eine normale Methode.
-
Das hat aber jetzt eher was mit C# zu tun (bzw. dem Marshalling).
Wie sehen deine struct-Definitionen in C# und C++ jetzt aus?
Und wie die genaue DllImport-Deklaration und dessen Aufruf?
-
Also das ist das C++ Struct in der DLL:
struct EventData { string eventID1; string eventID2; string priorityClass; string obNumber; string dataIDZ23; string dataIDZ1; string suppDataZ11; string suppDataZ12; string suppDataZ21; string suppDataZ22; string suppDataZ31; string suppDataZ32; string eventText; };Dies ist das Struct in dem C# Hauptprogramm:
public struct EventData { public string eventID1; public string eventID2; public string priorityClass; public string obNumber; public string dataIDZ23; public string dataIDZ1; public string suppDataZ11; public string suppDataZ12; public string suppDataZ21; public string suppDataZ22; public string suppDataZ31; public string suppDataZ32; public string eventText; }Der DLL Import im C# Programm sieht so aus:
[DllImport("Event2DBAccess.dll")] public static extern void GetEventText2(short arrSize, [In, Out] [MarshalAs(UnmanagedType.LPArray)] EventData[] entries);Die Structs sind mMn vollkommen einheitlich, es muss irgendwo an der Übergabe liegen. Habs schon zusätzlich mit dem CallConvetion Parameter versucht, weil ich da irgendwo was gelesen hatte, aber ohne Erfolg. Bei In und Out bin ich mir auch nicht ganz sicher, ein Out brauch ich doch gar nicht wenn ich in der DLL mit dem Pointer arbeite, oder ?
-
Ah ich vergass die DLL Definiton im C++ Programm.
Die steht im Header:#define DLLEXPORT __declspec(dllexport) extern "C" DLLEXPORT void GetEventText2(short arrSize, EventData* entries);
-
Also da muß ich dich enttäuschen, aber ein C# String ist nicht binär-kompatibel mit einem C++ std::string (außerdem verwendet C# intern Unicode (2 Bytes), während ein std::string nur ein Byte pro Zeichen speichert).
Du mußt dich intensiv mit dem Thema "Marshalling" beschäftigen. Schau mal intensiv die MSDN Doku zu der Klasse 'Marshal' an.
Desweiteren kann ich dir ein anderes Forum (http://www.mycsharp.de/wbb2/forum) empfehlen, wo auch schon sehr viele Fragen zum Thema "Marshalling" gestellt und beantwortet wurden:
http://www.mycsharp.de/wbb2/search.php?searchstring=Marshal%2A&boardids%5B%5D=*&send=send // Edit: leider versagt hier die Forensoftware (daher Link einfach kopieren)Dein eigentliches Vorhaben, direkt in C++ die C#-Strukturen zu beschreiben, wirst du aber so nicht hinbekommen.
Der übliche Weg ist es in C# einen StringBuilder zu erstellen (mit einer konstanten Kapazität) und in der C- bzw. C++-DLL dann auf einem char[] zu arbeiten.
Bei Strukturen wird es dann entsprechend komplex und wenn du dann auch noch Arrays von Strukturen hast wird es noch komplexer...Nichtsdestotrotz viel Erfolg bei der Suche nach einer Lösung und der Umsetzung.
Evtl. mußt du auch der einfachhalthalber den Zwischenweg über C++/CLI nehmen...