#include using namespace std; bool istSchaltjahr(int jahreszahl) // Aufbau der Kopfzeile einer Funktion ist immer wie folgt: // () // Datentyp bool kann die Werte true und false annehmen { if (jahreszahl % 4 == 0) { if (jahreszahl % 100 == 0) { if (jahreszahl % 400 == 0) { return true; // an dieser Stelle wird die Funktion // istSchaltjahr beendet und das Programm springt an die // Stelle zurück, an der istSchaltjahr aufgerufen wurde. // An der Stelle wird quasi der Aufruf istSchaltjahr(...) // durch den Wert ersetzt, der hier mittels return // zurückgegeben wird. } else { return false; } } else { return true; } } else // jahreszahl %4 != 0 { return false; } } // Ende istSchaltjahr bool tageszahlOK(int tage, int tageImMonat) // gibt true zurück wenn der Parameter tage zwischen 1 und tageImMonat liegt { if (1 <= tage && tage <= tageImMonat) { return true; } else { return false; } } // Forward declaration - vorweggenommene/vorwärts Deklaration // diese gibt dem Compiler an, dass es Funktion gibt, // die den Namen xyz hat und die Parameter abc und def erwartet int tageImMonat(int, int); // bei Vorwärtsdeklarationen von Funktionen können wir die Variablennamen // weglassen (diese werden vom Compiler (an dieser Stelle) ignoriert) // Wenn dadurch an dieser Stelle der Sinn der Funktion verschleiert wird, // sollten Sie die Variablennamen jedoch unbedingt angeben // konkret: in diesem Beispiel hätte man die Variablennamen besser angeben sollen bool datumIstGueltig(int tag, int monat, int jahr) { if (1 <= monat && monat <= 12) // && verknüpft zwei boolsche Werte // in diesem Fall das Ergebnis des Vergleichs 1 <= monat und // das Ergebnis des Vergleichs monat <= 12 // das Ergebnis ist wahr, wenn beide Vergleich sich zu wahr auswerten { if (tageszahlOK(tag,tageImMonat(monat,jahr))) { return true; } else { return false; } } // Monat liegt zwischen 1 und 12 else { return false; } } int tageImMonat(int monat, int jahr) // Eingabe: eine Monatszahl, eine Jahreszahl // Ausgabe: 28/29/30/31 bei gültigen Kombinationen, 31 sonst { if (monat == 2) { if (istSchaltjahr(jahr)) { return 29; } else { return 28; } } // Ende Februar else if (monat == 4 || monat == 6 || monat == 9 || monat == 11) // das || ist eine logische ODER-Verknüpfung // wertet sich zu wahr aus, wenn wenigstens ein Operand wahr ist { return 30; } else // es ist ein Monat mit 31 Tagen { return 31; } } void ausgabeDatumIstGueltig(void) // nur als Beispiel für eine Funktion ohne Parameter und ohne Rückgabewert { cout << "Das Datum ist gueltig!" << endl; } void ausgabeDatumIstNichtGueltig(void) // nur als Beispiel für eine Funktion ohne Parameter und ohne Rückgabewert { cout << "Das Datum ist nicht gueltig!" << endl; } int anzahlDerTageSeitJahresanfang(int tag, int monat, int jahr) { // die Prüfung, ob das Datum tag.monat.jahr gültig ist, wird hier nicht überprüft // Rückgabewert: bei gültigem Datum die Anzahl der Tage seit dem 1.1.jahr // bei unklarer Sachlage, immer angeben, was genau passiert, hier z.B. // Rückgabewert beim 1.1.jahr = 1 int mm; int anzDerTage = 0; for (mm = 1; mm < monat; mm = mm + 1) // zur Erinnerung: for (Initialisierung; Abbruchbedg.; Inkrement) // Beachte: ist die Bedingung schon zu Beginn verletzt, wird die Schleife // garnicht betreten, sondern gleich bei der zugehörigen "}" fortgesetzt { anzDerTage = anzDerTage + tageImMonat(mm, jahr); } anzDerTage = anzDerTage + tag; return anzDerTage; // Argumente für/wider for (int xyz= ...) oder int xyz; for (xyz= ...) // - im ersten Fall gilt das xyz nur bis zum Ende der for-Schleife // - im zweiten Fall auch danach // Problematik: so sollte es sein, aber nicht alle Compiler halten sich dran // deshalb: keine Variablendeklaration im Initailisierungsteil der for-Schleife } int anzahlDerTageZwischenAundB(int tagA, int monatA, int jahrA, int tagB, int monatB, int jahrB) // liefert für zwei Datumsangaben A und B die Anzahl der Tage zwischen A (exkl.) und B (inkl.) { int anzDerTage = 0; if (jahrA == jahrB) { anzDerTage = anzahlDerTageSeitJahresanfang(tagB,monatB,jahrB) - anzahlDerTageSeitJahresanfang(tagA,monatA,jahrA); return anzDerTage; } else if (jahrA < jahrB) { int jj; if (istSchaltjahr(jahrA)) { anzDerTage = 366 - anzahlDerTageSeitJahresanfang(tagA,monatA,jahrA); } else { anzDerTage = 365 - anzahlDerTageSeitJahresanfang(tagA,monatA,jahrA); } for (jj = jahrA + 1; jj <= jahrB - 1; jj = jj + 1) { if (istSchaltjahr(jj)) { anzDerTage = anzDerTage + 366; } else { anzDerTage = anzDerTage + 365; } } anzDerTage = anzDerTage + anzahlDerTageSeitJahresanfang(tagB,monatB,jahrB); return anzDerTage; // noch selbst einfügen, was passiert, wenn die Monate/Tage voreinander liegen } else // jahrA > jahrB { // return 0; // nur, weil's jetzt schnell geht, nicht, weil es hübsch ist return - anzahlDerTageZwischenAundB(tagB,monatB,jahrB,tagA,monatA,jahrA); // eine Möglichkeit } } int wochentagAmDatum(int tag, int monat, int jahr) // 15.10.1582, Freitag, war Beginn des Gregorianischen Kalenders // Ausgabe soll sein: 1 für Montag, 2 für Dienstag, ..., 7 für Sonntag { int abFreitagGerechnet = anzahlDerTageZwischenAundB(15,10,1582,tag,monat,jahr)%7; return ((abFreitagGerechnet+4)%7)+1; } void ausgabeWochentag(int wotag) // gibt bei wotag==1 Montag aus, bei 2 Dienstag, etc. bei außerhalb 1-7 undefiniert { if (wotag == 1) { cout << "Montag"; } else if (wotag == 2) { cout << "Dienstag"; } else if (wotag == 3) { cout << "Mittwoch"; } else if (wotag == 4) { cout << "Donnerstag"; } else if (wotag == 5) { cout << "Freitag"; } else if (wotag == 6) { cout << "Samstag"; } else // sollte (wotag == 7) { cout << "Sonntag"; } } int main(void) { int tag, monat, jahr; //, tagB, monatB, jahrB; //Aufgabe: die Eingabe des Datums soll solange //wiederholt werden, bis ein gültiges Datum eingegeben wurde // do // { // cout << "Gib bitte einen Tag Monat und Jahr ein: "; // cin >> tag >> monat >> jahr; // } while (!(datumIstGueltig(tag,monat,jahr))); // !() ist dieser Ausdruck wahr, wenn falsch ist, und umgekehrt // Die Struktur einer bedingten Schleife (fußgesteuert) ist immer(!) // do // { // // // ... // } while (); // Wenn eine Schleife wiederholt werden soll, bis etwas gilt, lautet die letzte Zeile // } while (!(> tag >> monat >> jahr; // while (!(datumIstGueltig(tag,monat,jahr))) // { // cout << "Das war kein gueltiges Datum!" << endl // << "Gib bitte nochmal einen Tag Monat und Jahr ein: "; // cin >> tag >> monat >> jahr; // } // wird die Bedingung wie hier zu Beginn abgefragt, spricht man von kopfgesteuerten Schleifen // while () // { // // // ... // } // geht das auch mit for-Schleifen? // zur Erinnerung: for (;;) { } // for-Schleife ist lediglich eine Abkürzung: // { // // while () // { // // // } // } // for( ;(!(datumIstGueltig(tag,monat,jahr))); ) // { // cout << "Das war kein gueltiges Datum!" << endl // << "Gib bitte nochmal einen Tag Monat und Jahr ein: "; // cin >> tag >> monat >> jahr; // } // ist das sinnvoll? // es tut, aber: // for-Schleifen sind Zählschleifen, bei denen man i.A. vorher wissen sollte, // wie oft diese durchlaufen werden! // Idee: es gibt verschiedene Arten von Schleifen, weil in der Praxis verschiedene // Arten benötigt werden // deshalb (zur Lesbarkeit): for-Schleifen immer zum Zählen // bedingte Schleifen (while / do..while), wenn die Anzahl der Durchläufe vorher unbekannt ist //Fazit: sinnvollste Variante oben ist: do...while (außer, wenn man beim ersten Mal einen // anderen Text haben möchte -> man will ... also doch eher ... while(..) ... //cout << "Gib bitte noch einen Tag Monat und Jahr ein: "; //cin >> tagB >> monatB >> jahrB; //if (datumIstGueltig(tag,monat,jahr)) //{ // ausgabeDatumIstGueltig(); //} //else //{ // ausgabeDatumIstNichtGueltig(); //} //cout << "Tage seit dem " << tag << "." << monat << "." << jahr // << " = " << anzahlDerTageSeitJahresanfang(tag,monat,jahr) << endl; //cout << "Tage zwischen dem " << tag << "." << monat << "." << jahr // << " und dem " << tagB << "." << monatB << "." << jahrB << " sind " // << anzahlDerTageZwischenAundB(tag,monat,jahr,tagB,monatB,jahrB) << endl; // cout << "Der " << tag << "." << monat << "." << jahr << " ist ein "; // ausgabeWochentag(wochentagAmDatum(tag,monat,jahr)); // cout << endl; int zahl; cout << "Gib eine Zahl ein: "; cin >> zahl; // unten geht's weiter // do // { // cout << "Die vorherige Stelle ist eine " << zahl%2 << endl; // zahl = zahl / 2; // der evtl. auftretende Nachkommaanteil entfällt automatisch, // // bei Ganzzahldivision wird in C/C++ IMMER abgerundet // } while (zahl>=1); // while (zahl>=1) // { // cout << "Die vorherige Stelle ist eine " << zahl%2 << endl; // zahl = zahl / 2; // } // Fazit bis hierhin: beides tut, welche Variante ist richtig? // Dies führt uns auf die Frage: was sind hier sinnvolle Testfälle // -> 42 // -> 64 // -> 63 // -> 0 // Fazit: do .. while ist richtig, das stellt man entweder fest durch vorausschauende Planung // oder durch Eingebung // oder Talent // oder durch Erfahrung // oder durch Testen // Aufgabe (Einführung von Arrays) // Idee: speichere die Ziffern zunächst alle ab und gebe diese dann in umgekehrter Reihenfolge aus# // es wird eine Struktur benötigt, die mehrere Ziffern abspeichern kann! int zahlen[10]; // so etwas deklariert ein Array Zahlen, das aus 10 int-Variablen besteht // der Zugriff geschieht durch zahlen[], wobei Index zwischen 0 und 9 liegt int index = 0; // Index zeigt jeweils auf das als nächstes zu füllende Element im Array do { zahlen[index] = zahl%2; index = index +1; zahl = zahl / 2; // der evtl. auftretende Nachkommaanteil entfällt automatisch, // bei Ganzzahldivision wird in C/C++ IMMER abgerundet } while (zahl>0); // an dieser Stelle ist nun das Array (zu deutsch: Feld) von Index 0 bis (index-1) gefüllt // diese Ziffern sollen nun in umgekehrter Reihenfolge wieder ausgegeben werden // welche Schleifenart? und warum? for, weil die Anzahl der Durchläufe jetzt bekannt ist int i; for (i = index-1; i>=0 ; i = i-1) { cout << "Die naechste Ziffer ist die " << zahlen[i] << endl; } return 0; }