Probleme mit Adressen und deren Initialisierung
-
Hallo Community,
Ich bin mit meinem Latein langsam am Ende
Ich find den Fehler nicht, bzw. kann ihn mir nicht erklären.
Ich habe ein Programm geschrieben, das anhand einer Exceldatei und einer Datenbank bestimmte Datentypen anlegt. z.B. einen String,Char,int ect.
Die Adresse der angelegten Variable speichere ich in eine TLIST (AdrList);MEIN_STRING *e; MEIN_STRING eSIZE; for (int i = 0; i < Q1->RecordCount; i++) { switch (Q1->FieldByName("DataTypInt")->AsInteger) { case DATA_TYPE_MEIN_STRING: e = new MEIN_STRING; AdrList->Add(e); DataTypeSize->Add(IntToStr((int)sizeof(eSIZE))); break; ....
Beim initialisieren der Variable läuft wieder das gleiche Schema ab.
Ich durchlaufe wieder die Datenbank und an Hand des eingetragenen Datentyps
Caste ich die in der AdrList hinterlegte Speicheradresse auf den entsprechenden Datentyp, um in diese einen Wert zu schreiben.StringInit((MEIN_STRING*)AdrList->Items[i],StateText->Strings[1].t_str());
Und hier habe ich mein Problem. Ich schreibe in den einen Speicherbereich das Wort "On"
und in den nächsten "Off" nachdem in der Funktion StringInit das eingetragen wurde.
steht in beiden Adressen der richtige Wert.
Komme ich jedoch aus dieser Schleife herraus(ich fülle in der Reihenfolge wie die Datentypen in der DB stehen) und Schaue dann in die beiden Speicherbereiche steht in dem zuerst geschriebenen nicht mehr das Wort "On" sondern nur noch "O".
Adressen und Größe sind aber identisch wie vorher.
Im zweiten bereich steht ganz normal "Off".
Drehe ich die Reihenfolge um, so das zuerst Off und dann On gesetzt wird.
Ist das ganze umgedreht im ersten Bereich steht wieder das "O" statt Off und im zweiten ganz normal On.Hier die Funktionen die genutzt werden um die Variablen zu initialisieren. Ich erkenne keinen Fehler?!
void TServer::StringInit(MEIN_STRING* pMEINnetString, const char* pszText) { memset( pMEINnetString, 0, sizeof(*pMEINnetString) ); pMEINnetString->data.chstringData = (char*)pszText; pMEINnetString->nBufferSize = (MEIN_UINT)strlen(pMEINnetString->data.chstringData); pMEINnetString->type = STRING_ANSI_X34; } //--------------------------------------------------------------------------- int TServer::BitStringSetBit(MEIN_BIT_STRING *pBitString, unsigned bitIndex, unsigned bitValue) { if (bitIndex >= pBitString->bitCount) return EINVAL; if (bitValue) pBitString->data[bitIndex / 8] |= (BAC_BYTE) (0x80 >> (bitIndex % 8)); else pBitString->data[bitIndex / 8] &= (BAC_BYTE) ~(0x80 >> (bitIndex % 8)); return EOK; } //--------------------------------------------------------------------------- int TServer::BitStringFromCharString(MEIN_BIT_STRING *pBitStr, const char *pStr) { unsigned i; unsigned nBit; if(pStr == NULL || pBitStr == NULL) return EINVAL; nBit = (unsigned)strlen(pStr); memset(pBitStr,0,sizeof(MEIN_BIT_STRING)); pBitStr->bitCount = nBit; for (i = 0;i < nBit;i++) { if(pStr[i] == '1' || pStr[i] == 'T' || pStr[i] == 't') BitStringSetBit(pBitStr,i,1); else if(pStr[i] == '0' || pStr[i] == 'F' || pStr[i] == 'f') BitStringSetBit(pBitStr,i,0); else return EINVAL; } return EOK; } //---------------------------------------------------------------------------
Adressen bleiben gleich, größe bleibt gleich, dennoch wird der Inhalt nach der Schleife der Datenbank zerstört?!
An was kann das liegen?!
Ich wüsste nicht was ich noch ändern könnte.
Hat eventuell von euch einen Tipp für mich ?Danke
-
Hallo
Leider ist nicht ersichtlich was genau MEIN_STRING für ein Datentyp ist. Allerdings diese beiden Zeilen sind schonmal problematisch :
memset( pMEINnetString, 0, sizeof(pMEINnetString) );
pMEINnetString->data.chstringData = (char)pszText;memset darf eigentlich nur für PODs angewendet (int, float, Zeiger, C-style structs...), nicht aber für Benutzerdefinierte Datentypen, die auf class inklusive Konstruktoren basieren. Wenn dein Datentyp MEIN_STRING also ein einfaches struct ohne Konstruktoren oder andere C++ Erweiterungen ist, ist das in Ordnung.
Allerdings weist du in der zweiten Zeile einem Member von MAIN_STRING die Adresse von pszText zu (und nicht den Inhalt, der hinter der Adresse steht). Das führt dann zu Problemen, wenn pszText nur von lokaler Gültigkeit ist. Beispielsweise dein gezeigter Aufruf StringInit(...,StateText->Strings[1].t_str()); erzeugt nämlich nur ein lokales pszText, desen Inhalt nach dem Aufruf von StringInit nicht mehr gültig ist. Solange du in deine MAIN_STRING nur die Adresse kopierst hast, ist der Adresse nach StringInit nicht mehr gültig. Du must stattdessen mit z.b. strcpy den Inhalt von pszText in einen mit new erzeugten Speicherbereich kopieren, damit deine MEIN_STRING-Instanz dann die Ownership für diesen Speicherbereich übernehmen kann. Dann bist du natürlich auch dafür verantwortlich manuell diesen Speicherbereich wieder zu löschen...Jetzt sollte dir klar sein das dein Konzept in altem C-Stil nur mühselig umzusetzen ist. Ich empfehle dir also dringend, dein Konzept zu überdenken.
- Brauchst du wirklich eine solche Laupfzeit-Typvarianz? Ist in C/C++ nämlich niht vorgesehen und schlecht zu implementieren.
- Brauchst du wirklich verschiedene Datentypen in einem einzelnem Array? Array sollten immer genau einen Datentyp beinhalten, sonst geht der Vorteil des Arrays verloren.
- Warum benutzt du TList, aber nicht String? Moderne C++ Datentypen übernehmen ihre Speicherverwaltung nämlich selbst, eine große Erleichterung.
- Wenn du wirklich einen Laufzeit-Metatyp haben willst, solltest du die dafür notwendige Logik nicht auf dem Array aufbauen, sondern bereits in den Element-Datentyp einbauen, auf Basis einer polymorphen Klasse.Mehr kann ich aus deinem Auszug nicht erkennen, um dein Problem weiter einzugrenzen solltest du den Debugger benutzen.
bis bald
akari
-
Danke für deine Hilfe akari.
Die Struktur von MEIN_STRING ist mir fest vorgegeben an dem konnte ich nichts ändern.Aber deine Aussagen mit der lokalen gültigkeit usw. haben mir sehr geholften.
Mittlerweile hab ich die Übergabe der Variablen abgeändert, so dass diese nicht überschrieben werden können und das der Inhalt übergeben wird.Danke für deinen Denkanstoss!