Frage zu Ende von For-Schleifen
-
Hallo zusammen, ich hoffe, dass ist jetzt keine allzu blöde Frage!
Ich versuche mir gerade C beizubringen mit dem Buch "Programming in C" von Stephen Kochan.
http://www.amazon.de/Programming-C-Stephen-Kochan/dp/8131713512/ref=sr_1_2?s=books&ie=UTF8&qid=1376130127&sr=1-2Hier ist ein Programm, welches die Primzahlen bis 50 ermittelt:
// Program to generate a table of prime numbers #include <stdio.h> int main (void) { int p, d; int isPrime;//Im Buch stand _Bool, ging bei mir aber net! for ( p = 2; p <= 50; ++p ) { isPrime = 1; for ( d = 2; d < p; ++d ) if ( p % d == 0 ) isPrime = 0; if ( isPrime != 0 ) printf ("%i ", p); } printf ("\n"); return 0; }
So wie es da steht, sah es für mich so aus, als wäre if( isPrime!= 0 ) noch Teil der inneren SChleife, was mich etwas verwirrt hatte.
Dann habe ich mal hinter dem inneren For und nach dem isPrime = 0; geschweifte Klammern gesetzt und siehe da, das Programm bringt immer noch das gleiche Ergebnis.Also scheint das innere For nach isPrime = 0; zu Ende zu sein!?
Wie erkennt man normalerweise, nach welchem Programm statement eine For-Schleife zu Ende ist?
Für die Lesbarkeit wären meiner Meinung nach ja geschweifte Klammern für sowas gut, aber wie es ausschaut, geht es auch ohne, was die LEsbarkeit erschwert, jedenfalls für einen Anfänger wie mich!
-
Hallo,
ohne geschweifte Klammern (Block) gilt immer nur die nächste Anweisung als Teil der Schleife (for, while) bzw. dasselbe gilt auch für die if-Anweisung.
Daher sollte man grundsätzlich den Code so einrücken, daß dies auch ersichtlich wird, also
for ( p = 2; p <= 50; ++p ) { // <- ich mag lieber diesen Klammerungsstil ;-) isPrime = 1; for ( d = 2; d < p; ++d ) if ( p % d == 0 ) // <- Einrückung isPrime = 0; if ( isPrime != 0 ) printf ("%i ", p); }
(und die Leerzeile zeigt noch zusätzlich, daß die untere if-Abfrage erst nach der Schleife ausgeführt wird)
P.S: Den Code kann man noch algorithmisch verbessern, wenn man die Schleife gleich abbricht, wenn man erkennt, daß keine Primzahl vorliegt:
for ( d = 2; d < p; ++d ) if ( p % d == 0 ) { isPrime = 0; break; }
Nun müssen hier geschweifte Klammern hin, damit das break zur if-Anweisung gehört.
P.S. Man kann noch weitere Verbesserungen am Primzahl-Algorithmus durchführen, aber dies ist ja jetzt nicht Bestandteil dieses Threads.
-
Ah, super, ich danke dir!
Möglicherweise hat das der Autor erwähnt und ich habe es überlesen!
Zu seiner Rettung, er hatte auch ein Leerzeichen nach dem inneren If, daran hätte ich also auch erkennen müssen!Das mit dem Break ist genial und logisch, wenn man recht früh erkennt, daß eine Zahl restlos teilbar ist, braucht man net noch die nachfolgenden Zahlen zu testen, das macht Sinn!
Vielen Dank!
PS: Dein Klammerungsstil sagt mir intuitiv auch mehr zu, werde das übernehmen!
-
Ich glaube, ich habe noch eine Verbesserung für den Algorithmus gefunden,
wenn man nach dem ersten isprime = 1 noch prüft,
ob die derzeitige Zahl grösser als 2 und restlos durch zwei teilbar ist,
dann ist es keine Primzahl und man gleich mit continue weitermachen, oder?
-
Dann hast du schon alle geraden Zahlen erwischt und kannst in der inneren Schleife mit d=3 anfangen und mit d+=2 erhöhen.
-
Und es gibt noch weitere Verbesserungen:
- es reicht bis sqrt(p) zu überprüfenint max = (int)sqrt(p); for ( d = 3; d <= max; d += 2 )
- man kann sich die Eigenschaft 6k+1 sowie 6k-1 zunutze machen, s. http://de.wikipedia.org/wiki/Primzahl#Eigenschaften_von_Primzahlen
(d.h. in 6er-Schritten jeweils zwei Werte überprüfen => reduziert nochmals die Suche um 1/3)P.S: 2 und 3 müssen dann vorher explizit getestet werden