Ich habe gelesen, wie der Zeiger in C ++ funktioniert, und ich habe versucht, ein wenig damit herumzuspielen, aber das Programm funktioniert nicht mehr.

#include <iostream>
using namespace std;

int main ()
{
  char a[] = "Hello";
  char * b = a;
  char ** c = &b;

  cout << *(b+1) << endl;
  //cout << **(c+2) << endl;
  return 0;
}

Wenn die kommentierte Zeile nicht kommentiert wird, funktioniert das Programm nicht mehr mit dem Fehlercode 0xC0000005. Mache ich etwas falsch oder ist das eine Art Fehler?

2
user3757605 29 Dez. 2015 im 19:49

5 Antworten

Beste Antwort

Hier:

char a[] = "Hello";
char * b = a;

Sie nutzen den Zerfall von Array zu Zeiger. Jetzt zeigt b auf a[0]. Das heißt, b enthält die Adresse von a[0]

Und dann

char ** c = &b;

c zeigt jetzt auf die Adresse von b, die selbst ein Zeiger ist. c enthält die Adresse von b, die die Adresse von a enthält (siehe, warum Leute jetzt Zeiger hassen?)

Wenn Sie von c aus auf a[0] zugreifen möchten, müssen Sie zuerst die Referenzierung aufheben:

*c

Was b ergibt, und dann müssen wir das dereferenzieren, um zu a[0] zurückzukehren:

*(*c)

Wenn Sie Zeigerarithmetik verwenden möchten, um auf a[1] zuzugreifen, möchten Sie b erhöhen, also:

* c + 1

Und jetzt haben wir die Adresse von a[1], und wenn wir das drucken wollen, müssen wir erneut dereferenzieren:

*(*c+1)

Sie haben den Fehler gemacht, die Adresse von b anstelle der Adresse von a[0] zu erhöhen, als Sie sagten:

**(c+2)

c enthielt die Adresse b, nicht a. Wenn Sie also diese Adresse erhöhen, führt dies zu undefiniertem Verhalten.

3
AndyG 29 Dez. 2015 im 17:00

c zeigt auf die Adresse von b im aktuellen Stapelrahmen.

c + 2 zeigt dank Zeigerarithmetik auf eine Position im Stapelrahmen.

*(c + 2) Sie greifen dann auf diesen Speicherort zu und nehmen dort nicht angegebene Bytes als Adresse.

**(c + 2) Jetzt versuchen Sie, auf die nicht angegebene Adresse zuzugreifen, und zum Glück stürzt sie ab.

3
StoryTeller - Unslander Monica 29 Dez. 2015 im 17:02

Okay, lass es uns noch einmal versuchen.

A ist ein Zeiger auf das erste Element im Array, in diesem Fall "H". c ist ein Zeiger auf die Adresse von b, die auch ein Zeiger auf das erste Element ist.

Wenn Sie c um 2 erhöhen, bewegen Sie diesen Zeiger um zwei vorwärts. Die Speicheradresse geht also um zwei vorwärts, aber c ist nur ein Zeiger auf a und nicht auf a selbst, sodass Sie sich in einem unbekannten Gebiet befinden. Stattdessen, was würde wahrscheinlich funktionieren (ungetestet):

cout<<*(*c+1)<<endl;

Diese Dereferenzierung c, so dass Sie b (oder a, dasselbe) erhalten, erhöhen Sie diesen Zeiger um 1, der im Array verbleibt, und dann dereferenzieren Sie erneut, um auf den Wert zuzugreifen.!

0
Untitled123 29 Dez. 2015 im 17:02

&b + 2 ist kein gültiger Zeiger.

Nehmen wir der Einfachheit halber an, dass ein Zeiger nur eine char breit ist (unser Speicher ist sehr, sehr klein).

Angenommen, a wird an der Adresse 10, b bei 20 und c bei 21 gespeichert.

char* b = a; ist dasselbe wie char* b = &a[0]; - es speichert die Position des ersten Elements (10) des Arrays in b.
char**c = &b speichert den Speicherort von b (20) in c.

Es sieht aus wie das:

  a                                       b    c
  10  11  12  13  14  15  16  17  18  19  20   21   22...
| H | e | l | l | o | 0 |   |   |   |   | 10 | 20 | 

Aus diesem Bild sollte ersichtlich sein, dass c + 2 22 ist, was keine gültige Adresse ist.
Dereferenzierung ist undefiniert und alles kann passieren - Ihr Absturz war einfach viel Glück.

Wenn Sie das erste l in "Hello" erwartet haben, befindet es sich bei a[2] (b[2]) (oder *(b + 2)) ((*c)[2]). (oder *(*c + 2)).

0
molbdnilo 29 Dez. 2015 im 17:21
char a[] = "Hello";
char * b = a;
char ** c = &b;

A und b zeigen auf den Anfang des char-Arrays mit "Hello" als Zeichen.

Beginnen wir also am Speicherort 0x100 Hallo ist gespeichert.

A ist ein Zeiger, in dem eine Adresse gespeichert wird.

A und b speichern beide diese Werte 0x100. Aber ihre Adressen sind etwas anderes. Nehmen wir an, die Adresse von a ist 0x200 und die Adresse von b ist 0x300.

C ist auch Zeiger. Es speichert also die Adresse von b. C speichert also die Adresse 0x300 als ihre Werte.

C + 1 = 0x304

C + 2 = 0x308

* c: Sie möchten auf den Wert zugreifen, der bei 0x300 gespeichert ist. Dies ist die Adresse von b.

* (c + 1): Sie möchten auf die Adresse 0x304 zugreifen

* (c + 2): Sie greifen dann auf 0x308 zu und nehmen dort nicht angegebene Bytes als Adresse.

** (c + 2): Dereferenzieren Sie die Adresse 0x308. Es kann die Adresse der Zeigervariablen sein oder nicht. Die Dereferenzierung kann also eine undefinierte Operation sein.

0
Abhishek Kumar 29 Dez. 2015 im 17:22