Zeiger und Referenzen in C + + Teil 1

19. April, · 2009 Posted in C / C + +

Zeiger und Referenzen sind zwei wichtige Begriffe in der Informatik. Sie erscheinen in vielen Programmiersprachen mit einem Kleid oder ein wenig anders, aber die Behandlung ist grundsätzlich das gleiche. In C + +, mit Zeigern Qualifikationen sind wesentliche Voraussetzungen.

Pointer ist eine spezielle Art der Daten, Variablen, deren erklärtes Ziel dieser Art können (oder nicht), einige andere Daten im Speicher. Ein Zeiger-Variable enthält die Adresse einer anderen Sache in Erinnerung. Dieses Ding kann eine Variable, Konstante, die Einleitung eines Datensatzes, eine Funktion, ua werden.

Deklarieren Pointers

Die Deklaration eines Zeigers ist in der Regel durch das Anhängen eines * vor dem Variablennamen getan. Eine viel verwendete Notation der Leim * Der Name des Typs symbolisch zu sagen, dass ist die Vereinbarkeit eines "Zeiger auf den Typ" anstelle eines "Zeigervariable", aber sie sind gleichwertig. Zum Beispiel:

  / / Zeiger auf einen int.
 ptr_num1 ; int * ptr_num1;

 / / Oder so.
 ptr_num2 ; int * ptr_num2;

 / / Zeiger auf eine doppelte.
 ptr_double1 ; double * ptr_double1;

 / / Oder so.
 ptr_double2 ; double * ptr_double2; 

Einmal angemeldet, kann die Zeiger existiert, hat die Größe und somit findet in Erinnerung. Die Größe eines Zeigers ist in der Regel gleich der Anzahl der Bits der Maschine / Anlage in Frage, z. B. 4 Byte in einem 32-Bit-System.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 pc ; int i, * pi ; double d, * pd ; // O operador sizeof diz o tamanho do tipo do seu argumento. cout << "Size of char:    " << sizeof ( c ) << " bytes" << endl ; cout << "Size of int:     " << sizeof ( i ) << " bytes" << endl ; cout << "Size of double:  " << sizeof ( d ) << " bytes" << endl ; cout << endl ; cout << "Size of char*:   " << sizeof ( pc ) << " bytes" << endl ; cout << "Size of int*:    " << sizeof ( pi ) << " bytes" << endl ; cout << "Size of double*: " << sizeof ( pd ) << " bytes" << endl ; char c, * PC, int i, * pi-, Doppel-D, * pd / / Der Operator sizeof sagt die Größe der Typ des Arguments. cout <<"Größe der Zeichen:" <<sizeof (c) <<" bytes "<<endl; cout <<" Größe von int: "<<sizeof (i) <<" bytes "<<endl; cout <<" Größe von double: "<<sizeof (d) <<" bytes " <<endl; cout <<endl; cout <<"Größe von char *:" <<sizeof (cp) <<<"bytes" <<endl; cout <"Größe von int *:" <<sizeof (pi) <<"bytes" <<endl; cout <<"Größe von double *" <<sizeof (pd) <<"bytes" <<endl; 

Mit Pointers

Nach seiner Aussage ist der Inhalt eines Zeigers auf einen zufälligen Wert, Müll-Speicher, wie jede Variable. Denn es nützlich zu sein, müssen wir ihm etwas geben. Wie hält ein Zeiger eine Speicheradresse, müssen wir weisen Sie eine gültige Adresse.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
  int x, y;
 px, * py ; int * px, py *;

 ; x = 13;
 ; y = 10;

 x ; px = & x;
 y ; & Py = y;

 42 ; * Px = 42;
 py ) ++ ; (* Py) + +;

 * px << endl ; cout <<* px <<endl;
 * py << endl ; cout <<* py <<endl;
 ( * px ) * ( * py ) << endl ; cout <<(* px) * (* py) <<endl; 

Der Operator & (kaufmännisches oder Zeichen ), bevor eine Variable Name bedeutet "Adresse", denn sein Name ist "Adresse".

Was ist von der Gleichheit verlassen hat, um in der Lage, genau die gleiche Art zu halten ist als die andere Seite der Gleichheit. Ein Zeiger speichert die Adresse. Also an eine Adresse in einem Zeiger in diesem Fall zuordnen, müssen Sie eine Adresse erhalten, mit dem Operator &.

Abgesehen von dem Fall, wo es impliziten Typumwandlungen (z. B. zwischen numerischen Typen), weisen eine Variable, um etwas mit einem anderen Typ als seine eigene, was zu einem Kompilierungsfehler. Zum Glück!

Nach einem Zeiger deutet schon auf eine gültige Adresse, können wir Zugriff auf die Inhalte dieser Adresse mit dem Operator * ( Stern ), deren offizieller Name ist "de-Referenz-Operator."

Beachten Sie, dass der Stern in einer Erklärung, bedeutet "Zeiger auf den Typ" und im Rahmen der liest oder schreibt den Inhalt eines Zeigers bedeutet "den Inhalt der Adresse" oder "die Inhalte", betonte von. Auch darauf achten, nicht das Symbol für arithmetische Produkt zu verwechseln. Um zu vermeiden, verwirrend, nicht vergessen, dass große Tabelle der Vorrang von Operatoren , die Sie soeben die Augen und fiel in Vergessenheit. Dort finden Sie, dass die de-Referenz-Operator Vorrang vor der Multiplikation Betreiber. Dann wirst du nicht vergessen, dass die de-Referenz-Operator Multiplikationsoperator ausgewertet wird, bevor die.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
  pa, * pb ; int a, b, c, * pa, pb *;
 ; a = 2;
 ; b = 3;

 a ; pa = & a;
 b ; pb = & b;

 pa * * pb ; c = * pa * pb;
 pa * * pb ; c = * pa * pb;
 pa * * pb ; c = * pa * pb;
 pa ** pb ; c = * pa ** bp;
 * pa ) * ( * pb ) ; c = (* pa) * (* pb);

 "Valor da Pegadinha: " << c << endl ; cout <<"Wert von Gotcha:" <<c <<endl; 

Wenn also, dass der Nachweis von Algorithmen Sie fragen, was macht einer der letzten fünf Zeilen des Beispiels Sie sagen, dass es die Inhalte multipliziert wird, um die von AP und BP hingewiesen. Nicht mehr abholen DP dafür! Und Brechen im realen Leben, wenn Sie wirklich brauchen, um dies zu tun, werden Sie Ihre Zukunft sparen vierten und fünften Generation vergangenen Exkommunikation , wenn Sie wählen letzten Zeile zur Benutzung des.

Alles ist mit einer gemeinsamen Variablen, die Sie mit den Inhalten tun können, möglich, auf die ein Zeiger, entweder lesend oder schreibend (es sei denn es ist klar, dass der Zeiger const ist, aber das ist ein anderes Gespräch ...).

Adressen und Zeiger

Nehmen Sie zum Beispiel den folgenden Code:

  18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
  int a, b;
 pa, * pb ; int * pa, pb *;

 "Antes de qualquer atribuição: \n " ) ; printf ("Vor jedem Einsatz: \ n");

 "&a  = %p \n " , & a ) ; // Endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Gültig OS angegebenen Adresse durch.
 "&b  = %p \n " , & b ) ; // Endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Gültig OS angegebenen Adresse durch.
 "&pa = %p \n " , & pa ) ; // Endereço válido dado pelo SO. printf ("% pa = & p \ n", & pa) / / Gültig OS angegebenen Adresse durch.
 "&pb = %p \n " , & pb ) ; // Endereço válido dado pelo SO. printf ("& pb =% p \ n", & bp); / / Gültig OS angegebenen Adresse durch.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("a =% d \ n", a); / / Content initialisierten (random).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / Content initialisierten (random).
 "pa  = %p \n " , pa ) ; // Conteúdo não inicializado (aleatório). printf ("% pa = p \ n", PA) / / Content initialisierten (random).
 "pb  = %p \n " , pb ) ; // Conteúdo não inicializado (aleatório). printf ("bp =% p \ n", pb); / / Content initialisierten (random).

 / Bitte entfernen Sie die folgenden Zeilen ein, kompilieren und ausführen.
 / / Printf ("* pa =% d \ n", * pa) / / Was ist (random *)?
 / / Printf ("* pb =% d \ n", * pb) / / Was ist (random *)?

 " \n Após as inicializações dos ponteiros: \n " ) ; printf ("\ n Nach der Initialisierung von Zeigern: \ n");

 a ; pa = & a;
 b ; pb = & b;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Noch gültige Adresse gegeben von der OS.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Noch gültige Adresse gegeben von der OS.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("% pa = & p \ n", & pa); / / gleiche Adresse als gültig von der OS.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb =% p \ n", & bp); / / gleiche Adresse als gültig von der OS.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("a =% d \ n", a); / / Content initialisierten (random).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / Content initialisierten (random).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", PA) / / initialisiert Content (& a).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("bp =% p \ n", pb); / / Inhalt initialisiert (b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a). printf ("* pa =% d \ n", * pa) / / Inhalte, auf die ap (pa * == a).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b). printf ("* pb =% d \ n", * pb) / / Inhalt, auf den bp (bp == * b).

 " \n Após as inicializações dos inteiros: \n " ) ; printf ("\ n Nach dem Initialisierungen von ganzen Zahlen: \ n");

 ; a = 10;
 ; b = 13;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Noch gültige Adresse gegeben von der OS.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Noch gültige Adresse gegeben von der OS.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("% pa = & p \ n", & pa); / / gleiche Adresse als gültig von der OS.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb =% p \ n", & bp); / / gleiche Adresse als gültig von der OS.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo inicializado (10). printf ("a =% d \ n", a); / / Inhalt beginnt (10).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (13). printf ("b =% d \ n", b) / / Text beginnt (13).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", PA) / / initialisiert Content (& a).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("bp =% p \ n", pb); / / Inhalt initialisiert (b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a == 10). printf ("* pa =% d \ n", * pa) / / Inhalte, auf die ap (pa * a == == 10).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b == 13). printf ("* pb =% d \ n", * pb) / / Inhalte, auf die PB (PB * == b == 13).

 " \n Alterando os valores através dos ponteiros: \n " ) ; printf ("\ n Wertewandel durch Zeiger: \ n");

 7 ; * Pa = 7;
 42 ; * BP = 42;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Noch gültige Adresse gegeben von der OS.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Noch gültige Adresse gegeben von der OS.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("% pa = & p \ n", & pa); / / gleiche Adresse als gültig von der OS.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb =% p \ n", & bp); / / gleiche Adresse als gültig von der OS.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo inicializado (a == *pa ==  7). printf ("a =% d \ n", a); / / Inhalt initialisiert (* pa a == == 7).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (b == *pb == 42). printf ("b =% d \ n", b) / / Content initialisiert (b == == * pb 42).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", PA) / / initialisiert Content (& a).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("bp =% p \ n", pb); / / Inhalt initialisiert (b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa ( 7). printf ("* pa =% d \ n", * pa) / / Content pa ernannt (7).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (42). printf ("* pb =% d \ n", * pb) / / content wies auf die von BP (42). 

Lines 18.19 respectivamnete deklarieren zwei Integer-und zwei Zeigern auf Integer.

Linien 23 bis 26 zeigen die Adressen meiner Variablen. Diese Adressen wurden durch das Betriebssystem gegeben und sind fix, während diese Variablen existieren. Eine Variable nicht verändert Adresse während des Programms, sondern kann zwischen einer Ausführung und anderen zu wechseln. Wer definiert, was dieser Adresse das Betriebssystem zum Zeitpunkt der Durchführung des Programms ist. Der Compiler weiß nur, dass x Byte für jede Variable benötigt werden, und der Interpretation (Stil), dass das Programm, dass der Raum zu geben.

Linien 30 bis 33 zeigen den Inhalt dieser Variablen, die nicht initialisiert wurde. Es ist Müll, der letzte Wert, dass jemand (weiß nicht, wer) die Plätze im Speicher des Computers abgelegt werden und die gehören jetzt zu meinem Variablen.

Beachten Sie, dass es nicht sicher ist, entfernen Sie Zeilen 36 und 37, als sie auf den Inhalt zuzugreifen, auf den AP und BP, die nicht initialisiert wurde. In diesem Versuch wird das Programm versuchen, diese Werte zu interpretieren, als ob sie Müll Zufallsvariablen int gültige Adressen wurden. Je nach Compiler, verwendet das Betriebssystem und ihr Schicksal kann harmlos sein oder nicht. Sicher ist, dass das Ergebnis dieser Zeilen nicht vorhersehbar ist und sicher Quelle von Problemen.

In den Zeilen 41 und 42 die Zeiger sind mit den Adressen der Integer-Variablen initialisiert a und b. Seitdem die Drucke sind wiederholt.

Sehen Sie die Adressen der Zeiger nicht ändern, was erwartet wurde. Was sind ihre Inhalte ändern. Variables PA und PB erhalten die Adressen von A bzw. B. Beachten Sie, dass der Inhalt der Hände genau die Adresse Wert der Variablen A und B, die von der OS zu Beginn des Programms erhielten. Überprüfen Sie mit dem Drucke oben. Der Inhalt, auf den AP und BP wird den gleichen Inhalt und B, die nicht initialisiert wurde, oder Abfall. Doch im Gegensatz zu den vorherigen Schritt, jetzt die Zeiger auf gültige Adressen (Adressen von A und B) und dass der Inhalt von A und B sind Müll Speicher Zeiger nun Punkt für die Variablen, die bereits zugeteilt worden sind.

In den Zeilen 61 und 62 der Integer-Variablen sind mit den Werten 10 und 13, wiederholt neu initialisiert und Drucke.

Diesmal coteúdos von A und B sind nicht mehr junk. Die Werte sind richtig bekannt. Beachten Sie, dass es keine Änderung in der Adressierung von Variablen im Vergleich zu den vorherigen Schritten, nur die Werte.

Siehe auch, dass nach a und b initialisiert wurden, wies die Inhalte von AP und BP wurden ebenfalls automatisch geändert. Dies geschieht, weil pa pb und verweisen auf den gleichen Speicherbereich, der über die Variablen PA und PB eingesetzt. Dies bedeutet, dass der Inhalt durch einen spitzen Zeiger kann durch Veränderung der Inhalte der ursprünglichen Variablen geändert werden darauf hingewiesen, durch ihn. Und schließlich, Zeilen 81-97 zeigen, dass auch die Umkehrung gilt, dh die Änderung der Inhalte, auf die ein Zeiger, verändert automatisch den Inhalt der ursprünglichen Variablen wiesen sie darauf hin.

Es ist einfacher, dieses Denken in Sätzen in portugiesischer Sprache, als Sie sich den Code zu verstehen.

Denn jetzt ...

Dies war die grundlegende Operationen mit Zeigern. Es gibt immer noch interessante Dinge als Zeiger auf Funktionen gesehen werden, zum Beispiel, aber das ist weiter fortgeschritten als Thema. Nach dieser Serie, die über vier Planstellen geplant ist, siehe Referenzen, Ähnlichkeiten und Unterschiede zwischen Zeiger und Referenzen und schließlich Zeiger auf Funktionen.

Links

Kommentare

  • Fine zeigen die gleichen Artikel, wie ich hoffe, die proxximos Beiträge fortzusetzen.
  • Kein Problem!

    Wordpress hat ein Plugin namens WP-Syntax , die hinter den Kulissen GeSHi .

    Einmal installiert, können Sie Ihren Code in PRE-Tags setzen, indem das Attribut "Sprache" und "line". Die Sprache ist selbsterklärend und hat eine Liste von Sprachen in der Dokumentation und der Zeile ist der Startlinie.

    Die GeSHi kann auch verwendet werden, um diese Fähigkeit in Wikis hinzuzufügen.

    Tipp: Bevor Sie kopieren und fügen Sie den Code, ersetzen Sie alle Tabs durch 4 Leerzeichen. Dadurch wird der Code unabhängig von der Stil angewendet, um Tabs.

    Hugs
  • Fernando
    Dude, wie hast du mich lehren, wie man das macht Sie nach dem Code, wie Sie auf dem Laufenden?
    Inside a box insbesondere durch Kennzeichnung der Linien und Hervorhebung der Suchbegriffe der Sprache?
Blog-Kommentare powered by Disqus