Forum: Mikrocontroller und Digitale Elektronik Pointer verstehen mit malloc und free


von Mohsen (Gast)


Lesenswert?

Hi,

ich beschäftige mich seit ca. 3-4 Wochen mit der c-Programmierung, bin 
also ein Neuling.

Ich habe das Kapitel mit den Pointern ,Heap und Stack abgeschlossen.
Nun habe ich mir aus dem Internet eine Uebungsaufgabe rausgesucht um zu 
schauen ob ich das ganze wirklich verstanden habe.

Die Aufgabe:
1.)
Ergänzen Sie zunächst die Funktion f1 um zwei lokale Variablen px und 
ppx. Die Variable px soll ein Zeiger auf die vorgegebene Variable x sein 
und ppx soll ein Zeiger auf px sein. Initialisieren Sie die neuen 
Variablen entsprechend und geben Sie dann für alle drei Variablen den 
jeweiligen Wert und die Adresse der Variablen auf der Konsole aus. Die 
Ausgabe sollte dann etwa wie folgt aussehen (natürlich mit anderen 
Adressen):

x = 0  Adresse von x: 0x7ffc654c45dc
px = 0x7ffc654c45dc Adresse von px: 0x7ffc654c45e0
ppx = 0x7ffc654c45e0 Adresse von ppx: 0x7ffc654c45e8

2.)
Ergänzen Sie nun die Funktion f2 ebenfalls um zwei lokale Variablen px 
und ppx und initialisieren Sie diese mit zwei Adressen, welche Speicher- 
bereiche auf dem Heap bezeichnen: px soll dabei auf einen Speicherbe- 
reich zeigen, in dem ein ganzzahliger Wert gespeichert werden kann und 
ppx soll auf einen Speicherbereich zeigen, in dem die Adresse einer 
ganzzahligen Variablen gespeichert werden kann. Initialisieren Sie den 
Inhalt der ersten Variable auf dem Heap mit dem Wert von x und den 
Inhalt der zweiten Variable auf dem Heap mit der Adresse der ersten 
Variablen auf dem Heap. Geben Sie wiederum die Werte und die Adres- sen 
der Variablen x, px und ppx auf der Konsole aus und geben Sie den 
dynamisch angeforderten Speicher wieder frei. Die Ausgabe sollte dann 
etwa wie folgt aussehen:

x = 0  Adresse von x: 0x7ffc654c45dc
px = 0x7ffc654c45dc Adresse von px: 0x7ffc654c45e0
ppx = 0x7ffc654c45e0 Adresse von ppx: 0x7ffc654c45e8

Meine Lösung:
1
void f1(){
2
  int x = 0;
3
  int *px;
4
  int **ppx;
5
  
6
  px = &x;
7
  ppx = &px;
8
  
9
  printf("x: \t%d\t\t\t Addr: %p\n", x, &x);
10
  printf("px: \t%p\t Addr: %p\n", px, &px);
11
  printf("pxx: \t%p\t Addr: %p\n\n", ppx, &ppx);
12
}
13
14
void f2(){
15
  int x = 0;
16
  int *px = malloc(sizeof(int));
17
  int **ppx = malloc(sizeof(int *));
18
  
19
  *px = x;
20
  *ppx = &px;
21
  
22
  printf("x: \t%d\t\t Addr: %p\n", x, &x);
23
  printf("px: \t%p\t Addr: %p\n", px, &px);
24
  printf("pxx: \t%p\t Addr: %p\n\n", ppx, &ppx);
25
  
26
  free(px); 
27
  free(ppx); 
28
}

[Mod: Den Code in [ c ] und [ /c ] eingefasst]

Leider gibts zu der Uebungsaufgabe keine Lösung.
Kann jemand vllt. kurz drueberschauen und mir sagen ob alles richtig 
ist?
Bzw. ob ich das mit den Pointern, Stack und Heap richtig verstanden 
habe.

Lg

: Bearbeitet durch Moderator
von Rainer V. (rudi994)


Lesenswert?

Läuft in CodeBlocks mit MinGW fehlerfrei bis auf Zeile: *ppx = &px;
Fehler/Warnung: assignment from incompatible pointer type
Beseitigung der Fehlermeldung durch: ppx = &px;
Oder durch Typecast: *ppx = (int *) &px;

Gleiche Aufgabe siehe auch: https://www.c-plusplus.net/forum/342707

: Bearbeitet durch User
von Marco H. (damarco)


Lesenswert?

Ist auch logisch denn -> **ppx sagt das der Zeiger auf einen Zeiger 
zeigt.

Warum lasse ich erst mal als Lerneffekt offen :)


"Beseitigung der Fehlermeldung durch: ppx = &px;
Oder durch Typecast: *ppx = (int *) &px;"

Oh Bitte nicht ! wenn man nicht verstanden hat was man da macht -> die 
Warnung ist legitim.

von Rainer V. (rudi994)


Lesenswert?

Marco H. schrieb:
> Beseitigung der Fehlermeldung durch: ppx = &px;
> Oder durch Typecast: *ppx = (int *) &px;"
>
> Oh Bitte nicht !

Ja stimmt! Zum Editieren meines Beitrags war es leider zu spät. Deshalb 
noch folg. Nachtrag:

Wird die Warnung ignoriert, liefert **ppx nicht den Wert von x. Ebenso 
bei *ppx = (int *) &px; obwohl keine Warnung gemeldet wird.
Bei ppx = &px; liefert **ppx auch den Wert von x. LG

: Bearbeitet durch User
von Marco H. (damarco)


Lesenswert?

Dann denk nach warum !!!

Gibt die Adresse vom Ausdruck &px  aus und vergleiche diese mit x.

von Mohsen (Gast)


Lesenswert?

Ich bin etwas verwirrt jetzt,

hab ich also alles richtig gemacht oder nicht?

Lg

von Marco H. (damarco)


Lesenswert?

Ich glaube schon, dein Code schon der von Reiner nicht ;)

: Bearbeitet durch User
von Rainer V. (rudi994)


Lesenswert?

Mohsen schrieb:
> hab ich also alles richtig gemacht oder nicht?

Marco H. schrieb:
> Ich glaube schon

Was soll das heissen? Das ist hier kein Religionsforum ;)

> *ppx = &px;

Falsch! Das speichert nur die Adresse von px im für ppx allokierten 
Bereich auf dem Heap. Auch wäre zumindest bei meinem Compiler ein 
Typecast wie *ppx = (int*) &px; nötig, sonst Fehler: Zuordnung eines 
inkompatiblen Zeigertyps.

Folg. wäre auch falsch, verursacht AppCrash: *ppx = (int*) *px;

In o.g. Aufgabe ist gefordert, daß der x-Wert in den für px allokierten 
Bereich auf dem Heap kopiert wird und die Adresse dieses Heap-Bereiches 
in dem für ppx allokierten Heap-Bereich gespeichert wird. Folg. Code hat 
bei mir den gewünschten Effekt:

*px = x;
*ppx = (int*) px;

Folg. Code zeigt mittels ppx den int-Wert aus dem px-Heap-Bereich an:
printf("*(int*) *ppx   = %d\n", *(int*) *ppx);

von Marco H. (damarco)


Lesenswert?

Also ich Behaupte du speicherst die Adresse von x  in einen Pointer wo 
der compiler ein Pointer vom Type int erwartet.

Gefordert ist pointer->pointer->x , du versuchst pointer->x .

Das die App abschmiert ist logisch denn das ganze ist auch gefährlich. 
Da der pointer keine gültige Adresse besitzt. Anders wie beim µP 
verhindert der Kernel den zugriff in dem er das Programm beendet.

und auch nach Free bleibt der Inhalt der Pointer erhalten.

Gebe sie mal mit free() frei und gebe die Adressen aus -> vermutlich 
stehen dann andere Adressen drin durch das Printf. In der Regel hat sich 
an dem Inhalt nichts geändert und du könntest munter darauf zugreifen.


Deshalb:

nach free()

px=NULL;
pxx=NULL;

und auch prüfen ob du von malloc auch speicher bekommen hast !
1
int *px = malloc(sizeof(int));
2
3
if(px){};

Außerdem gibt malloc den Type void zurück besser ist int 
*px=(int*)malloc(sizeof(int));

warum wirt du noch Festellen

: Bearbeitet durch User
von Rainer V. (rudi994)


Lesenswert?

Marco H. schrieb:
> nach free()
>
> px=NULL;
> pxx=NULL;
>
> und auch prüfen ob du von malloc auch speicher bekommen hast !

Habe ich gemacht, betreffende Teile meines Code finden sich im Beitrag 
16:25:00 05.05.2017 auf der 2.Seite unter folg. Link, wo über dieselbe 
Aufgabe diskutiert wird: https://www.c-plusplus.net/forum/342707-10

Mein Gesamtprogramm enthält auch Code zum Anzeigen der Bytes auf dem 
Heap, sodaß ich z.B. sehen kann, ob bei einer Zuweisung der Wert von x 
oder die Adresse des px-Heapbereiches in den ppx-Heapbereich kopiert 
worden ist.

Trotzdem: bei einem Zeiger, dessen Wert auf dem Heap liegt, auf einen 
Zeiger, dessen Wert auf dem Heap liegt, auf ein Objekt im Speicher (oder 
u.U. ebenfalls auf dem Heap) ist alles etwas tricky. Es wäre wohl auch 
einfacher, nur mit void-Pointern und memcpy() zu arbeiten, anstatt sich 
mit *p, **p usw. herumzuärgern. Aber das ist sicher nicht der Sinn der 
Übungsaufgabe des TE.

> Das die App abschmiert ist logisch ...
> Da der pointer keine gültige Adresse besitzt.

Ich nehme an, daß sich diese Anmerkung auf folg. bezieht:
Rainer V. schrieb:
> falsch, verursacht AppCrash: *ppx = (int*) *px;

Hier wird *ppx der Wert von x (wie 0, 123, 456 o.a.) zugewiesen, was im 
weiteren Verlauf zu einem Ausnahmefehler führt, weil dies keine gültige 
Adresse ist oder weil auf fremden Speicher zugegriffen wird.

Marco H. schrieb:
> Außerdem gibt malloc den Type void zurück besser ist int
> *px=(int*)malloc(sizeof(int));

Besser ist es. Ohne diesen Typecast meckert mein C-Compiler zwar nicht, 
aber in C++ wird sofort ein Fehler gemeldet.

von A. S. (Gast)


Lesenswert?

Marco H. schrieb:
> warum wirt du noch Festellen
meinst Du nach aktivierung höherer Warnstufen?

Ich habe echt so mein Problem mit pointer-casts, wenn sie auch 
indirektions-"level" ändern können...  Eigentlich habe ich ein 
generelles Problem mit casts, da dann alle typ- und Bereichsprüfunge 
ausgeschaltet sind...

von Marco H. (damarco)


Lesenswert?

Unter Standard C kann nichts passieren da malloc byte orientiert 
arbeitet.

Bei C++ sieht das anders aus, dort ist es Typen orientiert und wenn du 
das malloc nicht aus der Standard lib benutzt geht der Compiler davon 
aus das der Type *int ist. Einmal vergessen <stdint.h> einzubinden führt 
das dann zu Problemen gerade bei long Typen. So etwas ist schwer 
nachvollziehbar und tritt irgend wo im Programm unscheinbar auf.

Um dich davor zu bewahren gibt es die Warnung.

Beim cast muss man natürlich wissen was man macht. Das explizite casten 
zeigt das hier eine Typenumwandlung gewollt war.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.