Speicher, structs und pointer

Antworten
Nachricht
Autor
Tim_

Speicher, structs und pointer

#1 Beitrag von Tim_ » 07. Feb 2006 12:01

Ich stehe hier vor einem kleinen Problem mit structs und pointern.
Folgendes funktioniert einwandfrei:

Code: Alles auswählen

struct foo
{
	char *c1;
};

int main()
{
	struct foo bar;
	bar.c1 = (char *)malloc(6);
	bar.c1 = "blubb";
	
	printf("%s\n", bar.c1);

	return 0;
}
Wohingegen

Code: Alles auswählen

struct foo
{
	char *c1;
};

int main()
{
	struct foo *bar;
	bar->c1 = (char *)malloc(6);
	bar->c1 = "blubb";
	
	printf("%s\n", bar->c1);
	
	return 0;
}
einen Segmentation fault zur Folge hat.
Vermutlich ist es was triviales aber ich hab bisher keine Lösung gefunden.

Wäre super wenn mir jemand den Tipp geben könnte was ich hier falsch mache.

Gruß & danke
Tim

Alex.MH

#2 Beitrag von Alex.MH » 07. Feb 2006 15:57

Hi,

zu Beispiel 1:
Hier kannst du dir das malloc sparen. "blubb" wird nicht, wie du vielleicht denkst, in den frisch allozierten Speicher geschrieben. Du musst schon sowas wie "strncpy()" verwenden, um "blubb" in deinen neuen Speicherbereich zu schreiben. Eigentlich sollte der Compiler eine Warnung ausgeben, dass du einem char pointer einen "const char" Wert zuweisen willst. Dein Speicher, den du malloc alloziert hast geht in dem Moment verloren, indem du dem char pointer die Adresse von "blubb" zuweist. Dein Programm wuerde in diesem Fall ein Speicherleck haben, da du den allozierten Speicher nicht mehr freigeben kannst (du hast ihn ja mit einem neuen Pointer ueberschrieben).

zu Beispiel 2:
Es funktioniert nicht, weil du keine Speicher fuer die Struktur "bar" allozierst. Mit "struct foo *bar" hast du einen Pointer auf eine Struktur. Dieser Pointer zeigt aber ins Nichts. Greifst du dann darauf zu erhaelst du einen Segmentation Fault. Du musst mit "malloc()" erst Speicher fuer die Struktur allozieren und dann kannst du auf die Variablen der Struktur zugreifen.
Dein Beispiel 1 funktioniert, weil hier der Compiler fuer dich den Speicher fuer bar reserviert.

Gruss,
Alex

Tim_

#3 Beitrag von Tim_ » 07. Feb 2006 17:12

Begehen eigentlich viele C-Programmierer Selbstmord? :lol:

Danke, im Nachhinein ist es nicht ganz unlogisch dass man für das struct den Speicher reserviert und nicht für die einzelnen Variablen, aber von alleine wär ich da nicht draufgekommen.

Bei dem ersten Beispiel gibt er mir keinerlei Warnungen aus (gcc Gentoo 3.3.6).
Heisst das also, dass jede Zuweisung wie
c = "whatever";
den String zwischen den " neu in den Speicher schreibt und diese Adresse dem Pointer dann zuweist?
Und beim ersten Beispiel reserviert der Compiler für 'bar' einen Speicherbereich der Größe sizeof(char *) und nicht Platz für die chars selbst?!
Ist das denn dann so in Ordnung oder würde man das irgendwie anders machen?
Sprich, sollte ich im zweiten Beispiel dann für den Pointer auf das struct 4 Byte (=sizeof(char *)) oder 4 + x Bytes reservieren wenn ich x chars speichern will?

Was ist der saubere Weg?

Vielen Dank
Tim

Alex.MH

#4 Beitrag von Alex.MH » 07. Feb 2006 19:17

Bei dem ersten Beispiel gibt er mir keinerlei Warnungen aus (gcc Gentoo 3.3.6).
Kompilier deine Sachen einfach mit "-Wall" - dann warnt dich der Compiler. Sollte man eh immer machen.
Heisst das also, dass jede Zuweisung wie
c = "whatever";
den String zwischen den " neu in den Speicher schreibt und diese Adresse dem Pointer dann zuweist?
Ganz genau. "whatever" ist dann aber vom Typ "const char*" und darf somit nicht veraendert werden. Deshalb sollte dich der Compiler auch warnen, denn wenn du versuchst "whatever" mit einem String gleicher laenge zu ueberschreiben, dann stuerzt dein Programm mit einem "bus error" ab.

Sauberer Stil ist es also Konstanten auch als const zu markieren:

Code: Alles auswählen

const char* c = "whatever";
Und beim ersten Beispiel reserviert der Compiler für 'bar' einen Speicherbereich der Größe sizeof(char *) und nicht Platz für die chars selbst?!
Ebenfalls richtig. Allerdings reserviert der Compiler nicht sizeof(char*) sondern sizeof(struct foo) - was in diesem Fall aber das gleiche ist.
Ist das denn dann so in Ordnung oder würde man das irgendwie anders machen?
Sprich, sollte ich im zweiten Beispiel dann für den Pointer auf das struct 4 Byte (=sizeof(char *)) oder 4 + x Bytes reservieren wenn ich x chars speichern will?
Korrekt sollte das zweite Beispiel so aus sehen (ungetestet - also vielleicht doch nicht ganz korrekt):

Code: Alles auswählen

int main()
{
    struct foo* bar = (struct foo*)malloc(sizeof(struct foo));

    bar->c1 = (char*)malloc(6 * sizeof(char));

   strncpy(bar->c1, "Hallo", 6);

   printf("%s\n", bar->c1);

   return (0);
}
Gruss,
Alex

Tim_

#5 Beitrag von Tim_ » 07. Feb 2006 22:33

Seltsamerweise tut er trotz -Wall nicht meckern, das benutz ich inzwischen eigentlich immer.

Wieder mal danke für die Hilfe!
Gruß
Tim

Antworten