Datum:
Hey! ich spiele gerade etwas mit Struct's herum und habe nun versucht ein Array von structs zu erstellen. So siehts aus:
struct etest { int err_id; int err_no; char err_name; }; void main() { struct etest *errstack[3]; errstack[1]->err_id = 0x55; // ein element testweise beschreiben. printf("id: %x\n",errstack[1]->err_id); |
Mit dem Array index 1 wie im beispiel funktioniert das, nutze ich allerdings einen Index mit wert 0 läuft der compiler zwar ohne Fehler oder Warning durch, aber das Programm zeigt nur "Segmentation fault". Woran kann dies liegen? Idee? Ich nutze einen aktuellen gcc compiler unter ubuntu. Vielen Dank und Gruß, Thomas
Datum:
Sir.Tom schrieb: > habe nun versucht ein > Array von structs zu erstellen. Das aber tust Du nicht. Du hast ein Array von Pointern auf Structs erstellt, und da Du die Pointer nicht initialisierst, sie also im wahrsten Sinne des Wortes irgendwohin zeigen, schlagen Deine Versuche, auf die Strukturen zuzugreifen, verständlicherweise fehl.
Datum:
Guten Tag ... Hier mein Eigenversuch. Es compiliert und läuft fehlerfrei. Zufall oder zufällig richtig ?
#include <stdio.h> struct etest { int err_id; int err_no; char err_name; }; void main() { struct etest errstack; errstack.err_id = 0x55; // ein element testweise beschreiben. printf("id: %x\n",errstack.err_id); } |
Für Genies sind Zeiger absolutes Muß, für mich sind sie die Begründung für meine Depressionen ... Martin
Datum:
> Zufall oder zufällig richtig ? Für mich sieht's okay aus, allerdings... > Für Genies sind Zeiger absolutes Muß, > für mich sind sie die Begründung für meine Depressionen ... ... frage ich mich, wo du da einen Zeiger siehst? Klar, intern wird da vielleicht einer verwendet, da es sich um ein struct handelt, aber du selbst verwendest da ja keinen. Probier mal folgendes:
#include <stdio.h> struct etest { int err_id; int err_no; char err_name; }; void main() { struct etest errstack; struct etest *errstack_p; errstack_p = &errstack; errstack_p->err_id = 0x55; // ein element testweise beschreiben. printf("id: %x\n",errstack.err_id); } |
Achtung, ist aus dem Kopf, kann's grad nicht gegenprüfen, also evtl. mit Macken verbunden! Aber das wäre meiner Erinnerung nach ungefähr das, was für einen struct-Zugriff mittels Pointer nötig ist. Ralf
Datum:
Martin Beuttenmüller schrieb: > Für Genies sind Zeiger absolutes Muß, > für mich sind sie die Begründung für meine Depressionen ... Das hat mit Genie wenig zu tun. Eher damit, dass man kapiert, das es einen Unterschied macht, ob ein Buch selber im Regal steht oder ob dort ein Zettel steckt auf dem steht "Buch gerade von Mitglied 'xyz' entlehnt. Zu finden in Gang 5, Büro 8".
Datum:
Martin Beuttenmüller schrieb: > Guten Tag ... > > Hier mein Eigenversuch. Es compiliert und läuft fehlerfrei. > Zufall oder zufällig richtig ? Was um alles in der Welt hat das mit diesem Thread zu tun? Oder mit dem Titel? Schafft der Durchschittsdepp heute es nicht mal mehr einen Thread zu eröffnen, wenn er etwas fragen will? Das wäre für mich eher ein Grund für Depressionen. Es könnte ja sein, daß sich jemand (z.B. der TE oder jemand, der ihm schon mal geantwortet hat), NICHT mit deinem Problem beschäftigen will.
Datum:
@ Hrn. Wachtler Es war keineswegs meine Absicht, einen neuen Tread mit einer neuen Frage zu eröffnen. Vielmehr habe ich versucht, das obige Problem durch "trial 'n error" zu lösen und mir die Freieit genommen, das Ergebnis zu posten. Mag sein, das mein Auftreten mißverständlich geraten ist - Ihre Kritik hätte auch etwas dezenter formuliert werden können. --- Ersetzen wir doch einfach "Genies" durch "Profis". Ich bin keins von beidem, aber immer gewillt, dazuzulernen ... In diesem Sinne Martin
Datum:
aus Sir.Tom schrieb: > void main() > { > struct etest *errstack[3]; > > errstack[1]->err_id = 0x55; // ein element testweise beschreiben. > > printf("id: %x\n",errstack[1]->err_id); mach mal
void main() { struct etest errstack[3]; errstack[1].err_id = 0x55; // ein element testweise beschreiben. printf("id: %x\n",errstack[1].err_id); } |
Datum:
Der "Fehler" hier ist einfach, dass der Zeiger nicht initialisiert ist. In C++ zeigt ein Pointer, so er nicht initialisiert wird, einfach "irgendwohin". Genau so wie eine Variable einfach "irgendeinen" Wert hat wenn sie nicht initialisiert wird. Ein Pointer ist nämlich im Endeffekt nix anderes als eine Variable in der Breite des Adressbusses (also 32 bzw. 64 bit) wo halt eine Zahl drin steht, die dann eben als Adresse interpretiert werden soll statt als Zahl. Und da steht nun eben ohne Initialisierung irgendeine Adresse drin. Eine Adresse, die mit nahezu perfekter Sicherheit NICHT Dir gehört. Im Debug-Modus werden Variablen häufig standardmäßig mit 0 initialisiert. Sowas testet man entsprechend mit maximaler Optimierung, damit genau sowas vom Compiler eben nicht gemacht wird. Das nebenbei. Was in Deinem Beispiel passiert ist im Endeffekt das gleiche was hier passieren würde mit "normalen" Variablen:
int c, d, e, f; printf("%d %d %d %d\n", c, d, e, f); |
Jedes Mal wenn Du diesen Code ausführst, wirst Du wahrscheinlich anderes angezeigt bekommen. Zumindest wenn Dein Rechner schon 'ne Weile in Gebrauch war und entsprechend Datenmüll im Speicher noch rumliegt. Tut nicht weh, weil man's eben aufräumen soll bevor man's verwendet. Bei "normalen" Variablen existieren diese zur Beschreibung bereits wenn Du sie deklarierst. Der Aufruf
unsigned int c; c = 0x08154711; |
ist demnach durchaus zulässig. Was hier passiert ist, dass der Compiler im ram nach hinreichend Platz sucht um eine integer Variable anzulegen, merkt sich wo der Platz war und weiß, dass er jedesmal, wenn du was von der Variablen "c" willst er in diesen Platz schreiben soll. In "c" steht jetzt "irgendwas" drin. Wir haben ja auch nix reingetan (noch). Wir haben mit "unsigned int c" dem Compiler nur gesagt, er soll uns wo Platz für 'ne Int suchen. Mit der 2. Zeile wird nun in diesen Platz der Wert 0x08154711 geschrieben. Das funktioniert. Nun gucken wir doch mal was bei Zeigern passiert.
unsigned int *c; *c = 0x08154711; |
In der 1. Zeile sagen wir dem Compiler, er soll uns wo Platz für eine Adresse suchen. Wir sagen ihm sogar, dass diese Adresse irgendwann mal eine unsigned int enthalten wird. Wesentlich dabei ist, dass der Platz für den ZEIGER hier reserviert wird. NICHT der Platz für die unsigned int auf die er zeigt. Es wird nicht, wie oft behauptet wird, "nichts" vom Compiler hier reserviert. Es wird der Platz für den ZEIGER reserviert. Nicht, natürlich, der Platz auf den er zeigt. Genauso wie "unsigned int c" im 1. Beispiel Müll enthielt bevor wir eine Zahl hineinschrieben, genauso enthält "unsigned int *c" eine "Mülladresse" bevor wir eine sinnvolle Adresse hineinschreiben. Entsprechend geht diese Zuweisung schief, wir wollen hier den Wert 0x08154711 an eine Stelle schreiben, die uns nicht gehört! DAS geht dementsprechend schief und endet mit einem Programmabsturz. Jetzt können wir entweder eine integervariable reservieren und unser *c drauf zeigen lassen.
unsigned int c; unsigned int *ptr_c; ptr_c = &c; c = 0x08154711; *ptr_c = 0x08154711; //tut genau das gleiche wie die Zeile darüber |
Beachte: Es muss KEIN gültiger Wert an der Adresse von c stehen damit wir ihre Adresse dem Zeiger drauf zuweisen können. Was drin steht ist dem Zeiger herzlich egal. Wichtig ist für ihn nur, dass diese Adresse "gültig" ist und dem Programm "gehört", also allokiert wurde, entweder (wie hier) vom Compiler indem es eine Variable dazu gibt oder (wie wir's gleich machen werden) vom Programmierer indem er den Speicher dynamisch anfordert. Wenn die Adresse auf die der Zeiger zeigt auf diese Art definiert wird, ist es NICHT notwendig sie "manuell" freizugeben, da diese Adresse vom compiler allokiert worden ist. Anders siehts's aus wenn der Speicher dynamisch allokiert wird.
unsigned int *ptr_c; //C - Code ptr_c = (unsigned int*)malloc(sizeof(unsigned int)); //Alternativ dazu: C++ ptr_c = new int; *ptr_c = 0x08154711; //Jetzt damit arbeiten //C - Code free (ptr_c); //C++ code delete ptr_c; ptr_c = 0; //Muss nicht sein, sorgt aber für weniger Kopfweh. |
Speicher den Du explizit allokierst (mit malloc oder new) MUSST Du auch wieder durch die dazu passende "Aufräumaktion" deallokieren (mit free bzw. delete). Ist nicht simpel. Ich weiß. Wennst es aber einmal begriffen hast ist's echt kein Drama mehr. Ein wenig ASM hilft dabei übrigens sehr.
Datum:
@ Heinz L. Herzlichen Dank für die ausführliche Erklärung. Martin