Pascalsches Dreieck im Programm ausgeben
-
xx_20 schrieb:
Sind meine 2 Schleifen nicht richtig? n und k laufen doch jeweils bis z, k bis 2*z oder nicht?
Nein. Denk noch einmal nach, welche Werte k für gegebenes n haben kann. Dann verstehst du auch den zweiten Absatz mit der Erklärung, wie du das Dreieck grafisch schön hinbekommst.
-
Ich komme einfach nicht drauf :S
Probiere alles mögliche aber es funktioniert nicht. Mein "Dreieck" sieht jedesmal nur noch schlimmer aus, wie logisch mir meine Schleifen auch zu sein scheinen
-
xx_20 schrieb:
Ich komme einfach nicht drauf :S
Probiere alles mögliche aber es funktioniert nicht. Mein "Dreieck" sieht jedesmal nur noch schlimmer aus, wie logisch mir meine Schleifen auch zu sein scheinenOch, mit so viel Hilfe immer noch nichts
.
Na, bevor du Pipi in die Augen bekommst:
#include <stdio.h> #include <stdlib.h> unsigned long long fak(unsigned n) { unsigned long long result = 1; unsigned i = 1; for (; i <=n; ++i) result *= i; return result; } unsigned binomial(unsigned n, unsigned k) { return fak(n)/(fak(k)*fak(n-k)); } int main () { unsigned max_n; puts("Maximales n (0-20)? "); if (scanf("%ud", &max_n) == 1) { unsigned zeichenbreite=7; // "Empirisch" bestimmte Werte if (max_n > 20) // Zahlen werden zu groß exit(1); else if (max_n > 19) zeichenbreite = 7; else if (max_n > 16) zeichenbreite = 6; else if (max_n > 13) zeichenbreite = 5; else if (max_n > 9) zeichenbreite = 4; else if (max_n > 5) zeichenbreite = 3; else zeichenbreite = 2; char formatstring[6]; sprintf(formatstring, "%%%uu ", zeichenbreite - 1); unsigned n, k; for(n = 0; n <= max_n; ++n) { // Whitespace vorne int num_whitespace = ((max_n)/2. - n/2.)*zeichenbreite; int i; for(i = 0; i < num_whitespace; ++i) putchar(' '); // Eigentliche Werte for(k = 0; k <= n; ++k) { printf(formatstring, binomial(n,k)); } putchar('\n'); } } return 0; }
Sieht nun wirklich sehr schön aus:
Maximales n (0-20)? 20 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1 1 10 45 120 210 252 210 120 45 10 1 1 11 55 165 330 462 462 330 165 55 11 1 1 12 66 220 495 792 924 792 495 220 66 12 1 1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1 1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1 1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1 1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1 1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1 1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 153 18 1 1 19 171 969 3876 11628 27132 50388 75582 92378 92378 75582 50388 27132 11628 3876 969 171 19 1 1 20 190 1140 4845 15504 38760 77520 125970 167960 184756 167960 125970 77520 38760 15504 4845 1140 190 20 1
Es ist zwar alles recht grundlegend, es könnte jedoch sein, dass dir niemand glaubt, dass du das alleine hinbekommen hast, weil eben sehr viele Grundlagen clever kombiniert werden, während du noch nicht einmal Schleifen mit Hilfe richtig hinbekommst.
edit: Da war noch ein Fehler für n=20. Ausgebessert.
-
Vielen Dank!
Das würde ich mir auch nicht glauben.
Aber ich habe erst seit einem Monat programmierung und finde diese Aufgabe schon viel zu krass für unseren "Wissensstand".Zum Beispiel steht bei dir sprintf, das sehe ich zum ersten mal. Kenne nur printf und scanf. Und dass du oben scanf gleich mit in der if-Bedingung hast, kann ich auch nicht verstehen, sowas sehe ich auch das erste mal und ich habe versucht das so auseinanderzunehmen:
scanf("%ud", &max_n);
if(max_n == 1)aber das wird dann falsch......ich komme irgendwie überhaupt nicht klar mit diesem Programm, verstehe zum Beispiel auch überhaupt nicht was die Zahlen für die "Zeichenbreite" sein sollen.
Und das Schlimme ist, das ich mit diesem "Zwischenergebnis" bei meinem Tutor war, bevor ich es hier reingepostet habe, und er mir gesagt hat, dass die Schleifen so richtig sind, und ich mir da als BEdingung nur noch was anderes überlegen muss, damit ich das Dreieck hinbekomme. Und für den Fall, dass ich das richtig hinbekomme hatte ich schon den Inhalt des Dreieck "programmiert", wo er auch meinte es sei richtig und wenn ich diese BEdingung richtig bestimme wäre mein Programm fertig
deshalb war ich echt verzweifelt und wusste nicht an wen ich mich wenden soll, zu ihm sollte ich glaube ich nicht mehr gehen.
Vielleicht sollte ich Nachhilfe nehmen
-
Du kannst den Kladderadatsch mit der Zeichenbreite auch weglassen:
#include <stdio.h> #include <stdlib.h> unsigned long long fak(unsigned n) { unsigned long long result = 1; unsigned i = 1; for (; i <=n; ++i) result *= i; return result; } unsigned binomial(unsigned n, unsigned k) { return fak(n)/(fak(k)*fak(n-k)); } int main () { unsigned max_n; puts("Maximales n (0-20)? "); if (scanf("%ud", &max_n) == 1) { if (max_n > 20) // Zahlen werden zu groß exit(1); const int zeichenbreite = 7; // Maximale Breite einer Zahl bei n=20 unsigned n, k; for(n = 0; n <= max_n; ++n) { // Whitespace vorne int num_whitespace = ((max_n)/2. - n/2.)*zeichenbreite; int i; for(i = 0; i < num_whitespace; ++i) putchar(' '); // Eigentliche Werte for(k = 0; k <= n; ++k) { printf("%7u ", binomial(n,k)); } putchar('\n'); } } return 0; }
Dann sieht es bei 4 eben nicht mehr so:
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
sondern so aus:
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
Nun verständlicher?
Im Programm oben waren übrigens noch ein paar Schönheitsfehler drin, an den Grenzen hätte es >= statt >= heißen müssen:
if (max_n > 20) // Zahlen werden zu groß exit(1); else if (max_n == 20) zeichenbreite = 7; else if (max_n >= 16) zeichenbreite = 6; else if (max_n >= 13) zeichenbreite = 5; else if (max_n >= 9) zeichenbreite = 4; else if (max_n >= 5) zeichenbreite = 3; else zeichenbreite = 2;
-
Hmmm mit überlegen verstehe ich einiges vielleicht doch. ZUm Beispiel kannte ich auch result = i noch nicht bin jetzt aber drauf gekommen, das das result= resulti heißen muss.
Und Zeichenbreite ich glaube ich die Anzahl der Spalten, die freigehalten werdens ollen für die Zahlen im DReieck, da die Zahlen größer werden, je größer max_n ist, muss die Zeichenbreite größer werden damit es noch ein Dreieck bleibt...oder?
Ich verstehe dann aber diese Zeile überhaupt nichtchar formatstring[6];
sprintf(formatstring, "%%%uu ", zeichenbreite - 1);Ich glaube jetzt verstehe ich fast alles bis auf diese 2 Zeilen....und die Zeile wo im printf befehl nochmal formatstring vorne steht, aber das müsste auch an disen zwei zeilen liegen, was heißt denn hier formatstring[6]
wäre echt seeeeehr nett wenn du mir diese zwei zeilen noch erklären könntest.
Und nochmal tauuuusend DaNK!
-
scanf() gibt die Anzahl der gelesenen Werte zurück.
Man kann mit scanf auch mehrere verschiedene Daten einlesen.Nachzulesen z.B hier: http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
Die Seite kannst du dir gleich merken, da dort auch die anderen Funktionen der C-Standardlibrary erklärt werden.
Das ist eigentlich für C++, die Besonderheiten bei C werden aber erklärt.
-
Ach du hattest in zwischen schon geantwortet,
DANKESEHR!!!
-
xx_20 schrieb:
. Und dass du oben scanf gleich mit in der if-Bedingung hast, kann ich auch nicht verstehen, sowas sehe ich auch das erste mal und ich habe versucht das so auseinanderzunehmen:
scanf("%ud", &max_n);
if(max_n == 1)Das hast du auch völlig falsch interpretiert. Guck dir scanf an:
http://www.cplusplus.com/reference/clibrary/cstdio/scanf/Return Value
On success, the function returns the number of items successfully read. This count can match the expected number of readings or fewer, even zero, if a matching failure happens.
In the case of an input failure before any data could be successfully read, EOF is returned.Es wird also geprüft, ob der eingegebene Wert überhaupt eine Zahl war. Nix mit dem Wert von max_n. Warum sollte ich den Wert von max_n überhaupt auf Gleichheit mit 1 prüfen?
ich komme irgendwie überhaupt nicht klar mit diesem Programm, verstehe zum Beispiel auch überhaupt nicht was die Zahlen für die "Zeichenbreite" sein sollen.
Bei größeren max_n werden die Zahlen unten im Dreieck immer länger. Damit das Dreieck noch Dreieckig bleibt, muss man entsprechend mehr Füllzeichen einfügen. Die Grenzen 5,9,13,16,19 habe ich durch ausprobieren bestimmt. Vergleiche die Ausgaben meiner vereinfachten Version und der Version mit der variablen Zeichenbreite. Sieht doch viel besser aus mit variabler Zeichenbreite.
Und das Schlimme ist, das ich mit diesem "Zwischenergebnis" bei meinem Tutor war, bevor ich es hier reingepostet habe, und er mir gesagt hat, dass die Schleifen so richtig sind, und ich mir da als BEdingung nur noch was anderes überlegen muss, damit ich das Dreieck hinbekomme. Und für den Fall, dass ich das richtig hinbekomme hatte ich schon den Inhalt des Dreieck "programmiert", wo er auch meinte es sei richtig und wenn ich diese BEdingung richtig bestimme wäre mein Programm fertig
Nun, kommt erst einmal drauf an, ob dein Tutor überhaupt Ahnung hat. Wie genau hast du deine Schleifen denn gemacht? Es sollte auf jeden Fall der "Trick" auftauchen, k von 0 bis n laufen zu lassen. Sonst hast du keine Chance, auf das Dreieck zu kommen. Oder du bekommst ein Dreieck dieser Form:
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
Das geht auch mit vereinfachter Bedingung:
#include <stdio.h> #include <stdlib.h> unsigned long long fak(unsigned n) { unsigned long long result = 1; unsigned i = 1; for (; i <=n; ++i) result *= i; return result; } unsigned binomial(unsigned n, unsigned k) { if (k>n) return 0; // ACHTUNG: Hier auch geändert! return fak(n)/(fak(k)*fak(n-k)); } int main () { unsigned max_n; puts("Maximales n (0-20)? "); if (scanf("%ud", &max_n) == 1) { if (max_n > 20) // Zahlen werden zu groß exit(1); unsigned n, k; for(n = 0; n <= max_n; ++n) { for(k = 0; k <= max_n; ++k) // Dann muss man hier nicht denken { unsigned wert = binomial(n,k); if (wert > 0) printf("%7u ", wert); } putchar('\n'); } } return 0; }
Wenn es ein schönes Dreieck werden soll, dann findest du die Erklärung in meinem Beitrag ganz oben und die konkrete Umsetzung als Code dieser Bedingungen hast du auch gezeigt bekommen.
-
sprintf(formatstring, "%%%uu ", zeichenbreite - 1);
Da steht erstmal %% . Das schreibt ein % in den Formatstring.
Das %u danach schreibt den entsprechenden Paramter als vorzeichenlose Dezimalzahl in den Formatstring. Ist zeichenbreit z.B. 4 dann wird in formatstring eine 3 geschrieben.
Das u und das Leerzeichen werden übernommen.
Also steht in Formatstring ein "%3u ".
Damit wird dann das printf "gefüttert".Für solche Fälle gibt es aber den * im Formatstring.
printf("%*u ", zeichenbreite - 1, binomial(n,k));
-
xx_20 schrieb:
Ich verstehe dann aber diese Zeile überhaupt nicht
char formatstring[6];
sprintf(formatstring, "%%%uu ", zeichenbreite - 1);Ich glaube jetzt verstehe ich fast alles bis auf diese 2 Zeilen....und die Zeile wo im printf befehl nochmal formatstring vorne steht,
Dann schauen wir nochmal in das vereinfachte Beispiel:
printf("%7u ", binomial(n,k));
Da gibt die 7 (wie du in einer printf-Referenz nachlesen kannst) die Zahl der Zeichen an, auf die die Ausgabe aufgefüllt werden soll. Das mache ich, wie du richtig erkannt hast, weil die Zahlen unten breiter werden, die Ausgabe der Zahlen oben aber genau so breit sein muss wie unten, damit das Dreieck schön wird.
So, nun ist diese breite aber eine Variable. ich will also bei max_n = 20 da
"%7u " stehen haben und bei max_n=4 will ich "%2u " als Formatstring. Ich kann aber natürlich nichtprintf("%"zeichenbreite"u ", binomial(n,k));
schreiben. Das ist Unsinn, so funktioniert das nicht. Also muss ich mir einen Formatstring basteln. Der Formatstring von printf muss nicht etwas sein, dass man beim Programmieren fest einbaut, das kann irgendeine Zeichenkette (d.h. in C ein Array von chars) sein, zum Beispiel mein char formatstring[6]. Den muss ich nun noch mit dem passenden Inhalt füllen. sprintf ist wie printf, aber anstatt auf die Standardausgabe schreibt es in eine Zeichenkette, hier den Formatstring. Ansonsten ist alles genau gleich wie bei printf. Nun will ich also die oben genannten Zeichenketten in den Formatstring schreiben. Doch Ohweh! Wie gibt man mit printf ein Prozentzeichen aus? Wieder in die Referenz geguckt: Ach, mit %%. Somit können wir den Befehl auseinandernehmen:
sprintf(formatstring, "%%%uu ", zeichenbreite - 1);
Da steht:
Schreibe an die Stelle von formatstring folgedes: Ein Prozenzeichen, dann eine vorzeichenlose Zahl, dann ein Leerzeichen. Und dann noch die Angabe, dass die vorzeichenlose Zahl den Wert zeichenbreite-1 haben soll. Und somit hat formatstring hinterher den Inhalt den ich möchte und ich kann dies als Formatstring für das printf benutzen.
-
DirkB schrieb:
Für solche Fälle gibt es aber den * im Formatstring.
printf("%*u ", zeichenbreite - 1, binomial(n,k));
:p Ich sollte mir meinen Rat zu Herzen nehmen und selber öfters in die Referenz gucken. Das ist so natürlich viel einfacher. Hatte mich schon gewundert, dass dies so kompliziert sein sollte in C.
-
Im K&R gabs das auch noch nicht
@xx_20
K&R bezeichnet das Ur-C, das in dem Buch "The C Programming Language" (deutsch: Programmieren in C) von Kernighan und Ritchie beschrieben wird.
-
DirkB schrieb:
@xx_20
K&R bezeichnet das Ur-C, das in dem Buch "The C Programming Language" (deutsch: Programmieren in C) von Kernighan und Ritchie beschrieben wird.Übrigens das Lehrbuch für C überhaupt. Zumindest in der englischen Originalausgabe die ich kenne, die deutsche Übersetzung ist angeblich nicht so gelungen. Aber zum Programmieren muss man sowieso Englisch fließend lesen können. solltest du dir vielleicht mal besorgen, wenn du Hilfe brauchst.
-
Ihr könnt euch nicht vorstellen, wie glücklich ihr mich gemacht hab. Ich danke euch seeeehrvom HErzen!!!!!!!!!!!!!!
Und jetzt verstehe ich sogar alles in dem Programm!