2010-10-24 3 views
33

Ich bin ein absoluter Neuling für C, und während meiner Universitätsarbeit bin ich auf Kommentare in Code gestoßen, die sich oft auf das Aufheben der Referenz auf einen NULL-Zeiger beziehen. Ich habe einen Hintergrund in C#, ich bin davon ausgegangen, dass dies ähnlich wie eine "NullReferenceException", die Sie in .Net bekommen, aber jetzt habe ich ernsthafte Zweifel.Was genau bedeutet "einen NULL-Zeiger de-referenzieren"?

Kann mir bitte jemand in Laiensprache genau erklären, was das ist und warum es schlecht ist?

+0

Denken Sie daran, dass dies zu undefiniertem Verhalten führt. Sie erhalten keine Ausnahmen oder irgendetwas in C oder C++. – GManNickG

+0

Sie können einen Beispielcode eingeben. Es scheint, dass Leute (einschließlich mir) nicht bekommen, was Sie versuchen zu fragen. –

+0

Keine Notwendigkeit für Code (es gibt keine) - Dies ist ein konzeptionelles Problem, das ich habe, versuchen, den Kopf über die Terminologie der "Dereferenzierung" zu bekommen und warum ich mich darum kümmern sollte. – Ash

Antwort

47

A NULL Zeiger zeigt auf Speicher, der nicht existiert. Dies kann die Adresse 0x00000000 oder ein anderer implementierungsdefinierter Wert sein (solange es keine echte Adresse sein kann). Dereferenzieren heißt, versuchen, auf alles zuzugreifen, auf das der Zeiger zeigt. Der Operator ist der * Dereferenzierungsoperator:

int a, b, c; // some integers 
int *pi;  // a pointer to an integer 

a = 5; 
pi = &a; // pi points to a 
b = *pi; // b is now 5 
pi = NULL; 
c = *pi; // this is a NULL pointer dereference 

Dies ist genau das gleiche wie ein NullReferenceException in C#, mit der Ausnahme, dass Zeiger in C zu jedem Datenobjekt zeigen können, auch Elemente innerhalb eines Arrays.

+8

@Ash: Ein Zeiger enthält eine Speicheradresse, die auf etwas verweist. Um auf das mit dieser Speicheradresse * referenzierte * zuzugreifen, müssen Sie * die Speicheradresse * de-referenzieren. –

+0

@Ash, die In silico sagte, aber wenn Sie den Verweis auf den Wert, der an der Speicheradresse gespeichert ist. Versuche es. Do int p; printf ("% p \ n", &p); es sollte eine Adresse ausgeben. Wenn Sie keinen Zeiger (* var) erstellen, um die Adresse zu erhalten, die Sie verwenden & var – Matt

+0

@Greg Wie wäre es, wenn Sie 'char * foo = NULL und dann verwenden & foo? – Bionix1441

-1

Von wiki

Ein Null-Zeiger einen reservierten Wert hat, oft aber nicht unbedingt den Wert Null, was darauf hinweist, dass es zu keinem Objekt verweist
..

Da ein Null-wertige Zeiger tut sich nicht auf ein sinnvolles Objekt bezieht, führt ein Versuch, einen Nullzeiger zu dereferenzieren, normalerweise zu einem Laufzeitfehler.

int val =1; 
int *p = NULL; 
*p = val; // Whooosh!!!! 
+0

Danke für Ihre Antwort, ich bin ok mit was ein NULL-Zeiger war, ich war einfach nicht sicher, wie die "Dereferenzierung" in das Schema der Dinge passt . – Ash

2

Es bedeutet

myclass *p = NULL; 
*p = ...; // illegal: dereferencing NULL pointer 
... = *p; // illegal: dereferencing NULL pointer 
p->meth(); // illegal: equivalent to (*p).meth(), which is dereferencing NULL pointer 

myclass *p = /* some legal, non-NULL pointer */; 
*p = ...; // Ok 
... = *p; // Ok 
p->meth(); // Ok, if myclass::meth() exists 

im Grunde fast alles (*p) einhergehen oder implizit (*p) beteiligt, z.B. p->..., die eine Kurzschrift für (*p). ... ist; außer Zeigerdeklaration.

+0

Er markiert seine Frage als C nicht C++ – GWW

+2

@GWW: und es hat genau dieselbe Semantik in C und in C++, außer vielleicht, dass C keine Costum-Klasse hat. –

+0

Ist 'p-> meth()' nur eine Kurzform für '(* p) .meth()', mit der Letzteres ist in C und C++ verfügbar? – Arun

0

Zitiert aus wikipedia:

Ein Zeiger eine Stelle in Speicherreferenzen und Erhalten der Wert an der Stelle ein Zeiger bezeichnet ist bekannt als der Zeiger dereferenzieren.

Die Dereferenzierung erfolgt durch Anwenden des Operators unary * auf den Zeiger.

int x = 5; 
int * p;  // pointer declaration 
p = &x;  // pointer assignment 
*p = 7;  // pointer dereferencing, example 1 
int y = *p; // pointer dereferencing, example 2 

„dereferenzieren ein NULL-Zeiger“ bedeutet, wenn die Durchführung *pp ist NULL

20

Dereferenzieren bedeutet nur den Speicherwert an einer gegebenen Adresse zu lesen. Also, wenn Sie einen Zeiger auf etwas haben, zu dereferenzieren den Zeiger bedeutet, zu lesen oder schreiben Sie die Daten, auf die der Zeiger zeigt.

In C ist der unäre Operator * der Dereferenzierungsoperator.Wenn x ein Zeiger ist, dann zeigt *x was x zeigt. Der unäre &-Operator ist die -Adresse des Operators. Wenn x irgendetwas ist, dann ist &x die Adresse, unter der x im Speicher gespeichert ist. Die * und & Operatoren sind invers zueinander sind: wenn x keine Daten vorhanden sind, und y ist jeder Zeiger, dann diese Gleichungen sind immer wahr:

*(&x) == x 
&(*y) == y 

Ein Null-Zeiger ist ein Zeiger, der nicht auf einen beliebigen gültigen nicht zeigen Daten (aber es ist nicht der einzige solche Zeiger). Der C-Standard besagt, dass es undefined Verhalten ist, einen Nullzeiger zu dereferenzieren. Das bedeutet, dass absolut alles passieren kann: Das Programm könnte abstürzen, es könnte weiter leise arbeiten, oder es könnte Ihre Festplatte löschen (obwohl das eher unwahrscheinlich ist).

In den meisten Implementierungen erhalten Sie einen "Segmentierungsfehler" oder "Zugriffsverletzung", wenn Sie dies versuchen, was fast immer dazu führt, dass Ihr Programm vom Betriebssystem beendet wird. Hier ist eine Möglichkeit ein Null-Zeiger dereferenziert werden könnte:

int *x = NULL; // x is a null pointer 
int y = *x;  // CRASH: dereference x, trying to read it 
*x = 0;   // CRASH: dereference x, trying to write it 

Und ja, ein Null-Zeiger-Dereferenzierung ist so ziemlich genau wie ein NullReferenceException in C# (oder ein NullPointerException in Java), mit der Ausnahme, dass das Langauge Standard ist ein wenig mehr hilfreich hier. In C# hat das Dereferenzieren einer Nullreferenz ein wohldefiniertes Verhalten: Es wird immer eine NullReferenceException ausgelöst. Es gibt keine Möglichkeit, dass Ihr Programm ruhig weiterarbeiten oder Ihre Festplatte wie in C löschen kann (es sei denn, es gibt einen Fehler in der Sprachlaufzeit, aber auch das ist unglaublich unwahrscheinlich).