String einlesen und als nicht durch 0 terminiertes char-Array speichern, genaueres Inside...
-
doch, das geht schon. indem man z.b. eine klasse baut, die den char* cast-operator überlädt, sich also wie nen char verhält, mit ner referenz auf das nicht terminierte char array versorgt und die entsprechenden pointer operatoren überlädt, um bei zugriff auf das "letzte" element eine erzwungene 0 zurückzuliefern.
-
ok dann sollte ich evtl. noch die beiden weiteren Teile der Aufgabe posten, vielleicht lichtet sich dann der nebel
:
b) Geben Sie eine Methode für die Verkettung von Instanzen dieser Klasse an (concatenate-Operator "+")
c) Erstellen Sie einen Copy-Konstruktor und überladen Sie den Zuweisungsoperator!
Ich habe bisher nur in Java programmiert, und deshalb sind gerade diese Aufgaben für mich doch recht heftig. Sonst würde ich auch nicht nach Hilfe fragen...
-
thordk schrieb:
doch, das geht schon. indem man z.b. eine klasse baut, die den char* cast-operator überlädt, sich also wie nen char verhält, mit ner referenz auf das nicht terminierte char array versorgt und die entsprechenden pointer operatoren überlädt, um bei zugriff auf das "letzte" element eine erzwungene 0 zurückzuliefern.
Glaub kaum das sowas verlangt wird, wenn man sich den Rest der Aufgabe anschaut.
-
vielleicht bin ich auch einfach nur zu dumm um die Aufgabe zu verstehen und sie zu lösen, aber selbst wenns so ist wäre ich wirklich unendlich dankbar wenn mir vielleicht jemand auf die Sprünge helfen würde...
-
Schreib ne Klasse String mit dem Konstruktor, ermittle die länge des übergebenen Strings und kopier den in ein entsprechend großes array und speicher die länge in ner variable. (Hier keine Kopie zu machen wäre sehr gefährlich)
-
mit kopien zu arbeiten ist wesentlich sicherer, viel einfacher und generell vorzuziehen. ich würds einfach machen und in den kommentar schreiben, aus welchen gründen eine kopie erzeugt wird.
mein schnellschuss mit dem char* container hat z.b. nicht berücksichtigt, dass polymorphie für primitive objekte nicht funktioniert
-
gehtnix schrieb:
...Wenn intern kein 0 terminiertes Array gespeichert werden darf,...
Ich glaube nicht, dass diese Aufgabe derart spitzfindig gemeint ist.
Ich denke mal, der Aufgabensteller möchte hier, dass der Umgang mit expliziten Längen (und nicht mit strlen(), strcpy, ...) geübt/demonstriert wird.
Und das "Kopieverbot" ist vermutlich auch eher als Vereinfachung gedacht (und vielleicht soll ja in der Folgeübung gezeigt werden, wo dabei die Gefahren liegen).
Also im Prinzip ist nur doch das hier:das heißt also, ich soll eine Klasse String entwerfen, mit der Speicherung einer Zeichenkette, und einer Methode um die Zeichenkette wieder auszugeben-
in Source zu gießen.
Ich an Stelles des OPs würde einfach mal loslegen und mir nicht im Vorhinein alle möglichen Interpretationsweisen des Aufgabentextes durchphilosophieren.
Und wenn dann ein konkretes Ergebnis da ist, können wir hier ja noch Verbesserungsmöglichkeiten/Alternativen diskutieren....
Ist doch eine Programmieraufgabe und keine Exegese, oder ?Gruß,
Simon2.
-
Die Aufgabe ist IMO komplett dämlich formuliert. Wer auch immer sie formuliert hat ist IMO ganz weit davon entfernt geeignet zu sein um C++ zu unterrichten.
Alleine das fehlende const im ctor und die Formulierung "Rückgabe ist \0-terminiertes char-array"... OMFG. Bin ich froh dass ich damit nichts zu tun habe!
-
Ich glaube hier soll auch nicht C++, sondern Programmieren unterrichtet werden.
-
doppeldeutig schrieb:
Ich glaube hier soll auch nicht C++, sondern Programmieren unterrichtet werden.
Und dann ist es OK so mies formulierte Aufgaben zu stellen?
BTW: ich glaube auch nicht dass wer auch immer das geschrieben hat kompetent ist Programmieren zu unterrichten. Dafür schreibt er zu schluderig.
-
hustbaer schrieb:
Die Aufgabe ist IMO komplett dämlich formuliert. Wer auch immer sie formuliert hat ist IMO ganz weit davon entfernt geeignet zu sein um C++ zu unterrichten.
Alleine das fehlende const im ctor und die Formulierung "Rückgabe ist \0-terminiertes char-array"... OMFG. Bin ich froh dass ich damit nichts zu tun habe!Ich wollte gerade das selbe schreiben, aber nun brauche ich es ja nicht mehr ...
-
genau das finde ich ja auch, aber naja ich komme nicht drum rum und muss mit dem doch recht unordentlichen unterlagen zurechtkommen. ich habe jetzt zum testen mal was gecoded, was aber komischerweise nicht funktioniert. ich hab erstmal ein simples proggie geschrieben welches ein objekt erzeugt usw. ich weiß die art und weise sieht komisch aus ich hab jetzt viel getestet aber es geht nicht und dann habe ich mich an ein listing aus meinem buch gehalten doch es geht trotzdem nicht!
hier erstmal der code:
#include <iostream> using namespace std; class TestObjekt { public: TestObjekt(int x); ~TestObjekt(); int getWert(); private: int x_hide; }; TestObjekt::TestObjekt(int x) { x_hide=x; } TestObjekt::~TestObjekt(){} int TestObjekt::getWert() { return x_hide; } int main() { int eingabe=0; TestObjekt *test; cout<<"Bitte geben Sie einen Int-Wert ein! \n"; cin>>eingabe; test=new TestObjekt(eingabe); cout<<"Der Int-Wert lautet: \n"; cout<<test.getWert(); cin.get(); cin.get(); return 0; }
es kommt jedesmal wenn ich versuche auf die Memberfunktion getWertzuzugreifen der Fehler "getneueKlasse has not been declared".
ich kenne das alles nur aus Java und würde meinen dass ich keinen Zugriff auf die Methode habe. Aber wieso?
Da scheint es ein elementares Verständnisproblem zu geben bei mir, hoffe mir kann da jemand helfen!
Btw.: Ich habe den Code eigentlich anders geschrieben, dieser ist jetzt sehr an mein Buch angelehnt ich kann aber gerne nochmal meine "interpretation" davon posten falls dieser hier doch total falsch sein sollte.
edit:
also ich hab das doch hinbekommen, die Erzeugung des Objekts lief wohl falsch und daher konnte der Konstruktor das Objekt nicht so "bauen" dass daraus im Folgenden die Methode getWert nicht auf das Objekt zugreifen konnte. Wäre natürlich für eine genauere Erläuterung des Fehlers dankbar.
Code sieht jetzt folgendermaßen aus:
#include <iostream> using namespace std; class TestObjekt { public: TestObjekt(int x); ~TestObjekt(); void setWert(int y); int getWert(); private: int x_hide; }; TestObjekt::TestObjekt(int x) { x_hide=x; } TestObjekt::~TestObjekt(){} void TestObjekt::setWert(int x) { x_hide=x; } int TestObjekt::getWert() { return x_hide; } int main() { int eingabe=0; TestObjekt test(eingabe); cout<<"Der Standard-Int-Wert lautet: \n"; cout<<test.getWert()<<"\n"; cout<<"Bitte geben Sie einen Int-Wert ein! \n"; cin>>eingabe; test.setWert(eingabe); cout<<"Der Int-Wert lautet jetzt: \n"; cout<<test.getWert(); cin.get(); cin.get(); return 0; }
Jetzt muss ich das ganze erstmal umbauen das char-Arrays anstatt Int-Werte übergeben und gelesen bzw. gesetzt werden können...
-
test.getWert() muss test->getWert() heissen, und du solltest das erstellte Objekt wieder löschen (C++ ist ja nicht Java
).
Ansonsten wäre es gut wenn du 1:1 den Code postest den du auch ausprobiert hast.("getneueKlasse" kommt in deinem Code schonmal garnicht vor, daher kann es nicht der Code sein der zu der Fehlermeldung mit "getneueKlasse" führt)
-
Hey,
das "getNeueKlasse" stammt noch aus dem Beitrag bevor ich ihn editiert habe, habe den zum Besseren Verständnis quasi "on the fly" nochmal bearbeitet und dann editiert gepostet.
Das Proggie läuft jetzt schonmal, aber nun habe ich ein weiteres kleines Problem, denn nun habe ich umgebaut auf char-Arrays... Zunächst mal der Code:
#include <iostream> using namespace std; class TestObjekt { public: TestObjekt(char x[]); ~TestObjekt(); void setWert(char y[]); char* getWert(); private: char x_hide[20]; }; TestObjekt::TestObjekt(char x[]) { strcpy(x_hide,x); } TestObjekt::~TestObjekt(){} void TestObjekt::setWert(char y[]) { strcpy(x_hide,y); } char* TestObjekt::getWert() { return x_hide; } int main() { char eingabe[20]="Hello"; TestObjekt test(eingabe); cout<<"Testzeichenkette (vordefiniert): \n"; cout<<test.getWert()<<"\n"; cout<<"Bitte geben Sie eine Zeichenkette ein! \n"; cin>>eingabe; test.setWert(eingabe); cout<<"Die Zeichenkette lautet jetzt: \n"; cout<<test.getWert(); cin.get(); cin.get(); return 0; }
Das Proggie läuft, die Methoden funktionieren so wie sie sollen. Jetzt habe ich ein paar Probleme beim weiteren Vorgehen hinsichtlich der Aufgabenstellung:
a) Wie kann ich das "Ergebnis" der Methode getWert() im Hauptprogramm zwischenspeichern?
b) Ich möchte die eingegebene Länge der Zeichenkette aus dem Rückgabewert der getWert_Funktion zwischenspeichern; das Problem ist anscheinend der Pointer der zurückgegeben wird, denn der Compiler meckert bei dem Versuch von z.B. temp=test.getWert();, wobei ich temp als 20stelliges char-Array vorher schon initialisiert habe.
Mir würde spontan jetzt nur eine for-Schleife zum durchlauf des EIngabe-arrays einfallen mit einem Counter...
Würde mich über ein paar Anregungen wirklich freuen...
!
edit: ich kann übrigens mit delete test; das erzeugte Objekt NICHT löschen; der Compiler sagt dazu folgendes:
type 'class TestObjekt' argument given to 'delete', expected pointer
da kann also was nicht stimmen...
-
Jetzt ist es ja auch kein Zeiger mehr wie in dem Beispiel vorhin, deswegen musst du es jetzt auch nicht löschen.
Ansonsten: der Sinn der Klasse die du da schreibst ist dass du sie verwenden kannst um Strings zwischenzuspeichern. Davon abgesehen ist wahrscheinlich gemeint dass man das Array immer nur so gross machen soll wie nötig. Das geht nur wenn du den Speicher dynamisch anforderst.
Um das ganze abzurunden solltest du dann auch noch den Zuweisungsoperator (operator
implementieren, damit du Objekte der Klasse String auch kopieren kannst.
BTW: es ist gängige Praxis Membervariablen mit "m_name" zu benennen, also "m_x" statt "x_hide". Das ist zwar nicht die einzige "naming convention" die es da gibt, aber nach dem was ich bis jetzt an Code gesehen habe eine der meist verwendeten (wenn nicht die meist verwendete).
-
hustbaer schrieb:
Jetzt ist es ja auch kein Zeiger mehr wie in dem Beispiel vorhin, deswegen musst du es jetzt auch nicht löschen....
Nur, um Missverständnissen bei LogicCube vorzubeugen (hustbaer weiß das natürlich viel besser als ich):
Es müsste heißten:Jetzt ist es ja auch kein Zeiger mehr, der auf ein dynamisch erzeugtes Objekt verweist wie in dem Beispiel vorhin, deswegen musst du es jetzt auch nicht löschen....
... und selbst bei dynamisch erzeugten Objekten muss man nicht "immer" löschen, sondern "genau einmal".
Ist ein wenig spitzfindig, aber Leuten, die da noch nicht so ganz fit sind, helfen vermutlich möglichst eindeutige Formulierung, damit sie es nicht "in den falschen Hals bekommen".
Gruß,
Simon2.
-
Hey,
gut dann wäre also der erste "sinnvolle" Schritt jetzt erstmal die char-arrays so zu konstruieren dass deren Länge dynamisch bereitgestellt wird, also nur so lang sind wie die vom Benutzer eingegebene Zeichenkette.
Jetzt wäre die "billige" Variante, ein größeres Arrays bereitzustellen, die Zeichenkette einzulesen und dann evtl. mit sizeof(array) die Länge zu bestimmen, ein neues Array mit genau der Länge zu erzeugen und das Ganze umzuspeichern, dem Konstruktor und den beiden Methoden der Klasse String einen weiteren Paramater "Länge" hinzuzufügen und das Ganze dann eben umzustricken.
Die Variante ist aber nicht wirklich elegant finde ich.
Hat vielleicht jemand einen "Tip" wie man das Array für die eingelesene Zeichenkette dynamisch erstellen kann so dass direkt passend viele Stellen erzeugt werden? Das hört sich vielleicht blöd an ich weiß aber es wäre halt interessant zu wissen und ich würde gerne versuchen das so weiter zu bearbeiten...
-
Man merkt, dass du von Java kommst
Das mit dem sizeof(array) funktioniert so (in diesem Fall) in C++ leider nicht...
Um die Länge eines nullterminierten char-arrays festzustellen, bleibt dir wohl nichts anderes übrig, als die strlen()-Funktion aus der C-Standardbibliothek zu verwenden, oder das Verhalten dieser nachzubauen:void MyString::ComputeLength(const char* array) { mSize = strlen(array) - 1; //bzw. while(*array != '\0') { mSize++; array++; } }
In beiden Fällen hab ich jetzt angenommen, dass du das Nullbyte nicht mitkopieren möchtest.
Jetzt kannst du dynamisch Speicher anfordern, um das Array aufzunehmen:
void MyString::AllocateSpace() { mInnerArray = new char[mSize]; //mInnerArray ist vom Typ char* }
Und weil C++ nicht Java ist, musst du den Speicher beim Zerstören des Objektes auch wieder freigeben
MyString::~MyString() { ... delete[] mInnerArray }
Grüße
Martin
-
LogicCube schrieb:
...
Hat vielleicht jemand einen "Tip" wie man das Array für die eingelesene Zeichenkette dynamisch erstellen kann so dass direkt passend viele Stellen erzeugt werden? ...Japp - ist nicht schwer:
class TestObjekt { public: TestObjekt(char const x[]); ~TestObjekt(); void setWert(char const y[]); char* getWert(); private: char *x_hide; size_t len; }; TestObjekt::TestObjekt(char const x[]) : x_hide(new char[strlen(x)), len(strlen(x)) { strcpy(x_hide,x); } TestObjekt::~TestObjekt(){ delete[] x_hide; // hier solltest Du löschen, weil obe dynamisch alloziert } // ...
ACHTUNG: Dieser Code ist hochgradig unsicher !!!
Folgendes z.B. führt zu undefiniertem Verhalten:int main() { TestObjekt a("Simon2"); a.setWert("mehr Bytes"); // -> BOOM delete[] a.getWert(); // -> Hoppla ! Objekt hat keinen Speicher mehr und weiß es nichtmal ...
Hilfen könnten sein:
- setWert() kopiert höchsten len viele Zeichen oder
- setWert() alloziert neuen Speicher (und kopiert und delete[]-t den alten)
- getWert() liefert einenchar const*
zurückPrinzipiell sind char*-Geschichten immer unsicher ... es garantiert Dir z.B. niemand, dass der Initialwert überhaupt auf einen 0-terminierten String verweist.
Schön versteckt:char c[6] = "Simon2"; // 0-Byte passt nicht mehr rein TestObjekt a(c); // Hoppla ....
EDIT:
JimmydaMage schrieb:
...
mSize = strlen(array) - 1;
...
stimmt nicht . strlen() zählt NICHT das 0-Byte mit.
Gruß,
Simon2.
-
Hey,
das hört sich vom Ansatz her schonmal sehr gut an! Auch das mit dem nicht mitkopieren der terminierungs-0 am ende; jetzt könnte man ja im prinzip zunächst ausgeben wie lang die zeichenkette MIT 0 ist, und dann wenn man die zeichenkette zwischenspeichert in der klasse String (selbstgebaut), nochmal eine ausgabe (die ja dann logischerweise genau um 1 kleiner wäre) machen um zu zeigen das man wirklich die erminierungs-0 wegläßt!
ich muss jetzt zur arbeit (ja studenten brauchen auch geld
) und werde mich dann sobald ich abends nach hause komme dran machen das ganze zu implementieren; es ist zwar noch ein weiter weg, aber dafür bin ich nachher umso besser gelaunt wenn es dann tatsächlich kompett funktionieren sollte
Vielen Dank schonmal, bis heute abend!