vendredi 23 novembre 2018

Why is my street printed on Linux, but not on Windows?

Given in test.dat (the input file), the data were:

1 3.3 Langestrasse 2.200000
0 4.4 Koeningsstrasse
0 5.5 Koeniginstrasse

The following program should (parse the data into instances of the classes Tankstelle / TankstelleDeLuxe and ) save the data in reversed order in protokoll.dat
But the output written under Windows 10 (output of g++ --version:
g++ (x86_64-win32-seh-rev1, Built by MinGW-W64 project) 7.2.0) into Protokoll.dat is:

0 5.5  
0 4.4 Koeningsstrasse 
1 3.3 Langestrasse 2.200000

The property "Koeniginstrasse" is clearly missing. Interestingly, according to my friend (the program's author, I have the permissions to ask this question), the behaviour does not occur under his Linux environment.
tl;dr: Despite the same Makefile and the same compilation data, the correctness of the executable file is not guaranteed.

Interestingly, according to my friend (the program's author, I have the permissions to ask this question), this wrong behaviour does not occur under his Linux environment.

I was not able to make a MWE. Even the debugging output after step 7 in the list downward seems to show no problems. The program itself is certainly not the most elegant solution, it was made to fulfill a homework exercise.

Steps to reproduce:

  1. Save all given files in the same folder
  2. Run make in this folder.
  3. Run ./main.exe
  4. Answer with 3
  5. Answer with J
  6. Answer with test.dat
  7. Answer with J
  8. Look at protokoll.dat. Was "Koeniginstrasse" inserted?

I would be glad if you could give me some hints

  • wether this strange behaviour occurs on your PCs too
  • why Koeniginstrasse is not saved into protokoll.dat

The critical line seems to be line 126 in main.cpp.

f << meineListe.at(i)->benzinpreisAusgabe() << " " << meineListe.at(i)->adresseAusgabe() << " "; 

Many thanks in advance!

Files: Makefile:

main: main.o tankstelle.o tankstelleDeLuxe.o
    g++ -std=c++11 main.o tankstelle.o tankstelleDeLuxe.o -o main

main.o: tankstelle.h tankstelleDeLuxe.h main.cpp
    g++ -std=c++11 -c main.cpp

tankstelle.o: tankstelle.cpp tankstelle.h
    g++ -std=c++11 -c tankstelle.cpp

tankstelleDeLuxe.o: tankstelle.h tankstelleDeLuxe.cpp tankstelleDeLuxe.h
    g++ -std=c++11 -c tankstelleDeLuxe.cpp

clean:
    rm main *.o

tankstelle.cpp:

#include <iostream>
#include "tankstelle.h"
//#include <unistd.h>
//#include <stdlib.h>
//#include <cstdlib>

    //Initialisierung:

Tankstelle::Tankstelle(std::string adresse, double benzinpreis,bool waschstrasse)
: adresse(adresse), benzinpreis(benzinpreis), waschstrasse(waschstrasse)
{};

double Tankstelle::benzinpreisAusgabe(){
    return this->benzinpreis;
}
std::string Tankstelle::adresseAusgabe(){
    return this->adresse;
}
bool Tankstelle::waschstrasseAusgabe(){
    return this->waschstrasse;
}

tankstelle.h:

//tankstelle.h
#ifndef _TANKSTELLE_H_
#define _TANKSTELLE_H_

#include<string>    //fuer Adresse

class Tankstelle
{
  public:                              // oeffentlich
    Tankstelle(std::string adresse="Unbekannt", double benzinpreis=0,bool waschstrasse = false );  //   // Konstruktor mit Parameter und Defaultwert

    double benzinpreisAusgabe();
    std::string adresseAusgabe();
    bool waschstrasseAusgabe();
    bool waschstrasse;

  protected:                             // privat
    std::string adresse;
    double benzinpreis;
};

#endif //_TANKSTELLE_H_

tankstelleDeLuxe.cpp:

#include "tankstelle.h"
#include "tankstelleDeLuxe.h"


TankstelleDeLuxe::TankstelleDeLuxe(std::string adresse, double benzinpreis, double waeschepreis)
: Tankstelle(adresse, benzinpreis, true), waeschepreis(waeschepreis)
{}

void TankstelleDeLuxe::waeschepreisEingabe(double waeschepreis){
    this->waeschepreis = waeschepreis;
}

double TankstelleDeLuxe::waeschepreisAusgabe(){
    return this->waeschepreis;
}

tankstelleDeLuxe.h:

#include "tankstelle.h"
#include <iostream>

class TankstelleDeLuxe: public Tankstelle {

    double waeschepreis;  // in Klassen implizit private

    public:
        TankstelleDeLuxe(std::string adresse="Unbekannt", double benzinpreis=0, double waeschepreis=0);
        void waeschepreisEingabe(double waeschepreis);
        double waeschepreisAusgabe();
};

main.cpp:

// einbinden von nützlichen Funktionen
//#include<iostream> // fuers  << und >>  //eigentlich schon drin
#include<vector> //fuer Vektoren
#include <stdlib.h>//fuer char umwandeln in int
#include <stdio.h> // fuer NULL
#include <unistd.h>//fuer getopt
//#include<string>  //eigentlich schon da
#include<fstream> //fuer ein- und auslesen
#include<sstream> //fuer stringstream
#include<algorithm> // fuer reverse
#include "tankstelleDeLuxe.h"

using namespace std;

int main(int argc, char *argv[])
{
    int c = 0;
    while ((c = getopt (argc, argv, "h")) != -1){
        switch (c){
            case 'h': {
                cout << "Dieses Programm liest n Tankstellen ein." << endl;
                cout << "Sie werden aufgefordert das einzugeben." << endl;
                cout << "Optionen:" << endl;
                cout << "\t-h Ruft diese Hilfe auf." << endl;
                return 1;
            }
            default:{
                abort ();
            }
        }
    }
    cout << "Bitte geben sie eine Zahl an, die angibt, wieviele Tankstellen eingelesen werden.";
    int n;
    cin >> n;

    vector<Tankstelle*> meineListe;
    Tankstelle* neueTankstelle;


    cout << "Soll aus einer Datei eingelesen werden?(Falls nein werden Sie aufgefordert alle Daten einzeln einzugeben) \n [J/N]";
    char antwort;
    cin >> antwort;
    if('J'== antwort){
        cout << "Geben Sie den Namen der Datei bitte an. Sie muss sich in dem Ordner befinden, indem das aktuelle Programm verwendet wird. ";
        string dateiname;
        string zeile;
        cin >> dateiname;
        ifstream datei(dateiname);
        if(datei.is_open() ){
            while(getline(datei, zeile) ){
                stringstream zeilenbestandteile(zeile);
                vector<string> meineToken;
                string token;
                char delimiter = ' ';
                while(getline(zeilenbestandteile, token, delimiter)) {
                    if (token != "") {
                        meineToken.push_back(token);
                    }
                }
                int waschstellenanzeiger = stoi(meineToken.at(0));
                double benzinpreis = stod(meineToken.at(1));
                string adresse = meineToken.at(2);
                if(waschstellenanzeiger == 0){
                    neueTankstelle = new Tankstelle(adresse, benzinpreis);
                }else{
                    double waschpreis = stod(meineToken.at(3));
                    neueTankstelle = new TankstelleDeLuxe(adresse, benzinpreis, waschpreis);
                }
                meineListe.push_back(neueTankstelle);
            }

            datei.close();
        }else{
            cout << "Datei konnte nicht geoeffnet werden. Entweder ist sie am falschen Ort oder es liegt ein Tippfehler vor.";
            return 1;
        }
    }else if('N'!=antwort){
        cout << "Fehler bei der Eingabe. Programm beendet sich. \n";
        return 1;
    }else{
        for(int i=0; i<n;i++){
            cout << "Hat die Tankstelle eine Waschstrasse? \n [J/N]";
            char eingabe;
            cin >> eingabe;
            double waschpreis = 0; //muss fuers compilieren aussen sein
            if('J'== eingabe){

                cout << "Waschpreis? (double)\n";
                cin >> waschpreis;
            //  waschpreis = strtod(temp, NULL);
            } else if ('N' != eingabe){
                cout << "Eingabe hat nicht funktioniert. Das Programm wird beeindet. \n";
                return 1;
            }
            cout << "Benzinpreis?(in double) \n ";
            double benzinpreis;
            cin >> benzinpreis;
        //  benzinpreis = strtod(temp, NULL);
            cout << "Bitte die Adresse: \n ";
            string adresse;
            cin >> adresse;
            if('J'== eingabe){
                neueTankstelle = new TankstelleDeLuxe(adresse, benzinpreis, waschpreis);
            }else{
                neueTankstelle = new Tankstelle(adresse, benzinpreis);
            }
            meineListe.push_back(neueTankstelle);
        }
    }
    delete neueTankstelle;

    reverse(meineListe.begin(), meineListe.end());
        cout << "Sollen die Eingaben gespeichert werden?\n[J/N] ";
        char einGabe;
        cin>>einGabe;
        if('J'== einGabe){
            fstream f;
            f.open("protokoll.dat", ios::app); //erzeuge eine Datei bzw erweitere sie
                for(int i=0; i<meineListe.size(); i++){
                    if(meineListe.at(i)->waschstrasseAusgabe()){
                        f << 1 << " ";
                    }else{
                        f << 0 << " ";
                    }
                    cout << "Test-Adresse fuer " << to_string(i) << ": " << meineListe.at(i)->adresseAusgabe() << endl;
                    f << meineListe.at(i)->benzinpreisAusgabe() << " " << meineListe.at(i)->adresseAusgabe() << " "; //lese Info in die Datei aus
                    if(meineListe.at(i)->waschstrasseAusgabe()){
                        f << to_string((static_cast<TankstelleDeLuxe*>(meineListe.at(i)))->waeschepreisAusgabe());
                    }
                f <<endl;
                                                        }
            f.close();
        }

    //delete meineListe;


    return 0;
}

test.dat as given. protokoll.dat should be created automatically.

Aucun commentaire:

Enregistrer un commentaire