Anfänger hat Probleme mit Strings
-
Hallo liebe C++ - Gemeinde,
da ich hier schon mal TOP Unterstützung erhalten habe, habe ich wieder den Weg zu euch gefunden.
Es sind wieder einmal die wöchentlichen Hausaufgaben und diesmal zu Strings.
Die Aufgabe ist folgende:Schreiben Sie ein Programm, das die Namen einer Lehrveranstaltung, den wöchentlichen Selbststudienaufwand in Stunden und die Schwierigkeit zwischen 1 und 5 in drei Felder einliest.
Schreiben Sie folgende Funktionen, die über ein Menü auswählbar sind:
* Geben Sie eine Liste mit allen Veranstaltungen und deren Zeitaufwand sowie den summierten Zeitaufwand aus, bei denen die Schwierigkeit mindestens 3 ist.
* Geben Sie für eine Lehrveranstaltung, deren Namen Sie eingeben, Zeitaufwand und Schwierigkeit aus. Der Name darf dabei in einer beliebigen Kombination von Groß- und Kleinschreibung eingegeben und soll trotzdem gefunden werden (vermeiden Sie dabei Umlaute).Naja das Programm dazu habe ich im Prinzip schon fertig und es läuft auch, aber wenn man die Suche ein zweites mal aufruft und etwas neues sucht, dann funktioniert sie plötzlich nicht mehr :(...Warum?
Hier der Quelltext:
#include <iostream> #include <string> #include <iomanip> const int MAXSIZE = 100; //-->Nebenfunktionen //>Einlesenfunktion void lveinlesen(std::string lvname[], int aufwand[], int schwierig[], int& i) { std::cout<<"->!Geben sie nun ihre Lehrveranstaltungen ein!<-\n"<<std::endl; char answ = 'j'; for (i=0; i<=MAXSIZE;i++) { if (answ=='n' || answ=='N') break; std::cout<<"Name der Lehrveranstaltung: "; std::cin>>std::ws; getline(std::cin, lvname[i]); std::cout<<"Aufwand der Lehrveranstaltung(in Stunden): "; std::cin>>aufwand[i]; while (aufwand[i]<0) { std::cout<<"Die Eingabe ist zu klein, bitte geben sie erneut einen Wert ein."<<std::endl; std::cout<<"Aufwand der Lehrveranstaltung: "; std::cin>>aufwand[i]; } std::cout<<"Wie schwierig ist diese Lehrveranstaltung(1-5): "; std::cin>>schwierig[i]; while (schwierig[i]<1 || schwierig[i]>5) { std::cout<<"Die Eingabe ist ungültig, bitte geben sie erneut einen Wert zwischen 1 und 5 ein."<<std::endl; std::cout<<"Wie schwierig ist diese Lehrveranstaltung(1-5): "; std::cin>>schwierig[i]; } std::cout<<"Weitere Eingabe (j/n): "; std::cin>>answ; } } //>Funktion für Liste mit LV's Schwierigkeit über 3 + Gesamtaufwand derer void schwierig3 (std::string lvname[], int aufwand[], int schwierig[], int i){ int sum = 0; for (int n=0; n<i; n++) { if (schwierig[n]>=3) { std::cout<<std::setw(25)<<lvname[n]<<" "<<aufwand[n]<<" "<<schwierig[n]<<std::endl; sum+=aufwand[n]; } } std::cout<<"Gesamtaufwand: "<<sum<<std::endl; } //>Suche nach einer Lehrveranstaltung void suche (std::string lvname[], int aufwand[], int schwierig[], int i) { std::cout<<"Welche Veranstaltung suchen sie?"<<std::endl; std::string suche; suche.clear(); std::cin>>std::ws; getline(std::cin, suche); std::cout<<std::endl; std::string res; res.clear(); std::string::size_type z; for (z=0; z<suche.length(); z++) { char b = suche[z]; if (b>='A' && b<='Z') { b+= 'a'-'A'; } res+= b; } std::string lvnamecopy; lvnamecopy.clear(); std::string lvnameres; lvnameres.clear(); std::string lvnameklein[MAXSIZE]; lvnameklein[MAXSIZE].clear(); for(int n=0; n<i; n++) { lvnamecopy = lvname[n]; for (z=0; z<lvnamecopy.length(); z++) { char b = lvnamecopy[z]; if (b>='A' && b<='Z') { b+= 'a'-'A'; } lvnameres+= b; } lvnameklein[n] = lvnameres; } int merke = 0; for (int p=0; p<i; p++) { if (lvnameklein[p] == res){ std::cout<<std::setw(25)<<lvname[p]<<" "<<aufwand[p]<<" "<<schwierig[p]<<std::endl; merke++; break; } } if (merke==0) std::cout<<"Suche ergab keine Treffer!"<<std::endl; } //-->Hauptfunktion int main() { std::cout<<"\nLehrveranstaltungsverwaltung\n>--------------------------<\n"<<std::endl; //wichtige Felder initialisieren std::string lvname[MAXSIZE]; int aufwand[MAXSIZE]; int schwierig[MAXSIZE]; //Indexvariable int i = 0; lveinlesen(lvname, aufwand, schwierig, i); //->Verwaltungsprogramm int aufg = 0; while (aufg != 4) { std::cout<<"\nAufgabenmanager\n---------------"<<std::endl; //Auswahl std::cout<<"Druecken sie die"<<std::endl; std::cout<<"1 - Zum Anzeigen aller Lehrveranstaltungen mit Schwierigkeit ueber 3"<<std::endl; std::cout<<"2 - Zum Suchen einer Lehrveranstaltung"<<std::endl; std::cout<<"4 - Zum Programm beenden"<<std::endl; std::cout<<std::endl; std::cout<<"Was moechten sie tun?"; std::cin>>aufg; std::cout<<std::endl; switch (aufg) { case 1: std::cout<<">Liste der Lehrveranstaltungen mit Schwierigkeitsgrad ueber 3<"<<std::endl; schwierig3(lvname, aufwand, schwierig, i); break; case 2: std::cout<<">Suche nach einer Veranstaltung<\n"<<std::endl; suche(lvname, aufwand, schwierig, i); break; case 4: std::cout<<"-->Programm wurde beendet!"; break; default: std::cout<<"--->!!!Ungueltige Eingabe!!!<---"<<std::endl; std::cout<<">Bitte probieren sie es erneut.<"<<std::endl; break; } std::cout<<std::endl; } return 0; }Danke schonmal.
Viele Grüße,
Chillee
-
Bei mir funktioniert es schon bei der ersten Suche nicht
std::string lvnameklein[MAXSIZE]; lvnameklein[MAXSIZE].clear(); // <--Die Zeile ist erstes überflüssig, da die strings sowieso alle leer sind, und zweitens auch noch richtig falsch, denn das letzte Element ist lvnameklein[MAXSIZE-1].
Tipps:
Schreibe erstmal eine Klasse "Lehrveranstaltung" mit den Eigenschaften Name, Schwierigkeit und Aufwand. Speichere Instanzen dieser Klasse in einem std::vector und benutze evtl. Algorithmen aus <algorithm> für die Suche.
Danach kannst du es nochmal mit anderen Containern wie std::map probieren, wenn Du noch Lust hast
-
Hey...
erstmal vielen Dank für die Antwort. Doch leider kenn ich noch gar nichts von dem was du mir da beschrieben hast. Wir lerne grad noch die ganzen Grundlagen und unser letztes Kapitel drehte sich um strings und dazu war die HA. Naja und das mit Klassen und Objekten kommt erst im nächsten Kapitel, deswegen kann ich es noch nicht anwenden.
Zu der .clear - Zeile, damit hatte ich bloß experimentiert, da ich mir dachte, wenn ich die String immer vorher leer mache, dann kann auch nichts von der vorhergehenden suche drin stehen bleiben. Hatte aber leider keinen Erfolg.
PS: Falls es weiter hilft, hier mal unser Skript ;)...Wir sind gerade mit Kapitel 11 "Strings" durch. http://rapidshare.com/files/435841025/cpp1.epub(Leider bloß das Format für Adobe Digital verfügbar)
-
Ein Problem ist, dass nicht ganz klar ist, was "i" ist: ein Index oder die Anzahl? Das zeigt sich beim Einlesen:
for (i=0; i<=MAXSIZE;i++)Hier erlaubst Du sowohl 0 als auch 100, somit 101 Elemente. Das sollte nicht der ursprüngliche Fehler sein (da später meist gegen
n<igeprüft wird), ist jedoch trotzdem falsch.dann funktioniert sie plötzlich nicht mehr
Was genau passiert? Ausgaben? Nimm am besten Deinen Debugger und steppe das Programm beim 2. Durchlauf durch, dann kriegst Du schon mehr Hinweise, warum es knallt.
Wenn Ihr Klassen noch nicht habt: Habt Ihr denn zumindest ein
struct?
-
Um den Endlosschleifen bei Fehleingaben zu begegnen kannst du
std::cin.clear(); std::cin.ignore(std::cin.rdbuf()->in_avail());verwenden.
-
cinfehler schrieb:
Um den Endlosschleifen bei Fehleingaben zu begegnen kannst du
std::cin.clear(); std::cin.ignore(std::cin.rdbuf()->in_avail());verwenden.
Das wird nicht zuverlässig funktionieren, weil in_avail() gerne mal als
return 0;implementiert ist (es ist die Anzahl der mindestens einlesbaren Zeichen). Ich empfehle je nach Geschmack entweder 1 oder maximal viele Zeichen zu ignorieren.
-
Danke erstmal
!@ cinfehler: Was falsche Eingaben betrifft habt ihr natürlich recht, das vieles nicht abgefangen wird, aber da wird nicht so der Wert drauf gelegt...zumindest im Moment nocht nicht. Wichtiger ist die Funktionalität der Funktionen aus der Aufgabe! Außerdem hatten wir diesbezüglich auch noch keinen Unterricht, d.h. ich deine zweite Zeile verstehe ich noch nicht und weis so acuh nicht wo ich die hinsetzte im Quelltext.
Naja das mit der Suche ist ein größeres Problem.
@ minostaros: Danke für den Hinweis mit MAXSIZE, da hab ich nicht aufgepasst. Und i soll eigentlich der Feldindex sein...warum geht das nicht genau hervor?
Was den Debugger betrifft, ich werde das mal probieren...aber unser ach so toller Übungsleiter hat uns solche Sachen noch total vorenthalten
!EDIT: Könnt ihr bestimmte Debugger empfehlen? QT Creator habe ich bloß gefunden, das Programm über welches ich immer die QT Command Promt nutze, weil es uns von Übungsleiter empfohlen wurde.
-
Und i soll eigentlich der Feldindex sein...warum geht das nicht genau hervor?
Ganz einfach: weil Du es im Programm inkonsistent verwendest. Zwar wird
itraditionell immer als Index verwendet. Während der Eingabe istija noch der Index, und den größten verwendeten Index gibst Du (da Referenz) anmain( )zurück.
Im Rest des Programms jedoch übergibst Duian die Funktionen und verwendest es dort wie die Anzahl der Elemente und nimmstnals Index.Ein gutes Beispiel für eine weniger gute (und durch den Buchstaben i auch noch irreführende) Variablenbenennung.
Eine gute Regel besagt, dass man einstellige Variablen gar nicht verwenden soll, sondern sprechende Namen. Die Zeiten, wo man die Bytes im Sourcecode sparen musste, sind zum Glück vorbei.
Grundsätzlich ist immer die Frage, ob man lieber eine "Anzahl" oder einen "Größten Index" in die übergebene Variable steckt. Zwar geht beides, aber ich empfehle, immer die Anzahl zu nehmen. Zum einen kann es ja auch mal die Anzahl 0 geben, und zweitens macht es die for-Schleifen etwas sicherer, weil man immer
index < anzahlprüfen kann (und die Schleife auch bei Anzahl 0 noch richtig funktioniert, nämlich sofort abbricht). Mache das konstistent im ganzen Programm! Am besten in allen Deinen Programmen.Nenne also das Eine z.B. "anzahl" oder "anzahlVeranstaltungen", in den Schleifen dann "index" oder "kursNummer" oder "stringPos", je nachdem, was es wirklich darstellen soll. Liest sich einfacher als "n" oder "z", und zudem wäre der Fehler allein durch den Begriff schon aufgefallen.
-
Zum Debugger: Solltest Du sowieso schon im MS Studio unterwegs sein, dann benutze einfach den Debugger dort.
Oder lade Dir Eclipse runter mit der cpp-Erweiterung (Linux und Win). Es gibt für Win auch noch eine andere Umgebung, ich glaube DevCpp oder so, weiß aber net, ober der einen Debugger drin hat.
Lerne am besten gleich, mit sowas umzugehen (ist nicht schwer!). Es erspart Dir viel, viel Zeit bei der Fehlersuche...
-
Großes Dankeschön an die vielen Tipps!
Mein Programm läuft jetzt zumindest schon einmal
und zwar hab ich folgendes gemacht: In der Funktion für die Suche, an der Stelle, wo die Buchstaben von den Einträgen kleingemacht werden...std::string lvnamecopy; std::string lvnameres; std::string lvnameklein[MAXSIZE]; for(int n=0; n<i; n++) { lvnamecopy = lvname[n]; for (z=0; z<lvnamecopy.length(); z++) { char b = lvnamecopy[z]; if (b>='A' && b<='Z') { b+= 'a'-'A'; } lvnameres+= b; } lvnameklein[n] = lvnameres; lvnameres.clear();//---> Diese Zeile habe ich eingefügt! }Nun läuft die Suche auch mehrmals!

Nun zu deinem Tipps...nur damit ich alles richtig verstanden habe:
Ich soll niemals nur einzelne Buchstaben als Variablen verwenden, sondern immer so genauwie möglich. Also statt i schreibe ich index.Gut okay und dann müsste ich quasi diesen letzten Index an eine neue Variable übergeben z.B. an anzahl und diese dann in der Schleife als Bedingung (index<anzahl) verwenden, damit man nicht durcheinander kommt zwischen index und anzahl.
Ist das richtig?
Okay klingt auf jeden Fall logisch alles!

Was die Debugger betrifft, hatte ich nun mit QT gearbeitet...so konnte ich den Fehler beseitigen! Eclipse hatte unser Übungsleiter zwar auch von gesprochen, meinte aber das wäre mehr für Java...mh naja werd mir jetzt angewöhnen öfters mit sowas zu arbeiten.
Danke nochmal vielmals...
-
In Schleifen sind einbuchstabige Variablen gang und gebe und daher vollkommener Alltag. Bei anderen Variablen sollte man dies nicht machen. Programmieren ist ein wenig wie Bücher schreiben. Es muss gut lesbar, spannend und strukturiert von statten gehen.
-
Ich soll niemals nur einzelne Buchstaben als Variablen verwenden, sondern immer so genauwie möglich. Also statt i schreibe ich index.
Naja, niemals ist vielleicht ein wenig hart. Wie HighLigerBiMBam geschrieben hat, sind Einzelnbuchstaben als Schleifenzählern allgemein üblich. Du kannst natürlich machen, was Dir selbst besser gefällt, keine Frage.
Was ich geschrieben habe ist halt mein persönlicher Geschmack. Meistens verwende ich eher kurze Variablen wie
line,pos,paramoder so, wenn ich Arrays/Vektoren habe dielines,items,parametersheißen. Vor allem bei verschachtelten Schleifen macht es sich im Code weiter unten leichter, wenn man nicht jedes Mal überlegen muss, was jetzt eini,joderkist. Aber klar, wenn es mal wirklich eine kurze übersichtliche for-Schleife ist, dann ist es auch mal eini...Gut okay und dann müsste ich quasi diesen letzten Index an eine neue Variable übergeben z.B. an anzahl [...]
Ist das richtig?Genau, aber aufpassen, dass
anzahlrichtig berechnet wird (letzterIndex + 1).Eclipse ist zwar in Java geschrieben und kann da auch sehr viel, aber inzwischen ist die C++-Unterstützung hervorragend.
Egal was Du nimmst: Ein Editor ist ein Editor ist ein Editor.
-
Okay alles klar!
Habe nun die HA gestern abgegeben...mal sehen wie das Ergebnis aussieht.
In der kommenden HA werde ich das alles mal probieren und versuchen umzusetzen. Elcipse werde ich mir wohl auch mal zu genüge führen ;)...
So nochmals vielen Dank für die abermals gute Unterstützung. Bis nächsten Freitag wartet schon wieder die nächste HA, diesmal wird es wohl zum erstmal um die Verwendung von Klassen gehen.
Schönes WE und einen besinnlichen 3. Advent!
Viele Grüße,
Chillee