Wochentagsberechnung nach Gauß produziert "segmentation-faults"



  • Ich konnte jetzt auf die Schnelle den Segmentation Fault nicht nachvollziehen. Bei welcher Eingabe kommt der denn?

    Davon abgesehen, ist dein Algorithmus fehlerhaft. Zumindest stimmt die Ausgabe nicht, wenn ich dein Programm mit dem heutigen Datum starte.

    Und nochwas. Deine Fehlerbehandlung ist nicht in sich konsistent und falsch.
    Wenn du kein cin fail hast, führst du dein Programm einfach weiter aus.
    aber z.B. 0a0a0 führt nicht zu einem cin fail.

    Der Teil in dem if für cin fail funktioniert auch nicht richtig. Wenn dein Eingabebuffer Länge > 1 ist, reicht dein ignore nicht. Mit cin.ignore(1000,'\n') würde es immerhin bis zu einer Eingabe von 1000 Zeichen reichen.

    Was passiert denn, wenn die zweite Eingabe auch Fehlerhaft ist? Dann führst du dein Programm auch einfach weiter aus.



  • a) Mit eingeschalteten Warnungen kompilieren. (-Wall -pedantic oder ähnlich)
    b) Gründe für die Warnungen beheben.



  • Ein segmentation fault passiert oft über fehlerhaften Arrayzugriff.
    Z.B. wenn deine Funktionen wochentagDatum odr wochentagErsterJanuar etwas anderes als 0 bis 6 zurück geben.

    Meinst du nicht, das man an die verschiedenen Stellen einer Jahreszahl auch durch Rechen (Grundchulreschnen, keine Mathematik) kommt.
    An das Jahrhundert (erste beiden Stellen kommt man z.B. mit Jahr/100 😉



  • Vielen dank erstmal für die schnellen Antworten 😮 👍 😃
    also....

    wob schrieb:

    2. Was soll der Komma-Operator hier bedeuten:
    C++:
    int gaussKlammernAufrunden = ((int) (2, 6 * julMonat - 0, 2)) + 1;

    Das ist dass was ich mit den Gaußklammern meinte.

    https://wikimedia.org/api/rest_v1/media/math/render/svg/512bfc0dcc88c8e256bb37071d3198339dd2d58b

    Die eckige Klammer xx{\displaystyle \lfloor x\rfloor } \lfloor x\rfloor ist die Gaußklammer: Sie gibt die größte ganze Zahl kleiner oder gleich x an.

    Bei nach oben geöffneten Gaußklammern wird aufgerundet.
    Beispiel (Wikipedia)
    2,8=3\lfloor -2{,}8\rfloor =-3
    So habe ich es verstanden.
    Deshalb habe ich die double Zahl nach Int gecastet um die Nachkommastellen abzutrennen und dann +1 gerechnet, weil ja immer aufgerundet wird. 😕

    wob schrieb:

    2b. Was soll die (1) in der ersten Zeile:
    C++:
    vector<int> pos(1);
    pos = stellenAbtrennen(eingabeJahr);

    Ich wollte dem Vektor damit eine feste Größe geben weil ich gelesen habe dass dieser Fehler oft mit Vekotren, Arrays zusammenhängt. Ich habe da nur experimentiert.

    wob schrieb:

    2c. ist das einzelne | in folgender Zeile Absicht:
    C++:
    if (julMonat == 1 | julMonat == 2)

    Nein ist es nicht. 😞

    wob schrieb:

    3. Was macht die Funktion stellenAbtrennen? Sieht sehr merkwürdig aus.

    Also die Formel fordert folgendes:

    Quelle:Wikipedia schrieb:

    y
    Die beiden letzten Stellen der Jahreszahl, bei den Monaten Januar und Februar die letzten Stellen des Vorjahres (für Dez. 1907 also 7, für Jan 1907 6, für Jan 1900 99)
    c
    Die beiden ersten Stellen der Jahreszahl, bei den Monaten Januar und Februar die ersten Stellen des Vorjahres (für Dez. 1907 also 19, für Jan 1907 19, für Jan 1900 18)

    Dazu habe ich die eingegebene Jahreszahl in einen String konvertiert,
    die ersten beiden und letzen beiden Stellen dieser Zahl mittels substring in eine eigene Variable gespeichert und dann wieder in eine integer konvertiert.
    diese beiden Werte habe ich in ein Array gespeichert (welches die Funktion auf zurückgibt) einfach um mir eine weitere Funktion zu sparen.

    Ein weiteres Array benötige ich um die ersten beiden und letzten beiden Stellen der Vorjahreszahl abzuspeichern. Diese wird bei den Monaten Januar und Februar gebraucht.

    wob schrieb:

    Tritt der Fehler bei einem bestimmten Datum auf oder immer?

    Nein der Fehler tritt nicht immer auf.
    Z.b. funktioniert jetzt das Datum 27.06.1991 nicht. Vorher hat es funktioniert, aber dafür alle Daten ab 2000 nicht:D

    Schlangenmensch schrieb:

    Davon abgesehen, ist dein Algorithmus fehlerhaft. Zumindest stimmt die Ausgabe nicht, wenn ich dein Programm mit dem heutigen Datum starte.

    ja ich weiß 😞 😞 ich muss irgendeine Kleinigkeit verändert haben. Er hat schon den richtigen Tag angezeigt.

    Schlangenmensch schrieb:

    Und nochwas. Deine Fehlerbehandlung ist nicht in sich konsistent und falsch.
    Wenn du kein cin fail hast, führst du dein Programm einfach weiter aus.
    aber z.B. 0a0a0 führt nicht zu einem cin fail.

    Okay ja stimmt. Kann ich stattdessen

    if (cin.fail()&&cin.eof())
    

    nehmen?

    Schlangenmensch schrieb:

    Der Teil in dem if für cin fail funktioniert auch nicht richtig. Wenn dein Eingabebuffer Länge > 1 ist, reicht dein ignore nicht. Mit cin.ignore(1000,'\n') würde es immerhin bis zu einer Eingabe von 1000 Zeichen reichen.

    hab ich geändert 🙂

    Schlangenmensch schrieb:

    Was passiert denn, wenn die zweite Eingabe auch Fehlerhaft ist? Dann führst du dein Programm auch einfach weiter aus.

    klar stimmt. Ich schreibe gleich eine Schleife dafür.

    Furble Wurble schrieb:

    a) Mit eingeschalteten Warnungen kompilieren. (-Wall -pedantic oder ähnlich)
    b) Gründe für die Warnungen beheben.

    ich probiers mal



  • wob schrieb:

    2. Was soll der Komma-Operator hier bedeuten:

    wob wollte nichts über die Gaußklammern wissen.
    Du solltest darüber nachdenken, warum du da Kommas , stehen hast.
    Der Kommaoperator führt bei C++ meist für Missverständnisse. Gerade bei Anfängern.

    Und mit deiner Antwort hast du beiesen, dass du gar nicht weißt, wozu der da ist.

    Darum einfacher: Mit welchem Dezimaltrennzeichen werden Fließkommazahlen in C++ angegeben?



  • Philipp2706 schrieb:

    Okay ja stimmt. Kann ich stattdessen

    if (cin.fail()&&cin.eof())
    

    nehmen?

    Das ändert nichts daran, dass der Ausdruck zu false wird, wenn cin.fail()==false, du also mit der Eingabe 0a0a0 trotzdem nicht den if-Zweig kommst.

    Bei dem hier: ((int) (2, 6 * julMonat - 0, 2)) + 1; Was ist denn da dein erwartetes Ergbenis?

    willst du rechnen
    x = 2,6 * y - 0,2 + 1 ?
    In C++ nutzt man den "." als Dezimalseparator, also
    x= 2.6 * y - 0.2 + 1



  • Philipp2706 schrieb:

    wob schrieb:

    2. Was soll der Komma-Operator hier bedeuten:
    C++:
    int gaussKlammernAufrunden = ((int) (2, 6 * julMonat - 0, 2)) + 1;

    Das ist dass was ich mit den Gaußklammern meinte.

    Ich weiß, was eine Gaußklammer ist. Allerdings ist ((int) (2, 6 * julMonat - 0, 2)) + 1 dasselbe wie 3. (also 2 wegschmeißen, 6*julMonat -0 berechnnen und Ergebnis ignorieren, dann 2 in int casten und 1 addieren -> ergibt 3.

    wob schrieb:

    3. Was macht die Funktion stellenAbtrennen? Sieht sehr merkwürdig aus.

    Dazu habe ich die eingegebene Jahreszahl in einen String konvertiert,
    die ersten beiden und letzen beiden Stellen dieser Zahl mittels substring in eine eigene Variable gespeichert und dann wieder in eine integer konvertiert.

    Klingt sehr kompliziert und ineffizient. Siehe Dirks Antwort. "Teilen mit Rest" ist das Stichwort.

    wob schrieb:

    Tritt der Fehler bei einem bestimmten Datum auf oder immer?

    Nein der Fehler tritt nicht immer auf.
    Z.b. funktioniert jetzt das Datum 27.06.1991 nicht. Vorher hat es funktioniert, aber dafür alle Daten ab 2000 nicht:D

    In wochentagDatum wird nicht immer ein return aufgerufen. Siehe compiler-Warnungen!



  • DirkB schrieb:

    wob schrieb:
    2. Was soll der Komma-Operator hier bedeuten:
    wob wollte nichts über die Gaußklammern wissen.
    Du solltest darüber nachdenken, warum du da Kommas , stehen hast.
    Der Kommaoperator führt bei C++ meist für Missverständnisse. Gerade bei Anfängern.

    Und mit deiner Antwort hast du beiesen, dass du gar nicht weißt, wozu der da ist.

    Darum einfacher: Mit welchem Dezimaltrennzeichen werden Fließkommazahlen in C++ angegeben?

    Schlangemensch schrieb:

    Bei dem hier: ((int) (2, 6 * julMonat - 0, 2)) + 1; Was ist denn da dein erwartetes Ergbenis?

    willst du rechnen
    x = 2,6 * y - 0,2 + 1 ?
    In C++ nutzt man den "." als Dezimalseparator, also
    x= 2.6 * y - 0.2 + 1

    Klar, dummer Fehler :p

    Ich schreib den Code mal um und melde mich später. Danke erstmal 👍



  • Schlangenmensch schrieb:

    Philipp2706 schrieb:

    Okay ja stimmt. Kann ich stattdessen
    C++:
    if (cin.fail()&&cin.eof())
    nehmen?

    Das ändert nichts daran, dass der Ausdruck zu false wird, wenn cin.fail()==false, du also mit der Eingabe 0a0a0 trotzdem nicht den if-Zweig kommst.

    soo...
    ich habe den ganzen Eingabeteil überarbeitet. Jetzt müssten alle Fehler abgedeckt sein 🙂 🙂 Gibt es da noch was zu bemängeln?

    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    
    /* 
     */
    
    #include <iostream>
    #include <string> 
    #include <sstream>  
    #include <vector>
    #include <cmath>  
    #include <stdexcept>
    
    using namespace std;
    
    //Wochentage enum
    enum WochentageTyp {
        Sonntag, Montag, Dienstag, Mittwoch,
        Donnerstag, Freitag, Samstag
    };
    typedef WochentageTyp wochentage;
    string wochentageStr [] = {"Sonntag", "Montag", "Dienstag", "Mittwoch",
        "Donnerstag", "Freitag", "Samstag"};
    
    //Funktionen
    int wochentagDatum(int eingabeMonat, int eingabeJahr, int eingabeTag);
    vector<int> stellenAbtrennen(int eingabeJahr);
    wochentage wochentagErsterJanuar(int jahresZahlGauss);
    int julKalenderUmrechnen(int eingabeMonat);
    bool pruefenInteger(string eingabe);
    
    /*
     * 
     */
    int main(int argc, char** argv) {
        cout << "Immerwährender Kalender" << endl;
    
        string eingabeZeile;
        string eingabeTagStr;
        string eingabeMonatStr;
        string eingabeJahrStr;
        int eingabeTagInt, eingabeMonatInt, eingabeJahrInt;
    
        bool schleifeVerlassen = false;
        while (!schleifeVerlassen) {
            cout << "Bitte geben Sie ein Datum ein" << endl;
            //Eingabe des Datums
            string eingabeZeile;
            getline(cin, eingabeZeile);
            eingabeTagStr = eingabeZeile.substr(0, 2);
            eingabeMonatStr = eingabeZeile.substr(3, 2);
            eingabeJahrStr = eingabeZeile.substr(6, 4);
            //PrüfenInteger jeweils aufrufen
            bool boolVerknuepft =
                    (pruefenInteger(eingabeTagStr)) &&
                    (pruefenInteger(eingabeMonatStr)) &&
                    (pruefenInteger(eingabeJahrStr));
    
            if ((!("." == string(1, eingabeZeile[2]) &&
                    !("." == string(1, eingabeZeile[5]) == 0))) &&
                    (boolVerknuepft == 0)) {
                cout << "#Punktsetzung falsch" << endl;
                cout << "#Keine Symbole, Buchstaben oder Kommazahlen zulässig" << endl;
                continue;
            }
    
            if (!("." == string(1, eingabeZeile[2]) &&
                    !("." == string(1, eingabeZeile[5]) == 0))) {
                cout << "#Punktsetzung falsch" << endl;
                continue;
            }
    
            if (boolVerknuepft == 0) {
                cout << "#Keine Symbole, Buchstaben oder Kommazahlen zulässig" << endl;
                continue;
            }
    
            if (boolVerknuepft == 1) {
                eingabeTagInt = stoi(eingabeTagStr);
                eingabeMonatInt = stoi(eingabeMonatStr);
                eingabeJahrInt = stoi(eingabeJahrStr);
            }
    
            if (eingabeTagInt > 31 || eingabeMonatInt > 12 ||
                    (eingabeJahrInt < 1000 && eingabeJahrInt > 9999)) {
                cout << "#Unzulässige Werte" << endl;
                continue;
            }
    
            if (!(cin.fail() && cin.eof())&&((!(eingabeJahrInt % 4) &&
                    (eingabeJahrInt % 100)) || !(eingabeJahrInt % 400))) {
                cout << "#Das eingegebene Jahr ist ein Schaltjahr" << endl;
            }
    
            cout << "Eingabe korrekt" << endl;
            break;
        }
    
        //Julianischer Monat Umrechnung
        int julMonat = julKalenderUmrechnen(eingabeMonatInt);
        //Ausgabe Text für die erste Funktion
        cout << "--------------------------------------------" << endl <<
                "Der Wochentag des 1. Januars des Jahres " << eingabeJahrInt <<
                " ist ein "
                << wochentageStr [wochentagErsterJanuar(eingabeJahrInt)] << endl;
        //Zweite Funktion
        cout << "Der Wochentag des ersten Tages dieses Monats ist ein " <<
                wochentageStr[wochentagDatum(julMonat, eingabeJahrInt, 1)] << endl
                << "Der Wochentag des eingegebenen Datum ist ein  " <<
                wochentageStr[wochentagDatum(julMonat, eingabeJahrInt, eingabeTagInt)]
                << endl;
    }
    
    //Zahl des Monats in julianischen Kalender umrechnen
    int julKalenderUmrechnen(int eingabeMonat) {
        int monateJul;
        switch (eingabeMonat) {
            case 1: monateJul = 11;
                break;
            case 2: monateJul = 12;
                break;
            case 3: monateJul = 1;
                break;
            case 4: monateJul = 2;
                break;
            case 5: monateJul = 3;
                break;
            case 6: monateJul = 4;
                break;
            case 7: monateJul = 5;
                break;
            case 8: monateJul = 6;
                break;
            case 9: monateJul = 7;
                break;
            case 10: monateJul = 8;
                break;
            case 11: monateJul = 9;
                break;
            case 12: monateJul = 10;
                break;
        }
        return monateJul;
    }
    
    bool pruefenInteger(string eingabe) {
    
        char zeicheni;
        int ascii;
    
        for (int i = 0; i <= eingabe.length(); i++) {
            zeicheni = eingabe[i];
            ascii = int(zeicheni);
            if (ascii < 58 && i >= eingabe.length()) {
                return true;
            }
            if (ascii > 58) return false;
        }
    }
    
    wochentage wochentagErsterJanuar(int jahresZahlGauss) {
        //eingabeJahresZahl=vierstellige Jahreszahl
        //Gaußsche Wochentagsformel
        wochentage gaussTag = (wochentage) ((1 + 5 * ((jahresZahlGauss - 1) % 4)
                + 4 * ((jahresZahlGauss - 1) % 100) +
                6 * ((jahresZahlGauss - 1) % 400)) % 7);
        return gaussTag;
    }
    
    // Georg Glaeser Algorithmus
    int wochentagDatum(int julMonat, int eingabeJahr, int eingabeTag) {
    
        vector<int> pos;
        vector<int> posVorjahr;
    
        pos = stellenAbtrennen(eingabeJahr);
        posVorjahr = stellenAbtrennen(eingabeJahr - 1);
    
        int letzteStellen = pos[0];
        int ersteStellen = pos[1];
    
        if (julMonat == 1 || julMonat == 2) {
            letzteStellen = posVorjahr [0];
            ersteStellen = posVorjahr [1];
        }
    
        int gaussKlammernAufrunden = ((int) (2.6 * julMonat - 0.2)) + 1;
        int wochentagMonatsErster = ((eingabeTag + gaussKlammernAufrunden
                + letzteStellen + (letzteStellen / 4) +
                (ersteStellen / 4) - 2 * ersteStellen) % 7);
    
        return wochentagMonatsErster;
    }
    
    vector<int> stellenAbtrennen(int eingabeJahr) {
        vector<int> positionen;
        int erstenStellen = eingabeJahr / 100;
        positionen.push_back(erstenStellen);
        int letzteStellen = eingabeJahr % 100;
        positionen.push_back(letzteStellen);
    
        return positionen;
    }
    

    Ich bekomme allerdings immer noch diese Segmention-Faults. Ich bin mir ziemlich sicher dass es irgendwie an dem Vektor liegen muss. Aber ich komme nicht darauf was falsch sein soll 😕 eventuell passt die Dimension von dem übergebenen Vektor nicht zu dem Vektor der den zu übergebenden Vektor speichern soll 😕 😕



  • Grade nur kurz, weil vom Handy.

    Zwei Sachen:

    Punkt Segfault:

    bool pruefenInteger(string eingabe) {
    
        char zeicheni;
        int ascii;
    
        for (int i = 0; i <= eingabe.length(); i++) {
            zeicheni = eingabe[i];
            ascii = int(zeicheni);
            if (ascii < 58 && i >= eingabe.length()) {
                return true;
            }
            if (ascii > 58) return false;
        }
    }
    

    Was wird denn im letzten Schleifen Durchlauf an zeicheni zugewiesen?

    Punkt Eingabe Überprüfung:
    Was passiert, wenn die Eingabe z.B. Nur 3 Zeichen lang ist.



  • Bevor du weitermachst, solltest du unbedingt und immer Compilerwarnungen anschalten!

    Hier:

    test.cpp:65:23: warning: suggest parentheses around comparison in operand of ‘==’ [-Wparentheses]
    !("." == string(1, eingabeZeile[5]) == 0))) &&
    ^
    test.cpp:73:23: warning: suggest parentheses around comparison in operand of ‘==’ [-Wparentheses]
    !("." == string(1, eingabeZeile[5]) == 0))) {
    ^
    test.cpp: At global scope:
    test.cpp:40:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
    int main(int argc, char** argv) {
    ^
    test.cpp:40:27: warning: unused parameter ‘argv’ [-Wunused-parameter]
    int main(int argc, char** argv) {
    ^
    test.cpp: In function ‘bool pruefenInteger(std::__cxx11::string)’:
    test.cpp:158:23: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    for (int i = 0; i <= eingabe.length(); i++) {
    ^
    test.cpp:161:29: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if (ascii < 58 && i >= eingabe.length()) {
    ^
    test.cpp:166:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^

    Besonders wichtig dabei sind die ersten beiden Meldungen und die letzte Meldung.

    Was willst du mit a==b==0 erreichen? Und wozu willst du ein char in einen String wandeln? Willst du nicht sowas wie if (eingabeZeile[5] == '.') schreiben? Außerdem: bist du sicher, dass es eingabeZeile[5] überhaupt gibt? Was ist, wenn der Benutzer weniger Zeichen eingibt?

    Bei der letzten Warnung: stelle immer sicher, dass eine Funktion, die etwas returnen soll, auch etwas returnt!

    Zu den anderen: String-Längen sind unsigned, hier kannst du also z.B. size_t i statt int i schreiben.

    Um die beiden unused Parameter musst du dich nicht unbedingt kümmern -> oder schreib einfach int main() wenn du argc/argv nicht benötigst. Oder lass einfach die Namen weg oder kommentiere sie aus, z.B. so: int main(int /*argc*/, char** /*argv*/) .

    Weitere Kommentare (erster Blick, absolut unvollständig):

    • pruefenInteger : was ist "58"? Irgendwie verstehe ich die gesamte Funktion nicht. Willst du nicht sowas wie "isdigit" verwenden?
      - meinst du nicht, dass man julKalenderUmrechnen einfacher formulieren könnte?
      - wozu die Variable schleifeVerlassen , die eh immer false ist?


  • Schlangenmensch schrieb:

    Punkt Eingabe Überprüfung:
    Was passiert, wenn die Eingabe z.B. Nur 3 Zeichen lang ist.

    ist behoben

    if (eingabeTag > 31 || eingabeMonat > 12 ||
    			eingabeJahr < 1000 || eingabeJahr > 9999) {
    			cout << "#Unzulässige Werte" << endl;
    			continue;
    		}
    

    wob schrieb:

    Was willst du mit a==b==0 erreichen? Und wozu willst du ein char in einen String wandeln? Willst du nicht sowas wie if (eingabeZeile[5] == '.') schreiben?

    ja stimmt. Weiß ich auch nicht mehr so genau was ich mir dabei gedacht habe 😃

    wob schrieb:

    Außerdem: bist du sicher, dass es eingabeZeile[5] überhaupt gibt? Was ist, wenn der Benutzer weniger Zeichen eingibt?

    Ich würde ja vorher testen ob die eingegebene Zahl vierstellig ist.

    wob schrieb:

    - pruefenInteger: was ist "58"? Irgendwie verstehe ich die gesamte Funktion nicht. Willst du nicht sowas wie "isdigit" verwenden?

    Oh man 😡 hätte ich "isdigit" vorher gekannt, hätte ich mir einige Stunden Arbeit ersparen können 😞

    wob schrieb:

    Zu den anderen: String-Längen sind unsigned, hier kannst du also z.B. size_t i statt int i schreiben.

    geändert

    wob schrieb:

    - meinst du nicht, dass man julKalenderUmrechnen einfacher formulieren könnte?
    - wozu die Variable schleifeVerlassen, die eh immer false ist?

    auch geändert
    ...
    Ich habe den Code jetzt mit Visual Studio analysiert und es wurden keine Fehler festgestellt.

    Die segmentation faults sind weg aber das Programm wird mit "Code 0" beendet. 😞

    /*
    * To change this license header, choose License Headers in Project Properties.
    * To change this template file, choose Tools | Templates
    * and open the template in the editor.
    */
    
    /*
    */
    
    #include <iostream>
    #include <string> 
    #include <sstream>  
    #include <vector>
    #include <cmath>  
    #include <stdexcept>
    #include <iostream>
    #include <algorithm> // for copy
    #include <iterator> // for ostream_iterator
    #include <vector>
    
    using namespace std;
    
    //Wochentage enum
    enum WochentageTyp {
    	Sonntag, Montag, Dienstag, Mittwoch,
    	Donnerstag, Freitag, Samstag
    };
    typedef WochentageTyp wochentage;
    string wochentageStr[] = { "Sonntag", "Montag", "Dienstag", "Mittwoch",
    "Donnerstag", "Freitag", "Samstag" };
    
    //Funktionen
    int wochentagDatum(int eingabeMonat, int eingabeJahr, int eingabeTag);
    vector<int> stellenAbtrennen(int eingabeJahr);
    wochentage wochentagErsterJanuar(int jahresZahlGauss);
    int julKalenderUmrechnen(int eingabeMonat);
    
    /*
    *
    */
    int main(int argc, char** argv) {
    	cout << "Immerwährender Kalender" << endl;
    
    	int eingabeTag, eingabeMonat, eingabeJahr;
    	char punkt1, punkt2;
    	do{
    		cout << "Bitte geben Sie ein Datum ein" << endl;
    		//Eingabe des Datums
    		cin >> eingabeTag >> punkt1 >> eingabeMonat >> punkt2 >> eingabeJahr;
    		//Prüfen ob Integer
    		bool boolVerknuepft =
    			(isdigit(eingabeTag)) &&
    			(isdigit(eingabeMonat)) &&
    			(isdigit(eingabeJahr));
    
    		if ((!(punkt1 == '.') &&
    			!(punkt2 == '.')) &&
    			(punkt2 == 0)) {
    			cout << "#Punktsetzung falsch" << endl;
    			cout << "#Keine Symbole, Buchstaben oder Kommazahlen zulässig" << endl;
    			continue;
    		}
    
    		if (!(punkt1 == '.') &&
    			!(punkt2 == '.')) {
    			cout << "#Punktsetzung/Format falsch" << endl;
    			continue;
    		}
    
    		if (boolVerknuepft == 1) {
    			cout << "#Keine Symbole, Buchstaben oder Kommazahlen zulässig" << endl;
    			continue;
    		}
    
    		if (eingabeTag > 31 || eingabeMonat > 12 ||
    			eingabeJahr < 1000 || eingabeJahr > 9999) {
    			cout << "#Unzulässige Werte" << endl;
    			continue;
    		}
    
    		if ((eingabeTag > 31 || eingabeMonat > 12 ||
    			eingabeJahr < 1000 || eingabeJahr > 9999) &&
    			((!(eingabeJahr % 4) &&
    			(eingabeJahr % 100)) || !(eingabeJahr % 400))) {
    			cout << "#Das eingegebene Jahr ist ein Schaltjahr" << endl;
    		}
    
    		cout << "Eingabe korrekt" << endl;
    		break;
    	} while (cin);
    
    	//Julianischer Monat Umrechnung
    	int julMonat = julKalenderUmrechnen(eingabeMonat);
    	//Ausgabe Text für die erste Funktion
    	cout << "--------------------------------------------" << endl <<
    		"Der Wochentag des 1. Januars des Jahres " << eingabeJahr <<
    		" ist ein "
    		<< wochentageStr[wochentagErsterJanuar(eingabeJahr)] << endl;
    	//Zweite Funktion
    	cout << "Der Wochentag des ersten Tages dieses Monats ist ein " <<
    		wochentageStr[wochentagDatum(julMonat, eingabeJahr, 1)] << endl
    		<< "Der Wochentag des eingegebenen Datum ist ein  " <<
    		wochentageStr[wochentagDatum(julMonat, eingabeJahr, eingabeTag)]
    		<< endl;
    }
    
    //Zahl des Monats in julianischen Kalender umrechnen
    int julKalenderUmrechnen(int eingabeMonat) {
    	int monateJul;
    	if (eingabeMonat == 1 || eingabeMonat == 2) {monateJul = eingabeMonat + 10; return monateJul;}
    	else {monateJul = eingabeMonat + -2; return monateJul;}
    }
    
    wochentage wochentagErsterJanuar(int jahresZahlGauss) {
    	//eingabeJahresZahl=vierstellige Jahreszahl
    	//Gaußsche Wochentagsformel
    	wochentage gaussTag = (wochentage)((1 + 5 * ((jahresZahlGauss - 1) % 4)
    		+ 4 * ((jahresZahlGauss - 1) % 100) +
    		6 * ((jahresZahlGauss - 1) % 400)) % 7);
    	return gaussTag;
    }
    
    // Georg Glaeser Algorithmus
    int wochentagDatum(int julMonat, int eingabeJahr, int eingabeTag) {
    
    	vector<int> pos(stellenAbtrennen(eingabeJahr));
    	vector<int> posVorjahr(stellenAbtrennen(eingabeJahr - 1));
    
    	int* arrPos = pos.data();
    	int* arrPosVorjahr = posVorjahr.data();
    
    	int letzteStellen = arrPos[0];
    	int ersteStellen = arrPos[1];
    
    	if (julMonat == 1 || julMonat == 2) {
    		letzteStellen = arrPosVorjahr[0];
    		ersteStellen = arrPosVorjahr[1];
    	}
    	int gaussKlammernAufrunden = ((int)(2.6 * julMonat - 0.2)) + 1;
    	int wochentagMonatsErster = ((eingabeTag + gaussKlammernAufrunden
    		+ letzteStellen + (letzteStellen / 4) +
    		(ersteStellen / 4) - 2 * ersteStellen) % 7);
    
    	return wochentagMonatsErster;
    }
    
    vector<int> stellenAbtrennen(int eingabeJahr) {
    	vector<int> positionen;
    	int erstenStellen = eingabeJahr / 100;
    	positionen.push_back(erstenStellen);
    	int letzteStellen = eingabeJahr % 100;
    	positionen.push_back(letzteStellen);
    
    	return positionen;
    }
    


  • Philipp2706 schrieb:

    Die segmentation faults sind weg aber das Programm wird mit "Code 0" beendet. 😞

    Was erwartest du denn, wie dein Programm beendet wird?

    Was soll while(cin) bewirken? Warum springst du vor der while Überprüfung mit break aus der Schleife?



  • Philipp2706 schrieb:

    int wochentagDatum(int julMonat, int eingabeJahr, int eingabeTag) {
    	vector<int> pos(stellenAbtrennen(eingabeJahr));
    	int* arrPos = pos.data();
    	int letzteStellen = arrPos[0];
    	int ersteStellen = arrPos[1];
    

    Wer hat dir denn so beigebracht?! Wozu der Umweg über int*, womit du die Vorteile des vectors gleich wieder wegschmeißt.

    Sollte es nicht besser heißen:

    int wochentagDatum(int julMonat, int eingabeJahr, int eingabeTag) {
    	auto pos = stellenAbtrennen(eingabeJahr);
    	// irgendeine Art von ensure(pos.size() > 1) 
    	int letzteStellen = pos[0];
    	int ersteStellen = pos[1];
    


  • Warum überhaupt eine Funktion für eingabeJahr%100 bzw. eingabeJahr/100 ?
    Dann doch lieber zwei inline-Funktionen für Jahre und Jahrunderte.



  • DirkB schrieb:

    Warum überhaupt eine Funktion für eingabeJahr%100 bzw. eingabeJahr/100 ?
    Dann doch lieber zwei inline-Funktionen für Jahre und Jahrunderte.

    So habe ich es jetzt auch gemacht. Ich habe zu kompliziert gedacht und habe es sehr unterschätzt einen Vektor an eine Funktion zu übergeben.
    Ich bin auf die Idee gekommen weil ich mit substring anstelle von % und / gearbeitet habe um an die ersten und letzten Stellen der Jahreszahl zu kommen.
    Da hatte ich viel Code und wollte den Code nicht zweimal da stehen haben.

    Schlangenmensch schrieb:

    Was soll while(cin) bewirken? Warum springst du vor der while Überprüfung mit break aus der Schleife?

    Das break habe ich vergessen zu löschen, aber eigentlich funktioniert while (cin) doch. (Vorausgesetzt das Programm würde sich nicht beenden).

    Schlangenmesch schrieb:

    Philipp2706 schrieb:

    Die segmentation faults sind weg aber das Programm wird mit "Code 0" beendet. 😞

    Was erwartest du denn, wie dein Programm beendet wird?

    Die segmentation faults sind doch nicht weg 😞 Visual Studio zweigt mir "Code 0" und netbeans zeigt immer noch das selbe 😞

    Ich habe vermutet dass es an dem Vektor liegt der von der Funktion zurückgegeben wird aber das kann es ja jetzt auch nicht mehr sein.

    Jetzt habe ich die Formel von "int wochentagMonatsErster" in Verdacht, aber ich sehe nicht was daran so einen Fehler verursachen könnte.

    Ich bin echt ratlos so langsam 😕

    #include <iostream>
    #include <string> 
    #include <sstream>  
    #include <vector>
    #include <cmath>  
    #include <stdexcept>
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    //Wochentage enum
    enum WochentageTyp {
    	Sonntag, Montag, Dienstag, Mittwoch,
    	Donnerstag, Freitag, Samstag
    };
    typedef WochentageTyp wochentage;
    string wochentageStr[] = { "Sonntag", "Montag", "Dienstag", "Mittwoch",
    "Donnerstag", "Freitag", "Samstag" };
    
    //Funktionen
    int wochentagDatum(int eingabeMonat, int eingabeJahr, int eingabeTag);
    wochentage wochentagErsterJanuar(int jahresZahlGauss);
    int julKalenderUmrechnen(int eingabeMonat);
    inline int erstenStellen(int eingabeJahr);
    inline int letzteStellen(int eingabeJahr);
    
    /*
    *
    */
    int main(int argc, char** argv) {
    	cout << "Immerwährender Kalender" << endl;
    
    	int eingabeTag, eingabeMonat, eingabeJahr;
    	char punkt1, punkt2;
    
    	do{
    		cout << "Bitte geben Sie ein Datum ein" << endl;
    		//Eingabe des Datums
    		cin >> eingabeTag >> punkt1 >> eingabeMonat >> punkt2 >> eingabeJahr;
    		//Prüfen ob Integer
    		bool boolVerknuepft =
    			isdigit(eingabeTag) &&
    			isdigit(eingabeMonat) &&
    			isdigit(eingabeJahr);
    
    		if ((!(punkt1 == '.') &&
    			!(punkt2 == '.')) &&
    			(punkt2 == 0)) {
    			cout << "#Punktsetzung falsch" << endl;
    			cout << "#Keine Symbole, Buchstaben oder Kommazahlen zulässig" << endl;
    			continue;
    		}
    
    		if (!(punkt1 == '.') &&
    			!(punkt2 == '.')) {
    			cout << "#Punktsetzung/Format falsch" << endl;
    			continue;
    		}
    
    		if (boolVerknuepft == 1) {
    			cout << "#Keine Symbole, Buchstaben oder Kommazahlen zulässig" << endl;
    			continue;
    		}
    
    		if (eingabeTag > 31 || eingabeMonat > 12 ||
    			eingabeJahr < 1000 || eingabeJahr > 9999) {
    			cout << "#Unzulässige Werte" << endl;
    			continue;
    		}
    
    		if ((eingabeTag > 31 || eingabeMonat > 12 ||
    			eingabeJahr < 1000 || eingabeJahr > 9999) &&
    			((!(eingabeJahr % 4) &&
    			(eingabeJahr % 100)) || !(eingabeJahr % 400))) {
    			cout << "#Das eingegebene Jahr ist ein Schaltjahr" << endl;
    		}
    
    		cout << "Eingabe korrekt" << endl;
    		break;
    	} while (cin);
    
    	//Julianischer Monat Umrechnung
    	int julMonat = julKalenderUmrechnen(eingabeMonat);
    	//Ausgabe Text für die erste Funktion
    	cout << "--------------------------------------------" << endl <<
    		"Der Wochentag des 1. Januars des Jahres " << eingabeJahr <<
    		" ist ein "
    		<< wochentageStr[wochentagErsterJanuar(eingabeJahr)] << endl;
    	//Zweite Funktion
    	cout << "Der Wochentag des ersten Tages dieses Monats ist ein " <<
    		wochentageStr[wochentagDatum(julMonat, eingabeJahr, 1)] << endl
    		<< "Der Wochentag des eingegebenen Datum ist ein  " <<
    		wochentageStr[wochentagDatum(julMonat, eingabeJahr, eingabeTag)]
    		<< endl;
    }
    
    //Zahl des Monats in julianischen Kalender umrechnen
    int julKalenderUmrechnen(int eingabeMonat) {
    	int monateJul;
    	if (eingabeMonat == 1 || eingabeMonat == 2) {monateJul = eingabeMonat + 10; return monateJul;}
    	else {monateJul = eingabeMonat + -2; return monateJul;}
    }
    
    wochentage wochentagErsterJanuar(int jahresZahlGauss) {
    	//eingabeJahresZahl=vierstellige Jahreszahl
    	//Gaußsche Wochentagsformel
    	wochentage gaussTag = (wochentage)((1 + 5 * ((jahresZahlGauss - 1) % 4)
    		+ 4 * ((jahresZahlGauss - 1) % 100) +
    		6 * ((jahresZahlGauss - 1) % 400)) % 7);
    	return gaussTag;
    }
    
    // Georg Glaeser Algorithmus
    
    	int wochentagDatum(int julMonat, int eingabeJahr, int eingabeTag) {
    		int letzteStellenVar = letzteStellen(eingabeJahr);
    		int ersteStellenVar = erstenStellen(eingabeJahr);
    		int vorjahr = eingabeJahr - 1;
    
    	if (julMonat == 1 || julMonat == 2) {
    		letzteStellenVar = letzteStellen(vorjahr);
    		ersteStellenVar = erstenStellen(vorjahr);
    	}
    	int gaussKlammernAufrunden = ((int)(2.6 * julMonat - 0.2)) + 1;
    	int wochentagMonatsErster = ((eingabeTag + gaussKlammernAufrunden
    		+ letzteStellenVar + (letzteStellenVar / 4) +
    		(ersteStellenVar / 4) - 2 * ersteStellenVar) % 7);
    
    	return wochentagMonatsErster;
    }
    
    	inline int erstenStellen(int eingabeJahr)
    	{
    		int erstenStellen = eingabeJahr / 100;
    		return erstenStellen;
    	}
    	inline int letzteStellen(int eingabeJahr)
    	{
    		int letzteStellen = eingabeJahr % 100;
    		return letzteStellen;
    	}
    


  • Ein Grund in deinem Programm ein Segmentation Fault zu liefern ist bei Zugriff auf das Array wochentageStr,
    wenn der Index falsch ist.

    Lass dir doch mal innerhalb der Funktionen wochentagErsterJanuar und wochentagDatum den Rückgabewert ausgeben (mit cout)
    Dann siehst du welcher Index das ist. Erlaubt sind ja nur 0 bis 6.

    Oder mach da noch ein assert . http://www.cplusplus.com/reference/cassert/assert/



  • Philipp2706 schrieb:

    Schlangenmensch schrieb:

    Was soll while(cin) bewirken? Warum springst du vor der while Überprüfung mit break aus der Schleife?

    Das break habe ich vergessen zu löschen, aber eigentlich funktioniert while (cin) doch. (Vorausgesetzt das Programm würde sich nicht beenden).

    Okay, ich stell die Frage mal anders: Weißt du auch warum das funktioniert?


Anmelden zum Antworten