C++ File-Streams



  • Hallo!

    Zuallererst würde ich euch bitten nicht die Effizienz des Programms in Frage zu stellen und vielmehr auf den Fehler einzugehen den ich euch gleich erläutern werde.

    Was macht dieses Programm eigentlich?
    Dieses Programm speichert über eine Datei "Pizza Einträge". Es gibt vier vorgefertigte Standardpizzen. (siehe Quellencode Zeile 9)
    Die vier vorgefertigten Standardpizzen werden aber erst in die Datei geschrieben wenn man ein od. mehrere Pizzen in die Datei einfügt.

    Wie im Quellcode deutlich zu erkennen besitzt dieses Programm über ein "Auswahl-Menü". Und je nachdem welche Zahl man über die Standardausgabe(Tastertur) eingibt führt das Programm die jeweilige "Tätigkeit" aus.
    Alle drei Auswahlmöglichkeiten "laufen" über eine Switch-Schleife.

    !!!Das Programm funktioniert eigentlich!!!

    Doch wieso brauche ich dann eure Hilfe?

    Programmerkärung:

    Beginnen wir die Erklärung mit einem "simulierenden" Programmablauf!
    Auswahlmenü: Ich wähle "Pizza hinzufuegen" aus! (da ich erst eine Pizza hinzufügen muss damit die vier Standardpizzen in die Datei eingefügt werden)
    Jetzt gebe ich den Namen und den Preis der Pizza ein.
    Wir befinden uns wieder im Auswahlmenü!
    Ich wähle "Pizzakarte ansehen".
    Ausgaben werden die vier Standardpizzen und die eingegebene Pizza!
    Wieder im Auswahlmenü... etc.

    Fehlererklärung:
    Die Ausgabe sollte so erfolgen wie beschrieben, tut sie auch wenn in der Definition von "struct pizza" die Variable "preis" mit dem Datentyp "float" angegeben wird! -> [struct pizza { char name[30]; float preis; };] (siehe Quellcode Anfang)!
    Falls nicht wie in diesem Quellencode (hier hat die Variable "preis" den Typ "double") dann werden nur die Pizzen ausgebenen BIS zur Pizza mit dem Preis (6.5, 6.6, 6.7).(ACHTUNG: Dies gilt nur für die Standardpizzen nicht für eingegebene!!!!!!!!!)
    Dies bedeutet wenn die erste Standardpizza den Preis 6.5, 6.6 oder 6.7 hat wird nichts ausgegeben!

    Ich habe dies nur durch Stundenlange Arbeit herausgefunden und verzweifle schon langsam.
    Das lustige daran ist ja wenn die Variable "preis" den Typ double hat und nicht den Wert 6.5, 6.6 oder 6.7 wird alles normal ausgegeben! (Wenn die Variable "preis" den Typ float hat dann ist der Wert egal!)

    Was ich schon probiert habe:
    Standardpizzen weggelöscht und nur per Standardeingabe in dei Datei geschrieben! (preis natürlich typ double)
    Alles hat funktioniert egal welcher Wert die Variable "preis" gehabt hat.

    Ich wäre sehr dankbar, wenn mir jemand weiterhelfen könnte!

    Ein großes Lob an die Entwickler! Sehr übersichtlich und Benutzerfreundlich gestaltet! (bin neu in der Community und nutze eigentlich zum ersten mal ein Forum)

    Hier der Quellencode:

    #include "stdafx.h"         
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    char header[] = " * * * PIZZA PRONTO * * *\n\n";
    struct pizza { char name[30]; double preis; };
    const int MAXANZ = 10;
    pizza pizzakarte[MAXANZ] = { { "Magerita", 5.8},{ "Regina", 5.4 },
                               { "Bolonese", 8.9 },{ "Calzone", 7.9 } };
    char pizzaDatei[256] = "pizza.dat";
    int anz = 4;
    inline void eingabepuffer_leeren()
    {
    	cin.sync();
    	cin.clear();
    	cin.ignore(std::cin.rdbuf()->in_avail());
    }
    int main()
    {
    	int auswahl;
    	while (true)
    	{
    		system("cls");
    		do
    		{
    			cout << header << endl;
    			cout << "Was moechten Sie tun?\n\n" //Menue
    				<< "Pizzakarte ansehen...0\n"
    				<< "Pizza hinzufuegen....1\n"
    				<< "Abbrechen............2\n"
    				<< "Eingabe: ";
    			eingabepuffer_leeren(); //Eingabepuffer leeren
    			cin >> auswahl;
    			system("cls");
    		} while (auswahl < 0 || auswahl > 2);
    
    		switch (auswahl)
    		{
    		case 0:                                                                           //Pizzadatei auslesen!
    		{
    			ifstream inFile(pizzaDatei, ios::in || ios::binary);
    			if (!inFile)
    			{
    				cerr << "Fehler beim Oeffnen der Datei! (Datei vorhanden?)";
    				eingabepuffer_leeren(); //Eingabepuffer leeren
    				getchar();
    				exit(1);
    			}
    			pizza einePizza;
    			cout << "* * * Pizzakarte * * *\n\n";
    			int anzahl = 0;
    			while (true)
    			{
    				if (!inFile.read((char*)&einePizza, sizeof(pizza)))
    					break;
    				else
    					cout << "(" << ++anzahl << ")  " << einePizza.name << "\t" << einePizza.preis << endl;
    
    			}
    			if (!inFile.eof())
    			{
    				cerr << "Fehler beim Lesen der Datei!";
    				eingabepuffer_leeren(); //Eingabepuffer leeren
    				getchar();
    				exit(1);
    			}
    			eingabepuffer_leeren(); //Eingabepuffer leeren
    			getchar();
    			break;
    		}
    
    		case 1:                                                                            //Pizzadaten in Pizzadatei schreiben!
    		{
    			if (anz == MAXANZ)
    			{
    				cout << "Datei ist voll!";
    				eingabepuffer_leeren(); //Eingabepuffer leeren
    				getchar();
    				continue;
    			}
    			ofstream outFile(pizzaDatei, ios::out | ios::binary); //Prüfe ob Datei geoffnet werden kann!
    			if (!outFile)
    			{
    				cerr << "Fehler beim Oeffnen der Pizzadatei!";
    				eingabepuffer_leeren(); //Eingabepuffer leeren
    				getchar();
    				exit(1);
    			}
    			else
    			{
    				char pizza_name[30];
    				double pizza_preis;
    				int kontrolle = 0;
    				do //Schleife für die Eingabe der Pizzanamen!
    				{
    
    					eingabepuffer_leeren(); //Eingabepuffer leeren
    					if (kontrolle != 0)
    						cout << "Bitte geben den Namen der Pizza ein!" << endl;
    
    					cout << "Name der Pizza?\n"                                 //Abfrage Name der Pizza!
    						<< "Eingabe: ";
    					cin.getline(pizza_name, 30);
    					kontrolle = 1;
    					system("cls");
    				} while (pizza_name[0] == '\0');
    				kontrolle = 0;  
    				do
    				{
    					eingabepuffer_leeren(); //Eingabepuffer leeren
    					if (kontrolle != 0)
    					{
    						cout << "Bitte geben sie einen plausiblen Preis ein!";
    						getchar();
    						system("cls");
    					}
    					cout << "Preis der Pizza?\n" //Abfrage Preis der Pizza!
    						<< "Eingabe: ";
    					cin >> pizza_preis;
    					kontrolle = 1;
    					system("cls");
    				} while (pizza_preis <= 0 || pizza_preis > 1100);
    				++anz;
    				strcpy(pizzakarte[anz - 1].name, pizza_name);                                                        
    				pizzakarte[anz - 1].preis = pizza_preis;
    				for (int i = 0; i < anz; ++i) //In Pizzadatei schreiben
    				{
    					if (!outFile.write((char*)&pizzakarte[i], sizeof(pizza)))
    					{
    						cerr << "Fehler beim Schreiben in Datei!";
    						eingabepuffer_leeren(); //Eingabepuffer leeren
    						getchar();
    						exit(1);
    					}
    				}
    				cout << "Erfolgreich gespeichert!" << endl;
    				eingabepuffer_leeren(); //Eingabepuffer leeren
    				getchar();
    				system("cls");
    				break;
    
    			}
    		}
    		case 2: return 0;                                                                                   //Abbruch
    		default: cout << " Unbekannter Fehler!" << endl; break;
    		}
    	}
        return 0;
    }
    


  • Benutze den Debugger. Setze zB einen Haltepunkt, bevor du eine Pizza ausgibst und inspiziere die gelesene Pizza. Was für eine IDE benutzt du (VisualStudio, Eclipse, CodeBlocks oder garnichts von dem)?
    Das Programm ist ziemlich wirr, vor allem, weil du massiv C mit C++ vermischt. In welcher Sprache soll es denn am Ende geschrieben sein?



  • fossition schrieb:

    vielmehr auf den Fehler einzugehen den ich euch gleich erläutern werde.

    Zu spät. Du postest eine C++-Frage in einem C-Forum. Bist du blind, oder halt nur schnell ins Forum geschissen?

    fossition schrieb:

    (wall of text)

    Alter! Soviel produziere ja nicht mal ich in meinen Posts, und ich bin geschwätzig.

    Mal so ein paar Sachen, die mir direkt ins Auge springen:

    #include "stdafx.h"
    

    A-ha. Das ist ein vom Compiler generierter Header für vorkompiliertem Code. Brauchst du den? Eigentlich nicht.

    #include <cstdlib> fehlt, da stehen so Sachen drin wie system (was böse ist) und exit (warum? Return doch einfach, du verwendest das eh nur in main ). Außerdem fehlt cstring für dein strcpy .

    ios::in || ios::binary
    

    Warnung: ich mache zwar C in der Hauptsache, habe aber mal C++ gelernt. Und da habe ich gelernt, dass die Flags in ios_base definiert werden, nicht in ios . Kompiliert zwar auch so, aber dennoch.
    Fehler: Du verwendest den || -Operator. Der passt hier nicht.

    Warum öffnest du die überhaupt Binary? Gibt's dafür einen besonderen Grund?

    system("cls") - ist nicht portabel. mein Gentoo meldet hier, dass das Kommando nicht gefunden wurde.

    Den Rest habe ich mir dann gar nicht erst angeschaut. Bitte poste ein kompilierbares Beispiel - und das heißt nicht, dass du am Ende im Browser noch mal anfangen sollst, am Code rumzubasteln. STRG+A, STRG+C, in Browserfenster wechseln, STRG+V.

    fossition schrieb:

    Dies bedeutet wenn die erste Standardpizza den Preis 6.5, 6.6 oder 6.7 hat wird nichts ausgegeben!

    Habe mal Magerita auf 6.5 gestellt und dann eine Pizza DDD mit dem Preis 10 erstellt. Konnte das Problem nicht nachvollziehen:

    * * * Pizzakarte * * *
    
    (1)  Magerita	6.5
    (2)  Regina	5.4
    (3)  Bolonese	8.9
    (4)  Calzone	7.9
    (5)  DDD	10
    

    Und nu?

    fossition schrieb:

    Sehr übersichtlich und Benutzerfreundlich gestaltet!

    Der war gut!
    Komplementierst die Übersichtlichkeit und verfehlst dennoch das C++-Forum. Meine Herren ...

    Ansonsten musst du halt ran mit dem Debugger, hat Techel schon geschrieben. So, wie dein Programm aufgebaut ist, tut sich das keiner an, sorry.

    EDIT: Und sei mal nicht so verschwenderisch mit deinen Ausrufezeichen - wir verstehen dich auch so.

    EDIT2: Absatz über stdafx.h korrigiert, streng genommen ist das kein Windows-Header (hustbaer hat recht). Fehlerhafte Quotierung korrigiert.



  • dachschaden schrieb:

    #include "stdafx.h"
    

    A-ha. Das ist ein Windows-Header.

    Ist keine Windows-Header in dem Sinn. Ist bloss der Default-Name des Header Files das Visual Studio per Default für die "Precompiled Header" Funktion erzeugt.
    stdafx.h gehört also zum eigenen Projekt, und man kann reinschreiben was man möchte. Bzw. es umbenennen, ganz entfernen - was auch immer.



  • Neben den schon genannten Problemen:
    0. falsches Forum

    1. || statt |
    2. #include <cstring>
      3. Mischmasch aus C und C++
      4. Benutzen von system
      frage ich mich, ob du vielleicht eine pizza.dat mit float erzeugt hast und dann mit double wieder auszulesen versuchst oder umgekehrt. Hast du also vor deinen Tests mal die pizza.dat gelöscht? Ansonsten ist es schwer, das Problem nachzuvollziehen.

    Deine main() hat 130 Zeilen -> überleg dir doch mal, ob du das nicht besser in kleinere testbare Funktionen auslagern könntest.

    Warum gibst du in char pizzaDatei[256] = "pizza.dat"; die Länge an? Warum überhaupt überall C-Strings, wenn du doch C++ zu machen scheinst? Was spricht gegen std::string?

    Warum schreibst du die Daten binär in eine Datei mit diesem unschönen Cast: (char*)&einePizza - wäre es nicht besser, die Daten irgendwie anders zu schreiben?



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C (alle ISO-Standards) in das Forum C++ (alle ISO-Standards) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Dies war ein Übungsbeispiel und da solltet ihr euch eigentlich nicht fragen wieso ich z.B binär in die Datei schreibe...
    Ich habe einzig und allein darum gebittet auf Fehler zu achten und nicht andere unnötige Dinge in Frage stellen.

    Dieses Beispiel habe ich selber geschrieben und mit der Lösung kontrolliert.

    Den Fehler konnte ich dank eurer Kommentare finden. -> ifstream inFile(pizzaDatei, ios::in || ios::binary);

    Vielen Dank dafür!

    Wie bin ich ins falsche Forum "gerutscht"?
    Ich war zuallererst im richtigen Forum doch als ich den Text absenden wollte hatte ich die Rechnung falsch eingegeben.
    Wieso? Die Rechnung war 8+7 und da ich von den Taschenrechner gewöhnt war das der 1 links oben ist hatte ich 75 eingegeben statt 15.
    Danach war ich wieder auf der Startseite. Den Text hatte ich glücklicherweise zwischenkopiert und schnell einen neuen Beitrag gemacht und dabei nicht auf das Forum geachtet...abgesendet.

    Entschuldigung dafür!

    PS: Wenn ich nicht #include "stdafx.h" einfüge...
    fatal error C1010: Unerwartetes Dateiende während der Suche nach dem vorkompilierten Header. Haben Sie möglicherweise vergessen, im Quellcode "#include "stdafx.h"" einzufügen?
    ========== Erstellen: 0 erfolgreich, 1 fehlerhaft, 0 aktuell, 0 übersprungen ==========



  • fossition schrieb:

    Dies war ein Übungsbeispiel und da solltet ihr euch eigentlich nicht fragen wieso ich z.B binär in die Datei schreibe...

    Doch. Weil das Beispiel alles ist, was wir haben. Wir wissen sonst nicht, was du machst - aber bei dem, was wir sehen, fragen wir uns, warum du das machst.

    fossition schrieb:

    Ich habe einzig und allein darum gebittet auf Fehler zu achten und nicht andere unnötige Dinge in Frage stellen.

    1. Gebeten.
    2. Im Leben bekommt man nicht immer das, was man will. Gewöhn dich dran.

    fossition schrieb:

    PS: Wenn ich nicht #include "stdafx.h" einfüge...
    fatal error C1010: Unerwartetes Dateiende während der Suche nach dem vorkompilierten Header. Haben Sie möglicherweise vergessen, im Quellcode "#include "stdafx.h"" einzufügen?
    ========== Erstellen: 0 erfolgreich, 1 fehlerhaft, 0 aktuell, 0 übersprungen ==========

    In den Projekteinstellungen vorkompilierten Header deaktivieren.
    Das Problem ist, dass das ein "Feature" von Visual Studio ist, welches aber Kompatibilität mit anderen Betriebssystemen bricht. Das hier ist das C++-Forum, nicht das Windows-Forum. Deswegen sollte der Code, der hier gepostet wird, kompatibel sein, damit auch Leute auf einem Linux den Code kompiliert bekommen.



  • fossition schrieb:

    Ich habe einzig und allein darum gebittet auf Fehler zu achten und nicht andere unnötige Dinge in Frage stellen.

    dachschaden schrieb:

    1. Gebeten.
    2. Im Leben bekommt man nicht immer das, was man will. Gewöhn dich dran.

    Deine provokante Persönlichkeit gibt mir den Anschein das du in deinem Leben nicht das bekommen hast was du willst. Doch dies lass nicht auf mich bzw. andere Nutzer aus.
    Und bitte achte auf deine Wortwahl.

    Trotzdem bedanke ich mich für deine Bemühungen!



  • fossition schrieb:

    Deine provokante Persönlichkeit gibt mir den Anschein das du in deinem Leben nicht das bekommen hast was du willst.

    Ich würde mir, wenn ich du wäre, mal überlegen, warum ich so schreibe, wie ich schreibe. Das Ganze ist auch ein Test an die Leute hier. Wenn diese brauchbar sind, ignorieren sie sie. Wenn nicht ... tja, dann erwähnen sie sie halt. Viel zu lernen du noch hast, mein junger Padawan.

    fossition schrieb:

    Doch dies lass nicht auf mich bzw. andere Nutzer aus. Und bitte achte auf deine Wortwahl.

    Was soll mit meiner Wortwahl sein? Du kannst dir sicher sein, dass die Moderation gegen meine Wortwahl nichts hat, sonst hätte sie mich deswegen schon angepisst. Hat sie nicht. Und dann brauchst du dich auch nicht darüber zu beschweren.

    Ich bin dir gegenüber direkt. Wenn du Mist baust, dann sage ich dir das. Notfalls drastisch, damit du merkst, dass das Mist ist. Nichts anderes würde ich von den Leuten hier auch verlangen (siehe hustbaer). Je schneller du das lernst, je schneller wirst du "in der Community" lernen, worauf es ankommt.
    Wir waren alle mal Anfänger und haben dämliche Fehler gemacht, deswegen wollen wir nicht, dass Leute die gleichen dämlichen Fehler wieder machen.



  • Dachschaden ist in erster Linie ein provokantes Arschloch.



  • dachschaden schrieb:

    Das Problem ist, dass das ein "Feature" von Visual Studio ist, welches aber Kompatibilität mit anderen Betriebssystemen bricht.

    Nur wenn man es falsch verwendet.
    Wenn man immer überall die korrekten Pfade für #include verwendet, dann baut so ein Projekt mit oder ohne Precompiled-Header Feature.
    Es baut mit dann nur (meistens) schneller.



  • hustbaer schrieb:

    Nur wenn man es falsch verwendet.
    Wenn man immer überall die korrekten Pfade für #include verwendet, dann baut so ein Projekt mit oder ohne Precompiled-Header Feature.

    ... damit meinte ich eher, dass es sich hierbei um einen Header handelt, der vom GCC/G++ nicht generiert wird, und ich die Zeile deswegen entfernen muss, um es überhaupt kompiliert zu bekommen. Funktionell hatte das keine Nachteile, es war halt trotzdem notwendig.

    In diesem Sinne ist "inkludiert" bereits falsch verwendet. Was auch der Grund ist, warum ich bei Bibliotheks-internen #include s gerne noch mal einen Guard einbaue um die Anweisung und nicht nur in der Datei für den Fall, dass der Programmier das Header-Verzeichnis nicht in die Standard-Include-Verzeichnisse aufnimmt. Weil sonst das #include an sich bereits tödlich ist.

    @beg_offl: Wenn du nur arschverletzt sein willst, schlage ich vor, dass du das woanders bist.

    EDIT: Missverständlichen Satz weniger doppeldeutig gemacht.



  • fossition schrieb:

    Deine provokante Persönlichkeit ...

    Wie kann eine Persönlichkeit provokant sein?
    Das ist genauso rätselhaft wie "gebittet".
    Ausserdem ist dachschaden einer von den Harmlosen. Es gibt Schlimmere (mich z.B. :p )

    EDIT:
    Ansonsten hat mein main ungefähr zwei Zeilen:

    myclass mc;
    return( mc.start() );
    

    Alles Andere spielt sich ausserhalb von main ab.


Anmelden zum Antworten