Ich habe gerade eine Prüfung gemacht, bei der ich folgendes gefragt wurde:
%Vor%Schreiben Sie den Funktionskörper jeder der Methoden GenStrLen, InsertChar und StrReverse für den unten angegebenen Code. Sie müssen Folgendes berücksichtigen:
- Wie Strings in C ++ erstellt werden
- Die Zeichenfolge darf nicht überlaufen
- Das Einfügen von Zeichen erhöht seine Länge um 1
- Eine leere Zeichenfolge wird durch StrLen = 0
angezeigt
Die Antwort, die ich gab, war so (siehe unten). Mein Problem besteht darin, dass viele zusätzliche Variablen verwendet wurden, und das lässt mich glauben, dass ich es nicht auf die bestmögliche Weise mache, und die andere Sache ist, dass es nicht funktioniert ....
%Vor%Ich würde mich freuen, wenn mir jemand grob erklären könnte, was der beste Weg ist, die Frage zu beantworten und warum. Wie auch immer, mein Professor schließt jede Klassenfunktion wie "};", ich dachte, das würde nur für das Beenden von Klassen und Konstruktoren verwendet.
Vielen Dank für Ihre Hilfe.
Erstens, die triviale };
-Frage ist nur eine Frage des Stils. Ich tue das auch, wenn ich Funktionskörper innerhalb von Klassendeklarationen platziere. In diesem Fall ist ;
nur eine leere Anweisung und ändert nicht die Bedeutung des Programms. Es kann am Ende der Funktionen stehen (aber nicht das Ende der Klasse).
Hier sind einige große Probleme mit dem, was Sie geschrieben haben:
str
. Es ist nicht garantiert, mit index
bytes zu beginnen. GetStrLen
, Sie setzen es nur in InsertChar
. Es könnte den Wert -19281281 haben, wenn das Programm startet. Was passiert, wenn jemand GetStrLen
aufruft, bevor er index
? InsertChar
in InsertChar
. Was passiert, wenn jemand StrReverse
zweimal hintereinander anruft? revStr
, erstellen Sie eine umgekehrte Zeichenkette namens str
, aber Sie tun nie etwas damit. Die Zeichenkette in index
bleibt nach dem letzten Zeichen gleich. Der verwirrende Teil für mich ist, warum Sie eine neue Variable mit dem Namen StrLen
erstellt haben, vermutlich um den Index des vorletzten Zeichens der Zeichenkette zu verfolgen, wenn zu diesem Zweck bereits eine Variable namens index
vorhanden war , die du völlig ignoriert hast. Der Index des vorletzten Zeichens ist die Länge der Zeichenkette. Sie sollten daher die Länge der Zeichenkette auf dem neuesten Stand halten und diese verwenden, z. B.
Ihr Algorithmus zur Stringumkehr ist jedoch völlig falsch. Denken Sie darüber nach, was dieser Code sagt (vorausgesetzt, str
wird an anderer Stelle korrekt initialisiert und aktualisiert). Es heißt "für jedes Zeichen in revStr
, überschreibe die Gesamtheit von str
, rückwärts, mit diesem Zeichen". Wenn "Hello World"
mit revStr
begonnen hat, wird "ddddddddddd"
mit d
enden, da str
das letzte Zeichen in StrLen = 10
ist.
Was Sie tun sollten, ist etwa so:
%Vor% Beachten Sie, wie das funktioniert. Sag das str
. Dann kopieren wir Position 0 von revStr
in Position 9 von str
und positionieren dann 1 von 9
in Position revStr
von StrLen - 1
, usw., bis wir die Position str
of% kopieren co_de% in Position 0 von revStr
.
Aber dann hast du eine umgekehrte Zeichenkette in revStr
und du verpasst immer noch den Teil, wo du das in str
zurücklegst, also würde die komplette Methode wie
Und es gibt klügere Wege, dies zu tun, wo Sie keine temporäre Zeichenfolge revStr
haben müssen, aber das obige ist perfekt funktional und wäre eine richtige Antwort auf das Problem.
Übrigens brauchen Sie sich in diesem Code wirklich keine Gedanken um NULL-Bytes (
s) zu machen. Die Tatsache, dass Sie die Länge des Strings mit der Variablen StrLen
StrLen
verfolgen (oder zumindest sein sollten), macht den End-Sentinel überflüssig, da Sie mit str
bereits den Punkt kennen, hinter dem der Inhalt von %code% liegen sollte ignoriert.
Ihre Funktion GetStrLen()
funktioniert nicht, weil das Array str
nicht initialisiert ist. Es enthält wahrscheinlich keine Nullelemente.
Sie benötigen das index
-Member nicht. Verwenden Sie einfach StrLen
, um die aktuelle Stringlänge zu verfolgen.
Bei dieser Prüfungsfrage gibt es viele interessante Lektionen zu lernen. Erstens erscheint der Prüfer nicht selbst einem fließenden C ++ - Programmierer! Vielleicht möchten Sie sich den Stil des Codes ansehen, einschließlich der Frage, ob die Variablen und Methodennamen aussagekräftig sind, sowie einige der anderen Kommentare, die Sie über die Verwendung von (void)
, const
usw. gegeben haben die Methodennamen brauchen wirklich "Str" in ihnen? Wir arbeiten schließlich mit einer "Strings" -Klasse!
Für "wie Strings in C ++ konstruiert sind", sind sie (wie in C) null-terminiert und speichern nicht die Länge mit ihnen, wie es Pascal (und diese Klasse) tut. [@Gustavo, strlen()
wird hier nicht funktionieren, da die Zeichenfolge keine mit Null abgeschlossene Zeichenfolge ist.] In der "realen Welt" würden wir die std::string
-Klasse verwenden.
"Der String darf nicht überlaufen", aber wie weiß der Benutzer der Klasse, wenn er versucht, den String zu überlaufen. @ Tylers Vorschlag, eine std::overflow_exception
(vielleicht mit einer Nachricht) zu werfen, würde funktionieren, aber wenn du deine eigene String-Klasse schreibst (rein als Übung, du bist sehr unwahrscheinlich, dass du das im richtigen Leben tun musst), solltest du es tun wahrscheinlich eine eigene Ausnahmeklasse bereitstellen.
"Die Einfügung von Zeichen erhöht seine Länge um 1", das bedeutet, dass GetStrLen()
nicht die Länge der Zeichenfolge berechnet, sondern den Wert von StrLen, der bei der Konstruktion initialisiert und durch Einfügen aktualisiert wurde, zurückgibt.
Vielleicht möchten Sie auch darüber nachdenken, wie Sie Ihre Klasse testen . Zur Veranschaulichung habe ich eine Print()
-Methode hinzugefügt, so dass Sie den Inhalt der Klasse betrachten können, aber Sie sollten sich wahrscheinlich etwas wie Cpp Unit Lite ansehen.
Für was es wert ist, schließe ich meine eigene Implementierung ein. Im Gegensatz zu den anderen Implementierungen habe ich mich für die Verwendung von Raw-Pointers in der umgekehrten Funktion und deren Swap-Helper entschieden. Ich habe vermutet, dass die Verwendung von Dingen wie std::swap
und std::reverse
außerhalb des Rahmens dieser Untersuchung liegt, aber Sie werden sich mit der Standard-Bibliothek vertraut machen, so dass Sie ohne Räder neu erfinden und programmieren können.
Viel Glück mit dem Rest deines Studiums!
Dein Lehrer hat dir sehr gute Hinweise auf die Frage gegeben, lies es noch einmal und antworte dir selbst. Hier ist meine ungeprüfte Lösung:
%Vor% Wenn Sie das char-Array initalisieren, sollten Sie sein erstes Element auf 0 setzen und dasselbe für index
. So bekommst du eine seltsame Länge in GetStrLen
, da es an den Göttern liegt, wenn du die 0 findest, nach der du suchst.
[Update] In C / C ++, wenn Sie Ihre Variablen nicht explizit initialisieren, werden Sie normalerweise mit Zufallsmüll gefüllt (der Inhalt des ihnen zugewiesenen Rohspeichers). Es gibt einige Ausnahmen von dieser Regel, aber die beste Vorgehensweise besteht darin, Ihre Variablen immer explizit zu initialisieren. [/ Update]
In InsertChar
sollten Sie (nach der Überprüfung auf einen Überlauf) StrLen
verwenden, um das Array zu indizieren (wie im Kommentar angegeben "ein Zeichen 'ch' am Ende der Zeichenfolge 'str'" einfügen) und dann setzen der neue Abschluss 0 Zeichen und erhöhen StrLen
.
Sie benötigen index
nicht als Mitgliedsdaten. Sie können eine lokale Variable haben, wenn Sie das möchten, in GetStrLen()
: deklarieren Sie sie einfach dort und nicht im Klassenkörper. Der Grund, warum Sie einen seltsamen Wert erhalten, wenn Sie index
zurückgeben, ist, dass Sie ihn nie initialisiert haben. Um das zu beheben, initialisiere index
auf Null in GetStrLen()
.
Aber es gibt einen besseren Weg, Dinge zu tun: Wenn Sie ein Zeichen über InsertChar()
increment einfügen, müssen Sie den Wert von StrLen
eingeben, damit GetStrLen()
nur diesen Wert zurückgibt. Dadurch wird GetStrLen()
viel schneller: Es wird in konstanter Zeit ausgeführt (dieselbe Leistung unabhängig von der Länge der Zeichenfolge).
In InsertChar()
können Sie StrLen
als Index und nicht index
verwenden, was, wie wir bereits festgestellt haben, redundant ist. Aber denken Sie daran, dass Sie sicherstellen müssen, dass die Zeichenfolge mit einem '
-Wert endet. Denken Sie auch daran, StrLen
'GetStrLen()
beizubehalten, indem Sie es erhöhen, um InsertChar()
das Leben leichter zu machen. Außerdem müssen Sie den zusätzlichen Schritt in StrReverse()
ausführen, um einen Pufferüberlauf zu vermeiden. Dies geschieht, wenn der Benutzer ein Zeichen in die Zeichenfolge einfügt, wenn die Länge der Zeichenfolge bereits 79 Zeichen beträgt. (Ja, 79: Sie müssen ein Zeichen für die abschließende Null ausgeben).
Ich sehe keine Anweisung, wie man sich verhalten soll, wenn das passiert, also muss es nach Ihrem guten Urteilsspruch sein. Wenn der Benutzer versucht, das 80. Zeichen hinzuzufügen, könnten Sie die Anfrage ignorieren und zurückgeben, oder Sie könnten ein Fehler-Flag setzen - es liegt an Ihnen.
In deiner GetStrLen()
Funktion hast du ein paar Fehler. Zuerst rufen Sie '
auf, ignorieren aber dessen Rückgabewert. Warum rufen Sie es dann an? Zweitens erstellen Sie eine temporäre Zeichenfolge und arbeiten daran und nicht am Zeichenfolgenelement der Klasse. Ihre Funktion ändert also das String-Element nicht, wenn es es tatsächlich umkehren soll. Und zuletzt könnten Sie die Zeichenfolge schneller umkehren, indem Sie nur die Hälfte durchlaufen. f(void)
'
Arbeiten Sie an der Mitgliedsdatenfolge. Um eine Zeichenkette umzukehren, können Sie das erste Element (Zeichen) der Zeichenkette mit ihrer letzten (nicht die abschließende Null, das Zeichen unmittelbar davor!), Das zweite Element mit der zweitletzten und so weiter austauschen. Sie sind fertig, wenn Sie in der Mitte der Saite ankommen. Vergessen Sie nicht, dass die Zeichenfolge mit einem f()
-Zeichen enden muss.
Während Sie die Prüfung bestanden haben, wäre es auch eine gute Gelegenheit, Ihrem Kursleiter etwas über C ++ beizubringen: Wir sagen nicht int GetStrLen(void)
, weil das zu den alten Tagen von C89 gehört. In C ++ sagen wir int GetStrLen() const
. Wir bemühen uns auch in C ++, Klasseninitialisierungslisten zu verwenden, wann immer wir können. Erinnere deinen Lehrer auch daran, wie wichtig die const-Korrektheit ist: Wenn eine Funktion nicht geändert werden soll, sollte das Objekt als solches markiert sein. %code% sollte %code% sein.
Sie müssen nicht die Länge herausfinden. Sie wissen es bereits, es ist strLen. Außerdem gab es in der ursprünglichen Frage nichts, das darauf hinwies, dass der Puffer eine nullterminierte Zeichenfolge enthalten sollte.
%Vor%Wenn Sie hier nur eine Assertion verwenden, können Sie eine Ausnahme auslösen.
%Vor%Das Umkehren der Zeichenfolge ist nur eine Frage des Austausches der Elemente im Str-Puffer.
%Vor% Ich würde StrLen
verwenden, um die Länge der Zeichenfolge zu verfolgen. Da die Länge auch das Ende der Zeichenfolge angibt, können wir das zum Einfügen verwenden:
Zuerst, warum verwenden Sie String.h für die Zeichenfolge Länge? Das Array strlen (char []) gibt das Lenght- oder ein beliebiges char-Array als int zurück.
Ihre Funktion gibt einen werid-Wert zurück, weil Sie niemals den Index initialisieren und das Array Nullwerte hat, initialisieren Sie zuerst und führen Sie dann Ihre Methode aus.