Verständnisproblem: wchar_t Abfrage auf '\0'
-
Hi,
kann mir jemand erklären warum dieser Code nicht funktioniert, bzw. warum ich bei der Abfrage (5. Durchlauf der Schleife) einen "Zugriff Überlauf" bekomme ?
Genau dann, wenn auf das Ende des wchar_t arrays abgefragt wird.
Der CodeGuard erzählt was von 8 Byte lang, aber in den lokalen Variablen sieht man das es 10 Bytes sind, die letzten 2 sind 0x0000
Ist das bei wchar_t nicht zulässig, Problem mit new oder worin liegt hier mein Problem ?const wchar_t *KeyA = L"Test\0"; wchar_t X; wchar_t *Text = L"Das ist ein Beispiel"; wchar_t *pText = Text; // Copy von KeyA anlegen wchar_t *cpKeyA = new wchar_t[wcslen(KeyA)]; cpKeyA = wcscpy(cpKeyA, KeyA); // Pointer auf die einzelnen char von KeyA wchar_t *pKeyA = cpKeyA; // Original Pointer sichern wchar_t *pKeyASave = pKeyA; for ( int i = 0; i < wcslen(Text); i++ ) { X = *pKeyA; // hier wird X und pText verknüpft if ( *(++pKeyA) == L'\0' ) // Beim 5. Durchlauf, wenn der Pointer auf '\0' zeigt, { // wird das Programm durch den CodeGuard abgebrochen // Rücksetzen von pKeyA pKeyA = pKeyASave; } } delete [] cpKeyA;11.06.2011 10:57:25 CodeGuard(tm)-Prozess wurde gestartet: Wchar_t.exe(5820) Zugriff Überlauf im Prozess: Wchar_t.exe(5820) - C:\Projekte\Test\wchar_t\Unit2.cpp#267 Versuch, auf 2 Byte(s) an 0x01CD3748 zuzugreifen., an Offset 8 in Heap Block 0x01CD3740, der nur 8 Bytes lang ist. 0x004041C5 - C:\Projekte\Test\wchar_t\Unit2.cpp#267 0x004BAEED - Controls.pas#7191 0x004BF245 - Controls.pas#9833 0x00474A75 - StdCtrls.pas#4410 0x004BF398 - Controls.pas#9900 0x004BF245 - Controls.pas#9833 0x0049E61D - Forms.pas#3962 0x004BE8E3 - Controls.pas#9552 0x00424B8E - Classes.pas#13492 0x7760FD72 0x7760FE4A 0x77610943 0x77610B36 0x747FB4BA 0x747FB51C Objekt-Array (0x01CD3740) [Größe: 8 Byte] war erstellt mit new[] 0x0040416E - C:\Projekte\Test\wchar_t\Unit2.cpp#254 0x004BAEED - Controls.pas#7191 0x004BF245 - Controls.pas#9833 0x00474A75 - StdCtrls.pas#4410 0x004BF398 - Controls.pas#9900 0x004BF245 - Controls.pas#9833 0x0049E61D - Forms.pas#3962 0x004BE8E3 - Controls.pas#9552 0x00424B8E - Classes.pas#13492 0x7760FD72 0x7760FE4A 0x77610943 0x77610B36 0x747FB4BA 0x747FB51C ---------------------------------------------------------------------------------------------------------------------- Lokale Variablen: Name Wert KeyA :004EE5C0 L"Test" X L't' 116U (0x0074) Text :004EE5CC L"Das ist ein Beispiel" pText :004EE5CC L"Das ist ein Beispiel" cpKeyA :01CD3740 L"Test" [0] L'T' 84U (0x0054) [1] L'e' 101U (0x0065) [2] L's' 115U (0x0073) [3] L't' 116U (0x0074) [4] L'\0' 0U (0x0000) pKeyA :01CD3748 L"" pKeyASave :01CD3740 L"Test" Sender :01C60420 this :01C2E220 i 3 (0x00000003)
-
Der Fehler dürfte bereits in Zeile 7 entstanden sein - dort hast du nur Platz für 4 Zeichen angelegt, aber nicht für den Null-Terminator - damit schreibst du in Zeile 8 über das Ende des reservierten Speichers hinaus.
-
Super, danke ! Das war sozusagen voll ins Schwarze. Ich hab's jetzt so gelöst:
wchar_t *cpKeyA = new wchar_t[wcslen(KeyA)+1];
-
Nur als Denkanstoß habe ich noch zwei Fragen für dich:
- Warum hantierst du überhaupt mit nackten Zeigern und nicht mit std::wstring?
- Was genau erhoffst du die von dem \0 am Ende der ersten Zeile? (String-Literale sind schon implizit null-terminiert)
- Welchen Sinn hat die Schleife überhaupt?
-
CStoll schrieb:
Nur als Denkanstoß habe ich noch zwei Fragen für dich:
- Warum hantierst du überhaupt mit nackten Zeigern und nicht mit std::wstring?
- Was genau erhoffst du die von dem \0 am Ende der ersten Zeile? (String-Literale sind schon implizit null-terminiert)
- Welchen Sinn hat die Schleife überhaupt?
- Ich hab es vorher schon mal mit AnsiString und UnicodeString versucht und hab da jede Menge an Warnungen bekommen, sowas wie "Zeichen kann in der aktuellen Gebietseinstellung nicht dargestellt werden". Die Routine soll eine Zeichenkette (Textstring) verschlüsseln (X-ORen und 8. bit setzen). Um die Warnungen zu umgehen hab ich mich dann entschlossen, das als wchar_t array anzulegen.
- OK, das ist überflüssig dann. War mir nicht bewust.
- Wie gesagt soll mit dieser Schleife ein Text verschlüsselt werden. Ich hab die Schleife oben aber soweit abgespeckt um den Fehler zu lokalisieren.
Bestimmt gibt es dazu bessere Methoden, die ich aber noch nicht kenne.
-
Ich bin mir zwar nicht sicher, woher diese Warnungen kommen, aber solange du die verschlüsselten Daten nicht ausgeben willst, sollte es eigentlich kein Problem sein, wenn sie nicht darstellbar sind. btw, std::wstring ist der "große" Bruder von std::string und soll laut ANSI-Standard überall verfügbar sein. Damit müsste dann auch die Verschlüsselung kein Problem sein:
wstring text; getline(wcin,text); wstring key=L"Schlüssel"; wstring code; for(size_t i=0;i<text.length();++i) { wchar_t c = text[i] ^ key[i%key.length()]; code.push_back(c); }
-
Hi CStoll,
danke für dein Code-Snippet, funktioniert prima. Deutlich weniger code zeilen als ich zuvor hatte

2 Fragen hätte ich noch dazu:- Ist es besser den zu kodierenden Textstring als Referenz zu übergeben, und den codierten Text auch als Referenz im Aufruf von Kodieren(), oder
- den codierten Text als Referenz oder Zeiger zurückzugeben ?
void __fastcall TForm1::Button2Click(TObject *Sender) { wstring text = Memo1->Lines->Text.c_str(); wstring codierter_text; codierter_text = Kodieren( text ); Memo1->Lines->Text = codierter_text.c_str(); }wstring __fastcall Kodieren( wstring Text ) { const wstring keyA = L"Schlüssel"; wstring code; for ( size_t i = 0; i < Text.length(); ++i ) { wchar_t c = Text[i] ^ (keyA[i%keyA.length()] | 0x80); code.push_back(c); } return code; }
-
Den Originaltext würde ich als
const wstring&übergeben, bei der Rückgabe bin ich mir nicht sicher, ob Referenzparameter oder Rückgabewert günstiger sind.