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
voidf1(){
2
intx=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
voidf2(){
15
intx=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
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
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.
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
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);
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
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.
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...
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.