Wortzusammensetzung über Pointer und getline() statt mit gets()
-
silent_max schrieb:
Bei diesem Code bekomme ich jedoch die wüßten Fehlermeldungen.
Welche? Und was verstehst du an den Fehlermeldungen nicht?
silent_max schrieb:
Auch habe ich in meinen Büchern nichts verwertbares dazu gefunden.
Wonach hast du denn genau gesucht?
silent_max schrieb:
Was habe ich falsch gemacht bzw. wo ist mein Denkfehler?
Eine ganze Menge. Dein aktueller C++-Lern-Ansatz scheint sehr ineffizient zu sein. Ich kann nicht glauben, dass du die Bücher, die du angeblich besitzt, richtig verwendest. Dein zweites Programm ergibt von vorne bis hinten keinen Sinn. Erzähl mal, was du dir dabei gedacht hast.
-
Sone schrieb:
Aber wozu das Leben schwer machen?
Was heißt schwer machen?
Ich wollte einfach wissen, ob das klappt oder nicht. Und da mein Denkansatz wohl falsch ist, wollte ich euch Profis nach Tipps und Tricks fragen, wie ich über Pointer auf chars und der Funktion getline() ein Wort zusammen fügen kann, da ja die Funktion gets() verpönnt ist.
Gruß
-
Was soll an getline mit char-Arrays besser sein?
-
silent_max schrieb:
... wollte ich euch Profis nach Tipps und Tricks fragen ...
Die Tips und Tricks lauten ganz einfach:
Benutze - wo immer es geht - std::string anstelle von C-Strings.
-
manni66 schrieb:
Was soll an getline mit char-Arrays besser sein?
Ne ganze Menge.
-
Sone schrieb:
std::cout << "Zusammengesetztes Wort: " << strinst << '\n' << "Speicheradresse vom ersten Wort: " << reinterpret_cast<void const*>(str .c_str()) << '\n' << "Speicheradresse vom zweiten Wort: " << reinterpret_cast<void const*>(str2 .c_str()) << '\n' << "Speicheradresse vom zusammengesetzten Wort: " << reinterpret_cast<void const*>(strinst.c_str()) << '\n'; }static_casthätte es auch getan.
-
Belli schrieb:
Die Tips und Tricks lauten ganz einfach:
Benutze - wo immer es geht - std::string anstelle von C-Strings.Das würde ich noch einschränken. std::string braucht man nicht für Konstanten. const-char-Zeiger, die z.B. auf die Zeichenkettenliteral-Arrays zeigen, sind ja in Ordnung. Den Speicher, auf den sie zeigen, muss man nicht selbst verwalten und mit dem Read-Only-Zugriff kann man auch nicht viel Schaden anrichten.
Ich denke da an solche Situationen:
//im header string errormsg(int errorcode);//im cpp file const string emlist[] = { "foo", "bar" }; string errormsg(int errorcode) { if (errorcode<0 || errorcode>=2) return "wtf"; return emlist[errorcode]; }wo std::string eine ziemlich blöde Idee ist. Besser:
//im header const char* errormsg(int errorcode);//im cpp file const char*const emlist[] = { "foo", "bar" }; const char* errormsg(int errorcode) { if (errorcode<0 || errorcode>=2) return "wtf"; return emlist[errorcode]; }
-
Warum nicht so?
namespace { const std::array<std::string, 2> emlist = {{ "foo", "bar" }}; } const std::string &errormsg(unsigned errorcode) { assert(errorcode < emlist.size()); return emlist[errorcode]; }
-
TyRoXx schrieb:
Warum nicht so?
namespace { const std::array<std::string, 2> emlist = {{ "foo", "bar" }}; } const std::string &errormsg(unsigned errorcode) { assert(errorcode < emlist.size()); return emlist[errorcode]; }kk schrieb:
std::string braucht man nicht für Konstanten. const-char-Zeiger, die z.B. auf die Zeichenkettenliteral-Arrays zeigen, sind ja in Ordnung. Den Speicher, auf den sie zeigen, muss man nicht selbst verwalten und mit dem Read-Only-Zugriff kann man auch nicht viel Schaden anrichten.
-
Sone schrieb:
kk schrieb:
std::string braucht man nicht für Konstanten. const-char-Zeiger, die z.B. auf die Zeichenkettenliteral-Arrays zeigen, sind ja in Ordnung. Den Speicher, auf den sie zeigen, muss man nicht selbst verwalten und mit dem Read-Only-Zugriff kann man auch nicht viel Schaden anrichten.
Und was soll an dem Zeigergefrickel jetzt besser sein als
string?
Die paar gesparten Bytes zählen nicht. Die gesparte Indirektion auch nicht, das spielt bei Fehlerbehandlung keine Rolle.
-
TyRoXx schrieb:
Warum nicht so?
namespace { const std::array<std::string, 2> emlist = {{ "foo", "bar" }}; } const std::string &errormsg(unsigned errorcode) { assert(errorcode < emlist.size()); return emlist[errorcode]; }Mach, was du willst. Mir passt da die dynamische Initialisierung nicht, in der Zeichenketten aus dem statischen Speicher (die Literal-Arrays) kurz vor der Ausführung von main sinnloserweise in den Freispeicher kopiert werden. Damit gewinnst du noch nicht mal etwas...
std::stringbzwconst std::string&hier durchconst char*zu ersetzen ist keine Pointer-Frickelei.
-
TyRoXx schrieb:
Sone schrieb:
kk schrieb:
std::string braucht man nicht für Konstanten. const-char-Zeiger, die z.B. auf die Zeichenkettenliteral-Arrays zeigen, sind ja in Ordnung. Den Speicher, auf den sie zeigen, muss man nicht selbst verwalten und mit dem Read-Only-Zugriff kann man auch nicht viel Schaden anrichten.
Und was soll an dem Zeigergefrickel jetzt besser sein als
string?Und was soll in diesem Fall an
stringbesser sein?namespace { const std::array<char const*, 2> emlist = {{ "foo", "bar" }}; } char const* &errormsg(std::array<char const*, 2>::size_type errorcode) { assert(errorcode < emlist.size()); return emlist[errorcode]; }Edit:
std::string bzw const std::string& hier durch const char* zu ersetzen ist keine Pointer-Frickelei.

Wie kamst du darauf, Tyrox?Immer diese Vorurteile gegenüber Zeigern...
-
Auch dieser Code wird von meinem Compiler nicht angenommen:
#include<iostream> using namespace std; int main() { char Text_1[160]; char *pText_1 = {&Text_1[160]}; char Text_2[80]; char *pText_2 = {&Text_2[80]}; char Text_3[80]; char *pText_3 = {&Text_3[80]}; cout << "Erstes Wort eingeben:\n"; gets(&Text_2); cout << "Zweites Wort eingeben:\n"; gets(&Text_3); strcpy(&Text_1, &Text_2); strcat(&Text_1, &Text_3); cout << "Zusammengefuegtes Wort:" << &Text_1 << "\n"; cout << "Speicheradresse vom ersten Wort: " << &Text_2 << "\n"; cout << "Speicheradresse vom zweiten Wort: " << &Text_3 << "\n"; cout << "Speicheradresse vom zusammengefuegten Wort: " << &Text_1 << "\n"; return 0; }Dann kann ich die Idee ja völlig vergessen...
-
silent_max schrieb:
Auch dieser Code wird von meinem Compiler nicht angenommen
Was sagt er denn?
-
error C2664: 'gets': Konvertierung des Parameters 1 von 'char (*)[80]' in 'char *' nicht möglich error C2664: 'gets': Konvertierung des Parameters 1 von 'char (*)[80]' in 'char *' nicht möglich error C2664: 'strcpy': Konvertierung des Parameters 1 von 'char (*)[160]' in 'char *' nicht möglich error C2664: 'strcat': Konvertierung des Parameters 1 von 'char (*)[160]' in 'char *' nicht möglich
-
silent_max schrieb:
error C2664: 'gets': Konvertierung des Parameters 1 von 'char (*)[80]' in 'char *' nicht möglich error C2664: 'gets': Konvertierung des Parameters 1 von 'char (*)[80]' in 'char *' nicht möglich error C2664: 'strcpy': Konvertierung des Parameters 1 von 'char (*)[160]' in 'char *' nicht möglich error C2664: 'strcat': Konvertierung des Parameters 1 von 'char (*)[160]' in 'char *' nicht möglichWieso nimmst du denn auch die Adressen der Arrays?
Übergib' einfach direkt die Arrays, das array-to-pointer decay macht den Rest.
-
silent_max schrieb:
error C2664: 'gets': Konvertierung des Parameters 1 von 'char (*)[80]' in 'char *' nicht möglich error C2664: 'gets': Konvertierung des Parameters 1 von 'char (*)[80]' in 'char *' nicht möglich error C2664: 'strcpy': Konvertierung des Parameters 1 von 'char (*)[160]' in 'char *' nicht möglich error C2664: 'strcat': Konvertierung des Parameters 1 von 'char (*)[160]' in 'char *' nicht möglichVerstehst du diese Fehlermeldungen? Weißt du, was char(*)[80] ist?
-
Sone schrieb:
Und was soll in diesem Fall an
stringbesser sein?namespace { const std::array<char const*, 2> emlist = {{ "foo", "bar" }}; } char const* &errormsg(std::array<char const*, 2>::size_type errorcode) { assert(errorcode < emlist.size()); return emlist[errorcode]; }[...]
Immer diese Vorurteile gegenüber Zeigern...
In Zeile 8 sehe ich ein falsches
&. Beim Umgang mit Zeigern hast du also schon in so einem simplen Beispiel einen Flüchtigkeitsfehler gemacht. Mitstringwäre das nicht passiert.Ich sehe ja ein, dass die Speicheranforderung durch
stringverschwenderisch ist. Aberconst char *ist eindeutig die falsche Alternative. Die Idee von C++ ist nicht, dass man bei jedem kleinen Hindernis in prähistorisches Verhalten zurückfällt.Die Vorteile von
stringohne die Nachteile:#include <utility> #include <iostream> #include <array> #include <cassert> #include <cstring> template <class C> class basic_string_ref { public: typedef C value_type; typedef C &reference; typedef C *iterator; typedef iterator const_iterator; typedef std::size_t size_type; basic_string_ref(); basic_string_ref(iterator begin, iterator end); template <std::size_t N> basic_string_ref(value_type (&data)[N]); basic_string_ref(iterator c_string) : m_begin(c_string) , m_end(c_string + std::strlen(c_string)) { } size_type size() const { return std::distance(m_begin, m_end); } iterator data() const { return m_begin; } bool empty() const; iterator begin() const { return m_begin; } iterator end() const { return m_end; } //... private: iterator m_begin; iterator m_end; }; template <class C> std::basic_ostream<typename std::remove_const<C>::type> &operator << ( std::basic_ostream<typename std::remove_const<C>::type> &os, basic_string_ref<C> const &str) { std::copy(str.begin(), str.end(), std::ostreambuf_iterator<typename std::remove_const<C>::type>(os)); return os; } typedef basic_string_ref<char> string_ref; typedef basic_string_ref<const char> cstring_ref; namespace { const std::array<cstring_ref, 2> emlist = {{ "foo", "bar" }}; } cstring_ref const &errormsg(unsigned errorcode) { assert(errorcode < emlist.size()); return emlist[errorcode]; } int main() { for (auto i = emlist.begin(); i != emlist.end(); ++i) { std::cout << *i << '\n'; } }EDIT:
const-Verhalten korrigiert (danke an krümelkacker).
-
TyRoXx schrieb:
Ich sehe ja ein, dass die Speicheranforderung durch
stringverschwenderisch ist. Aberconst char *ist eindeutig die falsche Alternative.Das ist deine Meinung, die ich nicht mit dir teile.
TyRoXx schrieb:
Die Idee von C++ ist nicht, dass man bei jedem kleinen Hindernis in prähistorisches Verhalten zurückfällt.
Hast du ein anderes Argument als "ich finde, das gehört nur in die Prähistorie" parat? Denn es ist keins.
TyRoXx schrieb:
Die Vorteile von
stringohne die Nachteile:
[...]Das finde ich nicht überzeugend genug, als dass ich behaupten wollen würde, alles andere sei "eindeutig falsch".
Ich denke auch, dass du dein basic_string_ref nicht ganz zu Ende gedacht hast. Die const/nonconst Überladungen für begin/end finde ich komisch. Das passt einfach nicht zur restlichen Referenz/Zeiger-Semantik, die dieser Typ hat. Ist Dir schon mal aufgefallen, dass ein shared_ptr<T> folgenden Dereferenzierungsoperator bietet?
T& operator*() const ^^ ^^^^^Das const überträgt sich da nicht auf den Rückgabetyp bei so einem Zeiger-artigem Objekt. Und das ist auch sinnvoll so; denn ein "deep const" bringt nichts, wenn man das Objekt kopieren kann und über die non-const Kopie auf dieselben Daten zugreifen kann. Ich hätte bei dir folgendes erwartet:
T* begin() const {...} T* end() const {...}und dann am besten noch einen Konvertierungskonstruktor für string_ref -> cstring_ref eingebaut.
Aber wie unterscheidet sich jetzt cstring_ref von const char*? So, wie du es aktuell gebaut hast, beschränken sich die Unterschiede auf ein "STL Interface". Ein STL Interface ist nett, brauche ich aber bei Stringkonstanten so gut wie nie.
Das praktische an so einem benutzerdefinierten Typ ist nicht die Rückgabe von strings, sondern das Empfangen von Strings als Funktionsparameter. Man kann den Typ so bauen, dass dem Benutzer das ".c_str()" erspart bleibt, wenn er einen std::string zur Hand hat. Wenn ich mich richtig erinnere, ist das auch die Motivation des string_ref-Proposals.
Ich gehöre zu den ersten, die sich über Zeiger-Frickelei aufregen. Habe auch schon in ähnlicher Form ein array_ref-Klassentemplate gebastelt, was sich mit allerlei Dingen hat initialisieren lassen (
std::vector,std::array, rohes Array) sogar mit so lustigen Konvertierungen wie std::vector<Dings*> --> array_ref<const Dings* const>, die C++ mit rohen Zeigern erlaubt, ohne dass das ein Problem wär.Aber const char* oder const char[] für Zeichenkettenkonstanten kann ich bei bestem Gewissen nicht verteufeln.
-
Sone schrieb:
Wieso nimmst du denn auch die Adressen der Arrays?
Übergib' einfach direkt die Arrays, das array-to-pointer decay macht den Rest.Wie meinst Du das??
Kannst Du nicht einen Beispielcode schreiben? Weil ich verstehe bei "array-to-pointer decay" nicht, was Du meinst...