Hallo Konrad,
Es gibt auch indirekte Rekursion: a() ruft b() auf und b() ruft ihrerseits a() auf. Das kann man auch noch komplizierter über x Ebenen und y Verzweigungen machen, aber entscheidend ist, dass irgendwann eine Funktion aufgerufen wird, die schon läuft, was immer die Gefahr birgt, dass es in einer Endlosschleife endet und damit den Speicher aufbraucht.
kapiert
Hmm, am besten Du benutzt KDevelop nur zum editieren der C-Dateien (falls das geht) und erstellst Dir alles andere selbst. Zu viel Automagie verhindert sehr effektiv das Begreifen.
Wie schon als Antwort auf die Mail von Ulf gesagt: ich werde mich bessern
Noch ein Grund: je weniger Du global definierst, umso weniger kann Dir durcheinander geraten und umso unwahrscheinlicher ist es, dass Du in zwei Dateien die selbe Variable definierst (wird so ab 10000 Zeilen akut).
Merke: bei jeder globalen Variable nachdenken, ob es wirklich nötig ist.
ok, bin überzeugt.
Einfach: gib den Begrüßungstext _vor_ der Hauptschleife aus und lass ihn in main2() weg.
Da hatte ich wieder nich weiter gedacht. Na klar! Manchmal liegt das einfachste am nächsten...
Ich meinte den Rechner ;-)
oh!
C hat da ein Gedanken-Lese-Feature (zumindest, wenn man den richtigen Gedanken hat) ;-)
*leichtgrins*
/*KR: WICHTIG: bitte bitte lies Dir die Torvalds-Styles durch: /usr/src/linux/Documentation/CodingStyle */
S: *gefunden* *zumlesenvorgemerkt*
Bitte bald. ;-)
habe es augedruckt. Liegt jetzt neben Monitor und ist meine neue Abendlektüre :-)
Stack, def.: [Vorsicht: langsam und mehrfach lesen, am besten ausprobieren]
Stapelspeicher. Der Stack funktioniert mit Werten genauso, wie ein Stapel Papier mit Blättern: Du kannst oben drauflegen und auch oben wieder wegnehmen (weil alles andere durcheinander bringt ist es bei Computern einfach nicht erlaubt). Wenn Du eine Funktion aufrufst werden die Parameter und die Rücksprungadresse (die Position wohin es zurückgeht, wenn Du die Funktion verläßt) auf den Stack gelegt, dann wird die Funktion aufgerufen, sie legt ihrerseits alle lokalen Variablen drauf und arbeitet damit. Wird von dort eine weitere Funktion aufgerufen wird wieder all das draufgelegt (deswegen verschwenden Rekursionen Speicher). Verläßt Du die Funktion werden erst die lokalen Variablen weggeworfen, der Return-Wert (siehe Stichwort return) draufgelegt und zu der Rücksprungadresse gesprungen, ab da übernimmt wieder die übergeordnete Funktion, wirft die Parameter weg und übernimmt den Rückgabewert (oder verwirft ihn, je nach dem, ob er gebraucht wird). /*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.*/
Ich hoffe, das habe ich kapiert.
S: Erklär mir bitte das x[0] nochmal! Mir Zeigern und Vektoren komme ich S: bis jetzt noch net so recht aus. das *x ein Zeiger auf x ist, verstehe S: ich.
Ok, definieren wir mal ein Array:
char bsp[10];
bsp ist 10 char's gross. Ganz nebenbei bekommst Du 11 offensichtliche und legal anwendbare Ausdrücke:
bsp -> ein Zeiger auf das erste Element bsp[0] -> das erste Element .... bsp[9] -> das 10. Element
Ok, das finde ich noch recht leicht zu verstehen.
Notiz am Rande: bsp[99] wird nicht vom Compiler angemeckert, führt meistens aber zu sehr seltsamem Verhalten, da es eine Speicherstelle weit ausserhalb von bsp bezeichnet (90 Byte weiter oben).
jetzt einen Pointer: char *ptr;
Wir wissen, dass bsp ein Pointer auf ein char-Array ist, also ist das hier legal:
ptr=bsp;
damit zeigt ptr ebenso wie bsp auf das erste Element des Arrays bsp. Im Gegensatz zu bsp kannst Du ptr aber auch woanders hinzeigen lassen.
Um den Speicherinhalt der Variable zu nutzen, die hinter einem Pointer steht benutzt man *. Also:
*ptr='a';
weist dem Speicher hinter ptr, also dem ersten Element von bsp, ein 'a' zu. Sprich bsp[0]=='a'.
Da ptr und bsp sowieso auf den selben Speicher zeigen können wir sie also auch gleich behandeln:
*bsp ist identisch zu bsp[0], also sind diese Anweisungen:
*bsp='b'; bsp[0]='b';
absolut identisch. Das selbe gilt für ptr:
*ptr='c'; ptr[0]='c';
Das geht noch weiter:
bsp[4]='d'; ptr[4]='d';
tun (bei uns, da ptr==bsp) exakt das selbe.
Zeiger sind letztendlich nichts weiter als Zahlen, die irgendeine Stelle im Speicher bezeichnen, also kann man in C auch damit rechnen.
*(bsp+2) ist identisch zu bsp[2] und bsp+2 ist identisch zu &(bsp[2]) (& ergibt die Adresse der Variable dahinter)
Da man Pointer (im Gegensatz zu Array-Namen) auch verändern kann, kann man ihnen auch das Ergebnis dieser Pointer-Arithmetik zuweisen:
ptr=bsp+2;
Ab jetzt ist *ptr identisch zu bsp[2] ....
Oder man zählt sie schrittweise durch die Elemente durch: ptr++ - läßt ptr exakt ein Element weiter hoch zeigen (bei uns jetzt bsp[3]).
usw.....
Erfahrungsgemäß verbraucht man viele Tage mit Programmabstürzen, bis sich einem diese Logik vollkommen erschließt, also verzweifel nicht gleich ;-)
Ok, ich werde es allerdings trotzdem versuchen zu verstehen. Wir haben ja jetzt Pfingsten.
S: Wieso sollte er? Jemand, der das Prog richtig nutzen will, wird schon S: nicht so einen Käse machen oder was denkst du?
Normal würde er wohl net. Aber wichtig ist das, wenn Dein Programm irgendwas im System macht (auch wenn nur die Chance besteht, dass es von einem Skript aus aufgerufen wird, dass für einen Nutzer etwas mit root-Rechten macht), weil dann kann man mit gezielten Überläufen den Rücksprungpointer überschreiben und eigenen (bösen) Code ausführen, der wer weis was mit Deinem System macht.
Kann denn ein C-Programm am System etwas verändern? Im Buch steht etwas über die Arbeit mit Textdateien, aber nix über Systembefehle oder so... Das diese Sachen eine Sicherheitslücke darstellen, finde ich erschreckend.
S: *an alle* Sorry, wenn der Quelltext tödlich für einige zu lesen ist. Bin S: C-Anfänger
Deswegen die Gänsefüßchen "".... ;-) Ich war auch mal Anfänger.
Es ist trotzdem nett (von allen), wenn mir hier geholfen wird.
Kommentare werden nicht einkompiliert. Sie verschwinden schon nach dem ersten von 4 Schritten (Präprozessor, Compiler, Assembler, Linker).
Wie schon im Antwort auf Mail von Ulf: Ich lasse ie Kommentare also drin.
Konrad (der jetzt aber wirklich ins Bett geht)
Bye, Sebastian, der jetzt noch etwas rumprobiert.