C ++ - Prüfung zur Implementierung von String-Klassen

8

Ich habe gerade eine Prüfung gemacht, bei der ich folgendes gefragt wurde:

  

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   
%Vor%

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.

    
Carlos 07.05.2010, 21:45
quelle

11 Antworten

17

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:

  1. Sie initialisieren niemals den Inhalt von str . Es ist nicht garantiert, mit index bytes zu beginnen.
  2. Sie initialisieren nie 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 ?
  3. aufruft?
  4. Sie aktualisieren nie InsertChar in InsertChar . Was passiert, wenn jemand StrReverse zweimal hintereinander anruft?
  5. In 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.

%Vor%

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

aussehen %Vor%

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 ( StrLen s) zu machen. Die Tatsache, dass Sie die Länge des Strings mit der Variablen 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.

    
Tyler McHenry 07.05.2010, 21:57
quelle
4
%Vor%

Sie bekommen einen merkwürdigen Wert, weil Sie den Index nie initialisiert haben, Sie haben gerade angefangen ihn zu erhöhen.

    
dbyrne 07.05.2010 21:50
quelle
4

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.

    
Kristopher Johnson 07.05.2010 21:51
quelle
4

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.

> %Vor%

Viel Glück mit dem Rest deines Studiums!

    
Johnsyweb 09.05.2010 04:28
quelle
2
%Vor%

Dies sollte etwas mehr wie

sein %Vor%     
Earlz 07.05.2010 21:53
quelle
2

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%     
CodexDraco 07.05.2010 22:01
quelle
2

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 .

    
Péter Török 07.05.2010 21:50
quelle
2

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 'StrLen' -Wert endet. Denken Sie auch daran, 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 'f(void)' 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.

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.

    
wilhelmtell 07.05.2010 22:11
quelle
1

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%     
Brian Matthews 07.05.2010 21:56
quelle
1

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:

%Vor%     
R Samuel Klatchko 07.05.2010 21:58
quelle
1

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.

    
Gustavo Barrientos 07.05.2010 22:30
quelle

Tags und Links