2 Stimmen

C-Zeiger und Speicher

Ich lerne gerade C und stoße jetzt auf eine Mauer. Es ist schwierig für mich, Zeiger zu verstehen.

Stellen Sie sich vor, ich habe diesen Code:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#define DELTA 33

int calls, seed=356;

int sum_ds(int a){    
 int d=DELTA;          
 calls++;               
 return a+d+seed; 
}                       

int main() {
    int num;                                
    int *ptr;
    int **handle;

     num = 14;                              
     ptr = (int *)malloc(2 * sizeof(int));  
     handle = &ptr;
     *(*handle+0) = num;                    
     *(*handle+1) = num+1;  
     *ptr = num-2;      
     ptr = &num;        
     *ptr = sum_ds(num-2);
}

Lassen Sie uns Schritt für Schritt durch mein Verständnis gehen.

1 - int calls erstellt eine Variable namens calls und initialisiert sie nicht, so dass sie Müll enthält. Sie wird auf DATA und sagen wir mit der Speicheradresse 0xFFAA gespeichert.

2 - int seeds erzeugt eine Variable namens seeds, die mit der ganzen Zahl 356 initialisiert wird. Sie wird auf DATA gespeichert, und zwar mit der Speicheradresse 0xFFAB.

3 - int num erstellt eine Variable namens num und initialisiert sie nicht, so dass sie Müll enthält. Sie wird auf dem STACK gespeichert, und zwar mit der Speicheradresse 0xFFAC.

4 - int *ptr erzeugt einen Zeiger auf int und weist ihm keine Adresse zu. Er wird auf dem STACK gespeichert, sagen wir mit der Speicheradresse 0xFFAD.

5 - int **handle erzeugt einen Zeiger auf einen Zeiger von int und weist ihm keine Adresse zu. Er wird auf dem STACK gespeichert, sagen wir mit der Speicheradresse 0xFFAE. (VIELE ZWEIFEL HIER)

6 - num = 14 geht zur Adresse 0xFFAC und speichert dort die Zahl 14. Das geschieht im STACK.

7 - ptr = (int *)malloc(2 * sizeof(int)) Auf dem HEAP wird eine Speichergröße für 2 Ints zugewiesen und die Adresse des ersten Speicherbytes (sagen wir 0xFFZZ) wird (auf STACK) auf ptr gespeichert, so dass *ptr nun auf diese Speicheradresse zeigt.

8 - handle = &ptr handle zeigt jetzt auf ptr. Ich glaube, es zeigt jetzt auf das, was auf 0xFFZZ steht (VIELE ZWEIFEL HIER)

9 - *(*handle+0) = num der Zeiger auf den Zeiger von int, dem jetzt der Wert von num zugewiesen ist (14) (VIELE VIELE VIELE VIELE DUBELS HIER)

10 - *(*handle+1) = num+1 der Zeiger von pointer plus einer von int wird nun mit dem Wert von num + 1 belegt (15) (VIELE VIELE VIELE VIELE DUBELS HIER)

11 - *ptr = num-2 der Wert Punkt von ptr wird mit dem Wert von num - 2 (12) zugewiesen. Ich glaube, es geht an die Speicheradresse 0xFFZZ und speichert dort die Zahl 12.

12 - ptr = &num ptr zeigt jetzt auf num, ich glaube es zeigt jetzt auf 0xFFAC.

13 - *ptr = sum_ds(num-2) der Wert, auf den ptr zeigt, ist der zurückgegebene Wert von sum_ds. Ich glaube 0xFFAC wird mit 401 (12+33+356) zugewiesen.

Ist das richtig?

4voto

Péter Török Punkte 111735

1 - int calls erstellt eine Variable namens calls und initialisiert sie nicht, so dass sie Müll enthält. Sie wird auf DATA und sagen wir mit der Speicheradresse 0xFFAA gespeichert.

2 - int seeds erzeugt eine Variable namens seeds, die mit der ganzen Zahl 356 initialisiert wird. Sie wird auf DATA gespeichert, und zwar mit der Speicheradresse 0xFFAB.

Ein kleines Detail: sizeof(int) größer als 1 ist (auf den meisten Mainstream-Plattformen ist sie 4, so dass die zweite Adresse nicht um 1 höher sein kann als die erste. Abgesehen davon, AFAIK Sie sind so weit korrekt.

3 - int num erstellt eine Variable namens num und initialisiert sie nicht, so dass sie Müll enthält. Sie wird auf dem STACK gespeichert, und zwar mit der Speicheradresse 0xFFAC.

4 - int *ptr erzeugt einen Zeiger auf int und weist ihm keine Adresse zu. Er wird auf dem STACK gespeichert, sagen wir mit der Speicheradresse 0xFFAD.

Ein weiteres kleines Detail: Auf den meisten Mainstream-Plattformen wächst der Stack nach unten, so dass die vierte Adresse kleiner ist als die dritte. Abgesehen davon sind Sie soweit korrekt. (Außerdem wären die Adressen im Datensegment, im Heap und im Stack im wirklichen Leben ziemlich unterschiedlich).

7 - ptr = (int *)malloc(2 * sizeof(int)) Auf dem HEAP wird eine Speichergröße für 2 Ints zugewiesen und die Adresse des ersten Speicherbytes (sagen wir 0xFFZZ) wird (auf STACK) auf ptr gespeichert, so dass *ptr nun auf diese Speicheradresse zeigt.

Um pingelig zu sein: "Z" ist keine Hexadezimalzahl :-) Sagen wir also, es ist 0x1000 stattdessen.

8 - handle = &ptr handle zeigt jetzt auf ptr. Ich glaube, es zeigt jetzt auf das, was auf 0xFFZZ steht (VIELE ZWEIFEL HIER)

Nein, handle enthält nun die Adresse von ptr d.h. 0xFFAD . Indirekt obwohl - durch ptr - deutet es in der Tat auf 0x1000 (war 0xFFZZ in Ihrem Beispiel).

9 - *(*handle+0) = num der Zeiger auf den Zeiger von int, dem jetzt der Wert von num zugewiesen ist (14) (VIELE VIELE VIELE VIELE DUBELS HIER)

Im Grunde genommen richtig. Die von Ihnen verwendete Notation ist nicht ganz einfach zu handhaben, was es für Sie schwieriger macht, die Vorgänge nachzuvollziehen. Nach Schritt 8, *handle ist gleichbedeutend mit ptr . Und da Zeiger und Arrays in vielen Situationen austauschbar sind, ist *(ptr+0) äquivalent zu ptr[0] und auch an *ptr .

10 - *(*handle+1) = num+1 der Zeiger von pointer plus einer von int wird nun mit dem Wert von num + 1 belegt (15) (VIELE VIELE VIELE VIELE DUBELS HIER)

Ähnlich wie beim vorigen Punkt weisen Sie in der Tat ptr[1] = num+1 . Beachten Sie jedoch, dass ptr es int* so dass die Adressdifferenz zwischen ptr y ptr + 1 ist gleich sizeof(int) die, wie oben erwähnt, in der Regel 4 beträgt.

11 - *ptr = num-2 der Wert Punkt von ptr wird mit dem Wert von num - 2 (12) zugewiesen. Ich glaube, es geht an die Speicheradresse 0xFFZZ und speichert dort die Zahl 12.

Ja, damit wird der in Schritt 9 eingestellte Wert überschrieben.

12 - ptr = &num ptr zeigt jetzt auf num, ich glaube es zeigt jetzt auf 0xFFAC.

Richtig.

13 - *ptr = sum_ds(num-2) der Wert, auf den ptr zeigt, ist der Rückgabewert von sum_ds. Ich glaube 0xFFAC wird mit 401 (12+33+356) zugewiesen.

Richtig. Da der vorherige Schritt die *ptr gleichbedeutend mit num ist dieser Aufruf auch gleichbedeutend mit num = sum_ds(num-2) .

1voto

Jerry Coffin Punkte 452852

Seit calls außerhalb einer Funktion liegt, ist es eine static variabel. Statische Variablen werden mit 0 initialisiert.

Seit num ist eine lokale Variable ( auto Speicherklasse) ist es no initialisiert.

Zu Ihrem Punkt 9, *(*handle+0) = num; ist wahrscheinlich am einfachsten zu entschlüsseln, wenn man sich vor Augen hält, dass handle = &ptr daher *handle = ptr Dies entspricht also im Wesentlichen *(ptr+0) = num; was (wiederum) äquivalent ist zu ptr[0] = num; .

Für Punkt 10 erhalten Sie so ziemlich das Gleiche, außer einer +1 in beiden Fällen, es heißt also ptr[1] = num+1; .

Zu Punkt 11, *ptr=num-2; überschreibt, was in Punkt 9 geschrieben wurde - d.h. *ptr ist dasselbe wie *(ptr+0) Dies ist also gleichbedeutend mit ptr[0] = num-2;

In Punkt 12 haben Sie Recht, dass ptr wurde so eingestellt, dass es auf num . Das bedeutet, dass die Zuordnung in Nummer 13 gleichbedeutend ist mit num=sum_ds(num-2);

1voto

Bruno Soares Punkte 736

Eine Variable hat eine Adresse und speichert an dieser Adresse den Wert, den Sie gerade eingegeben haben:

int a = 10;

Richtig?

Ein Zeiger ist eine Art von Variable, die die Adresse einer anderen Variablen speichert. Also...

int a = 10;
int *p = &a;

Das bedeutet, dass "p" die Adresse von "a" speichert, die den Wert hat, den Sie verwenden möchten.

Führen Sie den folgenden Code aus und Sie werden es verstehen: printf("%p %p %d %d \n ", p, &a, *p, a);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X