PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zwei kleine Fragen zu C++ Standardklassen


SamStone
2006-05-06, 16:25:42
Jetzt mal zwei richtige Noobfragen.

Erstens zu Streams: Wie kann man mit Input Streams ganze Zeilen einlesen?
Wenn man z.B. das macht:
cin >> test;
Und die Eingabe lautet "test1 test2", dann wird in test ja nur "test1" gespeichert, weil der das in whitespaces trennt.
Es gibt zwar Elementfunktionen wie getline(), aber die beziehen sich ja auf C Strings.
Was ist der einfachste weg, alles bis zu einem Newline Zeichen (also anders gesagt eine ganze Zeile :rolleyes: ) in eine Variable einzulesen?

Zweitens zu Strings:
Wie kann ich einen kompletten String in Groß (oder Klein) Buchstaben umwandeln? Wenn ich das richtig sehe, dann hat die String Klasse keine eingebaute Methode dafür. Alternativ könnte man das ja sicher irgendwie per StringStreams machen, aber so wie ich das sehe, gibt es auch keine Manipulatoren, die alles in Großbuchstaben umwandeln.

Also selber schreiben kann ich eine solche Funktion natürlich selbst, aber irgendwo muss in den Standardklassen doch auch was entsprechendes eingebaut sein.

Expandable
2006-05-06, 16:45:25
Ganze Zeile einlesen z.B. so:


char chars[128];
std::cin.getline(chars, 128, '\n');
std::cout << "Ausgabe: " << chars;


Groß-/Kleinbuchstaben: String zeichenweise durchgehen und anhand dieser ASCII-Tabelle entscheiden, ob eine Umwandlung nötig ist: http://www.torsten-horn.de/techdocs/ascii.htm

Alternativ so:


#include <cctype>
#include <iostream>

int main()
{
char chars[128];
std::cin.getline(chars, 128, '\n');
for (int i = 0; i < 128; ++i)
chars[i] = tolower(chars[i]);
std::cout << "Ausgabe: " << chars;

return 0;
}


Oder mit std::string:


#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int main()
{
string str22 = "This IS a MiXed CaSE stRINg";
transform (str22.begin(),str22.end(), str22.begin(), tolower);
cout << "[" << str22 << "]" << endl;

return 0;
}

Trap
2006-05-06, 16:55:27
SamStone[/POST]']
Was ist der einfachste weg, alles bis zu einem Newline Zeichen (also anders gesagt eine ganze Zeile :rolleyes: ) in eine Variable einzulesen?


#include<string>
#include<iostream>

std::string x;
std::getline(std::cin,x);


Für in Kleinbuchstaben wandeln würd ich std::transform nehmen so wie schon von Expendable gepostet.

Expandable
2006-05-06, 18:29:34
Trap[/POST]']
#include<string>
#include<iostream>

std::string x;
std::getline(std::cin,x);



Cool, das wusste ich auch noch nicht... ;)

Trap
2006-05-06, 19:20:21
Expandable[/POST]']Cool, das wusste ich auch noch nicht... ;)
Ich hab das auch erst nach einiger Zeit gefunden, ist gut versteckt ;)

SamStone
2006-05-06, 20:24:05
Zum Großumwandeln: Jo so kann man es machen, danke.
Ich dachte halt nur, dass so etwas in der Art schon eingebaut ist, weil es ja denke ich ziemlich sinnvoll ist.

Zum std::getline: Jooo genau das hab ich gesucht.
Der Stroustrup schreibt diese Funktion komischerweise in das Kapitel zu den Strings, obwohl es im Stream Kapitel logisch viel sinnvoller aufgehoben wäre.

Danke euch.

SamStone
2006-05-06, 21:13:50
Expandable[/POST]']
int main()
{
string str22 = "This IS a MiXed CaSE stRINg";
transform (str22.begin(),str22.end(), str22.begin(), tolower);
cout << "[" << str22 << "]" << endl;

return 0;
}

Das hier klappt bei mir nicht. G++ zeigt mir da ein fehler bei dem tolower argument. Wenn ich das mit nem Umweg über ne Hilfsfunktion mache, dann klappt es.
Woran liegts?

Wenn ich das ganze genau so mit ner Funktionsklasse wrappe, dann funktioniert es problemlos:
struct grossumwandler: public unary_function <int, int>
{
int operator()(int i) { return toupper(i); }
};
//...
transform(test.begin(), test.end(), test.begin(), grossumwandler());


Mit transform(test.begin(), test.end(), test.begin(), toupper);
komischerweise halt nicht :| .

Expandable
2006-05-06, 23:24:24
Wie lautet die Fehlermeldung? cctype included?

SamStone
2006-05-07, 00:20:24
cctype ist included (auch wenn ich toupper benutzen kann, ohne das einzubinden).

sven@sven:~/C$ g++ -Wall test++.cpp
test++.cpp: In function »int main(int, char**)«:
test++.cpp:23: Fehler: keine passende Funktion für Aufruf von »transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unknown type>)«

Er erkennt also die toupper funktion vom typ her nicht anscheinend.

Könnte es sein, dass toupper aus optimierungsgründen oder so eine eingebaute funktion im g++ ist?

GloomY
2006-05-07, 18:43:19
Trap[/POST]']Für in Kleinbuchstaben wandeln würd ich std::transform nehmen so wie schon von Expendable gepostet.Alternativ wenn es auf Geschwindigkeit ankommt und man mit chars arbeitet:char c;
c &= ~0x20;Hier wird ausgenutzt, dass der "Abstand" von Klein- zu Großbuchstaben im ASCII-Code genau 32 beträgt. :)

Trap
2006-05-07, 19:07:01
Das macht aber Sonderzeichen kaputt.

Gast
2006-05-07, 20:57:05
Genau. Schlimmer noch, Leerzeichen werden zu 0, dadurch werden Strings mit Leerzeichen mittendrin terminiert. Besser (inklusive Schleife):char* c=...;
for (int i=0;c[i]!=0;++i)
{
if ((c[i]>='a')&&(c[i]<='z')) c[i]&=~0x20;
}

-zecki

Coda
2006-05-07, 21:04:23
Ich glaube eine Subtraktion wäre da doch sinnvoller, denn Netburst mag logische Operationen ja mal gar nich oder?

maprie
2006-05-08, 16:51:53
Ich hatte auch Probleme mit dem toupper im transform. :: davor hat das gelöst, aber frag mich nicht warum ;)
So siehts bei mir aus:

transform (suchbegriff.begin(), suchbegriff.end(), suchbegriff.begin(), ::toupper);

SamStone
2006-05-08, 20:01:28
maprie[/POST]']Ich hatte auch Probleme mit dem toupper im transform. :: davor hat das gelöst, aber frag mich nicht warum ;)
So siehts bei mir aus:

transform (suchbegriff.begin(), suchbegriff.end(), suchbegriff.begin(), ::toupper);
:| Ist das bei allen Compilern so, oder nur bei g++?

Was genau sagt ein einfaches :: davor? Das sich das in irgendeinem Namespace befinden kann?

Coda
2006-05-08, 20:16:52
:: ist der globale Namespace.

Gast
2006-05-08, 20:34:54
Ich weiß nicht ab welcher Version es gefixt ist, aber im gcc war tolower und toupper früher als Makro definiert, darum zickte es so rum, und darum gehts auch mit dem Wrapper.

maprie
2006-05-08, 21:12:08
Wobei ich mich frage, warum man explizit den globalen Namespace angeben muss. Der Rest ist doch auch globaler Namespace. Sehr seltsam.

Gast
2006-05-08, 21:26:04
Das ganze funktioniert aber nur wenn char unsigned ist. tolower arbeitet nur mit unsigned char. Ist char als signed char implementiert gibt es Probleme.

Man kommt also, wenn man es mit std::transform macht und das Programm portabel sein soll, nicht um einen Funktor herum.

Gast
2006-05-08, 21:29:30
Um einen Funktor kommt man wahrscheinlich schon herum. Ich wollte nur sagen das die Lösung

transform (suchbegriff.begin(), suchbegriff.end(), suchbegriff.begin(), ::toupper);

unportabel ist.

maprie
2006-05-08, 21:40:21
Hier hab ich was gefunden: http://www.devx.com/getHelpOn/Article/9702/1954?pf=true


string s="hello";
transform(s.begin(), s.end(), s.begin(), toupper);

Alas, the program above will not compile because the name 'toupper' is ambiguous. It can refer either to:


int std::toupper(int); // from <cctype>

or


template <class chart>
charT std::toupper(charT, const locale&);// from
<locale>

Use an explicit cast to resolve the ambiguity:


std::transform(s.begin(), s.end(), s.begin(),
(int(*)(int)) toupper);

This will instruct the compiler to choose the right toupper().

Aber was bedeutet das Casting vor toupper?
Edit: Das sagt, das toupper ein Zeiger auf eine Funktion vom Typ int mit einem Parameter vom Typ int sein soll, womit die richtige Funktion aus cctype gewählt wird. Liege ich da richtig?

SamStone
2006-05-08, 21:42:08
Coda[/POST]']:: ist der globale Namespace.
Das ist dann aber sehr seltsam, da cctype seine Sachen ja eigentlich alle im std Namespace deklariert.

Coda
2006-05-08, 21:51:06
SamStone[/POST]']Das ist dann aber sehr seltsam, da cctype seine Sachen ja eigentlich alle im std Namespace deklariert.
Auch im globalen. Nur die C++-Header verwenden ausschließlich std als namespace.