Hi (nochmal) Ulf,
Verallgemeinere das doch mal. nehmen wir an, wir haben n Funktionen... :) Im Ernst, stell dir vor, du hast z.B. 3 Funktionen a(), b() und c(). a ruft b auf, b ruft c auf und c wieder a. Damit sprengst du nach kurzer Zeit jeden Speicher. So etwas passiert jetzt dauernd in deinem Programm.
*schluck* So kann also aus einem kleinen Programm ein Speicherfresser werden... wie fürchterlich.
Iiiihhhh, eine IDE :). Versuch's mal auf die ganz grausame Art mit Editor und Kommandozeile. Ist am Anfag zwar abschreckender, aber wenn du das kannst, weißt du wenigstens, was deine IDE macht und bist nicht so ein <F9>-Drücker :).
Ok, ich steige um. KDevelop war ja sowieso nur in Englisch (was ich nicht verstehe!)
Da das ein hingekleckstes Trivialprogramm ist, mag das mit den globalen Variablen noch gehen, aber gwöhn dir das für halbwegs ernsthaftes Programmieren unbedingt ab. Es kommen sonst noch andere probleme ala Überschatten von variablen dazu.
ok
S: Ja, das verstehe ich. Die zweite main hatte ich deswegen genommen, weil S: der User, wenn er zurück ins Hauptmenü will, nicht erst wieder den S: Begrüßungstext sehen soll. Das hat mich genervt, wusste aber nicht, wie S: man es sonst anders machen könnte.
Dafür nimmst du eine Variable, die nur beim ertsen Durchlauf der Schleife einen bestimmten Wert hat.
int myflag = 1; for (...) { ... if (myflag) zeigeBegruessungstext(); myflag=0; ... }
ok auch hier. Ich wusste garnicht, was es für nette Anwendungen gibt für Schleifen.
S: Ja da hast du schon wieder Recht. Also werde ich mich für tatatataa S: Deutsch entscheiden :-)
Du darfst aber keine Umlaute benutzen, also nimm lieber Englisch :). Das hat den Vorteil, daß du später keine Probleme beim Umstellen bekommst, wenn du mal mit nicht-Deutschen programmierst (geht ziemlich schnell :))
Ok, aber da kann ich nicht für grammatische Richtigkeit garantieren :-))
S: *insbuchguckundbegriffstacksuch* Ist mit Stack ein Teil des Speichers S: gemeint? Sorry, Beschreibung kenn ich nicht
Stack ist ein LIFO (Last In First Out) Speicher. Der Prozessor kann Werte mittels push und pop auf den Stack legen/vom Stack einlesen. Wenn du eine Funktion aufrufst, wird immer ein bißchen Stack verbraucht, nämlich für Parameter, Rücksprungaddresse, lokale Variablen etc. Ein sinnloser Funktionsaufruf verbraucht also immer Speicher. Mit gedankenlos eingesetzten rekursiven Aufrufen kannst du auch ganz hinterhältig dein System abschießen. Es wird immer mehr Stack belegt, bis einfach kein Speicher mehr da ist. Pech für die anderen Proggies.
Ok, das habe ich verstanden. BTW: ich sollte das C-Buch dringend weiterlesen (Kapitel 30-Rekursion)
Also (irgendwann hatte ich das schonmal jemandem erklärt), wenn du nicht einen einzelnen char in deinen Speicher packst, sondern einen Array, so liegen die einzelnen Elemente linear hintereinander im Speicher. Wenn also z.B. vector ein Array von float ist, so liegen die einzelnen Elemente (d.h. die einzelnen floats) hintereinander im Speicher. Auf sie kann man dann mit dem []-Operator zugreifen. Liegt also z.B. vector[0] auf der Adresse 5, so ist vector[3] auf Addresse 8 zu finden. Eine Besonderheit von C ist nun, daß der Arrayname immer ein Zeiger auf den Datentyp darstellt. Wieder das Vectorbeispiel: Nach einer Deklaration, z.B. "float vector[10]", ist "vector" (ohne eine eckige Klammer) immer der konstante Zeiger auf das erste Element des Arrays, d.h. die folgenden Codezeilen sind äquivalent:
vector[0]=5.7; *vector=5.7;
vector[1]=1.7; *(vector+1)=1.7; //ungetestet, aber es müßte klappen
Laß von Speicherarithmetik aber lieber erst mal die Finger, bis du damit vertraut bist.
Das werde ich lieber tun. Das ist doch schon ein wenig kompliziert.
Jetzt mal was längeres zur Erklärung. Um auf den Stack zurückzukommen, ist bei i386-kompatiblem CPUs der Stack immer so ausgelegt, daß er VON OBEN NACH UNTEN gefüllt wird, d.h. wenn ich ein "push ax; push bx; push cx" (ax, bx, cx sind Register, für den Anfang also beliebige Werte), so sieht der Stack so aus (links sind niedrigere Speicherbereiche)
cx bx ax
Wenn eine Funktion aufgebaut wird, wird ein sogenannter stack frame aufgebaut, d.h. der Stack wird so gefüllt, daß die Funktion ein abgeschlossenes Stückchen Stack bekommt, aus dem sie nie herausmuß, d.h. angenommen a() ruft b() auf, sieht der Stack in etwa aus:
stack frame von b() | stack frame von a()
Alles was b jemals braucht, befindet sich in seinem Stackbereich. Ein einzelner stack frame sieht jetzt rudimentär etwa so aus
lokale Variablen| Sonstiges | Rücksprungadresse
Irgendwo in deinen lokalen Variablen steht jetzt der Puffer gvar. Was macht jetzt scanf? Es schreibt solange in gvar, bis ein newline kommt. Läuft wunderbar, solange der Benutzer bei <100 Zeichen bleibt. Was passiert aber jetzt, wenn der Benutzer mehr als 100 Zeichen eingibt? Dann wird der gesamte Stackbereich hinter gvar überschrieben (für den Prozessor ist dein Array lediglich ein großer Byteblock, also ist ihm das egal wenn er groß den Stack übermalt). Irgendwo steht dann die Rücksprungadresse. Jetzt stell dir einen ganz bösen Benutzer vor. Der nimmt dein programm im Debugger auseinander, stellt fest, wo die Rücksprungadresse liegt, überschreibt dann bei der Eingabe den stack frame so, daß die Funktion auf jeden Fall zurückkehrt, schreibt hinter die Rücksprungaddresse ein bißchen eigenen Code und überpinselt die Rücksprungaddresse, so daß sie auf seinen eigenen Code im Stack zeigt. Das Ganze nennt man dann buffer overflow oder auch stack smashing. Und so werden dann Server gehackt :).
Tatsache? wow! Server knacken hatte ich mir anders vorgestellt. Aber wenn ich ehrlich bin ist das (sorry) sehr kompliziert, zumindest aus meinen Augen. Trotzdem ist das , was ich noch verstanden habe, sehr lehrreich. Danke für die Erklärung.
Solange dein Programm keine besonderen Privilegien hat, ist das nur halb so wild, aber wenn es sich um ein root-Proggie handelt...
...kann es sehr böse ausgehen, klar.
Vorm Compiler läuft noch der Präcompiler (gpp). Seine Aufgabe ist es u.a. Kommentare zu entfernen und Makros zu expandieren. Dann erst wird die Datei an den Compiler weitergereicht.
Gut, dann kann ich die Kommentare also drinlassen, wie schön!
cu, Ulf
Danke und Bye, Sebastian