/*************************************************************************** main.c - description ------------------- begin : Mon Mai 28 18:35:13 CEST 2001 copyright : (C) 2001 by Sebastian Roth email : sebbi@claranet.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*************************************************************************** * Corrections and advices by Konrad Rosenbaum * ***************************************************************************/ /*KR: Hinweis 1: Fragen weisen nicht immer auf Fehler hin, sondern oft auch auf Stellen, über die man einfach nachdenken sollte.*/ /*KR: warum denn config.h? Willst Du das Teil später via autoconf anpassen?*/ #ifdef HAVE_CONFIG_H #include #endif #include #include /*KR: warum static?*/ //static int eingabe; /*KR: ^^^^^^ das macht sich lokal besser als global! Grund: die Funktionen können sich dann nicht gegenseitig die Variablen verhunzen.*/ //static float v,s,t; /*KR: das gilt auch für diese. Noch ein Grund: wenn sie lokal sind wird der Speicher nur solange belegt, wie nötig. Das mag bei Größenordnungen von 16Byte (wie hier) noch lächerlich erscheinen, aber bei einigen hundert Funktionen mit ihrerseits dutzenden von Variablen, die teilweise im kilobyte-Bereich liegen fällt das schon ins Gewicht.*/ /*KR: Funktionen, die schon genutzt aber erst später definiert (=implementiert=ausprogrammiert) werden, sollten schonmal vorher deklariert (=bekanntgegeben) werden. Man nennt das Forward-Deklaration. Und genau das tun übrigens auch die meisten Header-Dateien, wie stdio.h*/ void physicmain();/*KR: Unterschied: statt {...} kommt ein Semikolon ; */ void geschwzeitausw(); void wegzeitgleich(); void wegzeitngleich(); void main2(); int main(int argc, char *argv[]) { /*KR: der viele printf und switch-Code muss wirklich nur 1x existieren, also lagern wir ihn in eine Funktion aus (main2).*/ /*KR: Hauptschleife (sowas haben alle Ereignisorientierten Programme - Du bist in bester Gesellschaft.*/ for(;;)main2(); /*KR: Du kommst jetzt in den Genuß meiner Endlosschleifen-sammlung. Besser lesbar wäre sicherlich die gekommen: while(1) main2(); noch besser: while(1){ main2(); } andererseits ginge auch das: do{ main2(); }while(1); Oder etwas esotherischer: int i; for(i=1;i==1;i=1){ main2(); } was i auf 1 initialisiert, es auf 1 prüft und es wieder und wieder auf 1 setzt. Etwas redundant, also lassen wir das zweite setzen weg. Und die {} auch. ;-) int i; for(i=1;i==1;) main2(); wozu eigentlich i auf 1 prüfen? das Ergebnis des Ausdrucks ist schließlich wieder 1! int i; for(i=1;1;) main2(); wozu noch i definieren und setzen? for(;1;) main2(); also eigentlich sollte er wissen, was ich will!! for(;;) main2(); quod erat demonstrantum! */ }/*Ende der Hauptfunktion*/ void main2(void) { int eingabe;/*KR: was sach' ich? Ist besser! ;-) */ /*KR: netter Sprachmix. Entscheide Dich bitte für eine Sprache. ;-) */ printf("Willkommen bei Physics for Linux!\n\n"); printf("Hauptmenü:\n"); printf("Eine physikalische Gleichung errechnen --> 1\n"); printf("Hilfe --> 2\n"); printf("Beenden --> 3\n"); /*Jetzt muss der User auswählen*/ printf("Auswahl: "); scanf("%i",&eingabe); switch(eingabe) { /*KR: es ist i.A. übersichtlicher, wenn die öffnende { hinter oder unter switch steht und der ":" hinter dem case xy und das darunter eingerückt wird....*/ /*KR: WICHTIG: bitte bitte lies Dir die Torvalds-Styles durch: /usr/src/linux/Documentation/CodingStyle */ case 1: printf("Jetzt geht zur Physik!"); physicmain(); break; case 2: printf("Noch nicht fertig"); break; case 3: printf("cu...\n"); /*KR: bitte auch bei Funktionsnamen für exakt eine (1) Sprache entscheiden - möglichst die selbe, wie in den Strings.*/ //beenden(); /*KR: beenden ist recht kurz, also kann man es auch gleich von hier aus ausführen*/ exit(EXIT_SUCCESS); break; default: printf("Bitte eine Zahl auswählen!\n"); /*KR: ohne extra Aufruf kehrt es zu main() zurück das geht in eine Schleife, die wieder main2 aufruft ------ das spart uns eine Menge Stack! Der Aufruf von main2 an dieser Stelle bringt Dich in eine Endlosschleife, die jedesmal Speicher verbraucht, bis Du beendest.*/ //main2(); break; }/*Switch beenden*/ }/*Ende der Neben-Hauptfunktion*/ /*KR: wird nicht mehr gebraucht, siehe main2 void beenden(void) // Zuletzt editiert am 29.05.01 { exit(EXIT_SUCCESS); }/+*Programm beenden*/ void physicmain(void) // Zuletzt editiert am 30.05.01 { int end=0;/*KR: unterscheidet zwischen Ende und Schleife*/ int eingabe; do{ /*Da Rekursion (=Selbstaufruf) immer Ressourcen verbraucht ist eine Iteration (=Schleife) immer vorzuziehen, wenn der Code dadurch nicht übermäßig schwieriger wird. Erst recht, wenn er (wie hier) übersichtlicher wird.*/ printf("\nMit welcher Gleichung, welchem Gesetz soll gerechnet werden?\n"); printf("Weg-Zeit Gesetz --> 1\n"); printf("Beenden... --> 2\n"); printf("Auswahl: "); scanf("%i",&eingabe); switch(eingabe) { case 1: geschwzeitausw(); break; case 2: /*KR: die selbe Kritik, wie in main2: ein einfaches beenden bringt uns in die Schleife zurück... ...versuch Dir mal zu überlegen, was passiert, wenn...*/ //main2(); end=1; break; default: printf("\nBitte eine gültige Zahl eingeben!\n"); /*die Schleife geht weiter*/ break; } }while(!end);/*KR: mach weiter, bis der Nutzer beenden will*/ /*KR: Hinweis "!end" heißt "not end" also ergibt dieser Ausdruck 1 (wahr, true), wenn end gleich false (in C: 0); ist end irgendwas ungleich 0 (< oder > 0) dann ergibt der Ausdruck 0 (false)*/ } void geschwzeitausw(void) { int eingabe; printf("Gleichförmig --> 1\n"); printf("Ungleichförmig --> 2\n"); printf("Auswahl: "); scanf("%i",&eingabe); switch(eingabe) { case 1: wegzeitgleich(); break; case 2: wegzeitngleich(); break; default: printf("Bitte gültige Zahl eingeben"); break; } } void wegzeitgleich(void) { /*KR: Insider Tipp: Einzel-chars machen sich mit scanf echt blöd. Also: String einlesen (a'ka ganze Zeile) und dann nur den ersten Character nehmen. Noch so ein Tipp: ein Array kann auch wie ein Pointer behandelt werden (und umgekehrt) die Ausdrücke x[0] und *x sind also immer identisch.*/ /*KR: mehr als 100 wird er wohl net tippen, auch wenn diese Schätzung noch riskant ist...*/ char gvar[100]; float s,v,t; printf("Grundgleichung: s=v*t\n"); printf("Bitte die gesuchte Variable eingeben:"); scanf("%s",gvar);/*KR: Strings ohne & übergeben, sie sind schon pointer*/ switch(*gvar)/*KR: das erste Element nehmen*/ { case 's': printf("Gesucht ist > s <\n"); printf("Bitte einen Wert für v (in m/s) eingeben: "); scanf("%f",&v); printf("Bitte einen Wert für t (in s) eingeben: "); scanf("%f",&t); s = v * t; printf("Geschwindigkeit: %f m/s\n",v); printf("Zeit: %f s\n",t); printf("Weg: %f m\n",s); /*KR: wie "böse", wir kommen bei Rücksprung doch sowieso dorthin zurück!*/ //physicmain(); break; default: /*KR: man sollte immer Fehler und Fehleingaben behandeln*/ printf("Sorry, andere Werte als 's' sind noch nicht implementiert.\n"); break;/*KR: break sollte man auch immer machen, Fehler passieren zu schnell!*/ } } void wegzeitngleich(void) { }