Zeiger vs. Referenz

angelsfall

angelsfall

Routinier
Hallo,

schon lange versuche ich mir per Google und Wiki klar zu machen, was der Unterschied zwischen einer Referenz und einem Zeiger ist, jedoch ohne fruchtbaren Erfolg.
Laut Wiki ist ein Zeiger eine spezielle Form der Referenz, der dereferenziert werden kann. Damit bin ich aber nicht glücklich, denn unter Perl kann ich ja schließlich auch eine Referenz dereferenzieren. Sowohl Zeiger als auch Referenz beinhalten die Speicheradresse der Variable, auf die sie zeigen. Und beide lassen sich dereferenzieren. Liegt der Unterschied nur in den Definitionen innerhalb der Programmiersprachen?
Wäre schon, wenn mir jemand eine akkurate Definition geben kann. Dankeschön!
 
Auf Zeiger kannst du auf jeden Fall immer Zeigerarithmetik anwenden. Wenn du wo hinzeigst, wo du nicht hinzeigen darfst, tja pech gehabt...

Bei Referenzen wird dir das so nicht passieren, den sie können nur auf gültige Objekte zeigen. Ob Referenzen auch explizit zugewiesen werden können hängt von der Sprache ab. Bei Java ist das ja zum Beispiel gang und gebe. Ich denke man kann generell sagen, das Referenzen implizite Zeiger sind, steckt ja auch noch meist ein Garbage Collector dahinter, der dir die Objekte aus dem Speicher entfernt, sobald keine Referenz mehr vorhanden ist.
 
Vielleicht noch eine etwas "bildliche" Erklärung zu der von MadJoe.
Ein Zeiger zeigt (wie der Name ja so schon sagt) auf eine andere Variable bzw. Speicherbereich. Eine Referenz erzeugt quasi einen zweiten Namen für den gleichen Speicherbereich.

Wenn du also z.B. einen int foo hast und einen Pointer x anlegst dann zweigt dieser auf den Speicherbereich von foo. In x ist also nur die Andresse gespeichert und du mußt diese dereferenziert um an den Inhalt zu kommen:
foo = 5;
*x = 5;
Legst du eine Referenz y an, dann hast du nachher im Prinzip zwei Variablen die gleichberechtigt auf den gleichen Inhalt verweisen. Du kannst also mit beiden genau gleich arbeiten:
foo = 5;
y = 5;

Wenn es beide Möglichkeiten gibt, würde ich sagen ist die Referenz in 90% aller Fälle die sinnvollere Wahl, da man mit einer Referenz eben genauso normal umgehen kann wie mit der ursprünglichen Variablen.
 
Danke für eure Antworten.
pinky schrieb:
Vielleicht noch eine etwas "bildliche" Erklärung zu der von MadJoe.
Ein Zeiger zeigt (wie der Name ja so schon sagt) auf eine andere Variable bzw. Speicherbereich. Eine Referenz erzeugt quasi einen zweiten Namen für den gleichen Speicherbereich.
Das Problem ist, dass ich mir das auch immer versucht habe so klar zu machen, wie du es beschrieben hast, jedoch wenn ich nochmal drüber nachdenke, ist das für mich nach dieser Definition genau das Gleiche. Die Referenz ist praktisch nur ein Alias für den Originalen Variablennamen, aber im Endeffekt beinhalten doch sowohl Zeiger als auch Referenz die Adresse der Variable, auf die sie verweisen.
 
Ja im Endeffekt geht es ja wirklich nur um das unterschiedliche Handling für den Programmierer, also jetzt gerade bei C++.

Den eines kann man nicht, die interne Funktionsweise pauschal vergleichen, das läuft bei C++ z.B. ganz anders ab als bei Perl/PHP oder als bei Java.

Wenn ich das Beispiel PHP hernehme, so ist es wirklich "nur" ein zweiter Name für eine Variable, denn dort hast du mehr oder weniger ein großes Array in dem Symbole (Variablennamen, Funktionen etc.) und im besten Fall eine dazugehörige "Ablage" drinnen stehen. Das liegt auch daran, dass ja PHP eine Skriptsprache ist und die Umgebung selbst in C++ geschrieben ist.

(Sorry für das lange gerede, aber ich mach mir halt meisten wirklich gedanken, wie sowas intern alles abläuft!)

Grüße Joe
 
angelsfall schrieb:
Die Referenz ist praktisch nur ein Alias für den Originalen Variablennamen, aber im Endeffekt beinhalten doch sowohl Zeiger als auch Referenz die Adresse der Variable, auf die sie verweisen.

Ja, eine Referenz könnte man auch als Alias bezeichnen. Ob und wie eine Referenz nachher zu dem Inhalt der ursprünglichen Variable findet ist eine Frage die für dich nichtmehr sichtbar ist. Intern wird das sicher über irgendwelche Adressen passieren (ist aber sicher Sprachabhängig und vielleicht sogar teilweise Kompilerabhängig). Für dich hat aber eine Referenz keinen Unterschied zum ursprünglichen Variablennamen (man könnte es auch als eine Art "information-hiding" bezeichnen).
Dieses kleine Beispiel macht es vielleicht etwas anschaulicher:
Code:
#include <iostream>

void pointer (int *x)
{
    std::cout << "pointer: x = " << x << "; adresse von x = " << &x << std::endl;
}

void referenz (int &x)
{
    std::cout << "referenz: x = " << x << "; adresse von x = " << &x << std::endl;
}

int main()
{
    int x = 5;

    std::cout << "original: x = " << x << "; adresse von x = " << &x << std::endl;
    pointer (&x);
    referenz (x);

    return 0;
}

Die Ausgabe:
Code:
original: x = 5; adresse von x = 0xbfffdd54
pointer: x = 0xbfffdd54; adresse von x = 0xbfffdd40
referenz: x = 5; adresse von x = 0xbfffdd54

wie du siehst gibt es für den Anwender (hier Programmierer) keinen Unterschied zu Original und Referenz, die Andresse ist gleich und der Wert ist gleich. Ein Pointer dagegen hat eine eigene Adresse und beinhaltet als Wert die Adresse des Originals. D.h. während ein Pointer wirklich was anderes ist als das Original ist eine Referenz nichtmehr vom Original zu unterscheiden, quasi zwei Namen für den gleiche Speicherplatz.


Hoffe das macht es etwas klarer...
 
Zuletzt bearbeitet:
hmmm... ich hab mir mal diesen thread und andere quellen zum thema im netz angeschaut und naja der technische unterschied zwischen pointern und references ist mir nun klar... vor allem nach der lektüre meines vorgängers ist mir die unterschiedliche behandlung durch den compiler klar... aber wo liegt denn nun der unterschied von seiten des programmierers??? also konkret was kann ich mit zeigern machen was mit referenzen nicht geht und umgekehrt?!?!?
 
du kannst zeiger in C verwenden, referenzen nicht :D

mit zeigern kannst du rechnen, mit referenzen nicht...

auf bald
oenone
 
osugi schrieb:
aber wo liegt denn nun der unterschied von seiten des programmierers??? also konkret was kann ich mit zeigern machen was mit referenzen nicht geht und umgekehrt?!?!?

Da gibt es einiges, von kleineren bis zu fundamentalen Unterschieden, z.B.:
Wenn man Daten innerhalb einer Funktion ändern möchte, muss man die Argumente per "Referenz" (und nicht per value) übergeben, das geht entweder via Zeigern oder Referenz, was nachher in der Benutzung sich durch eine unterschiedliche Syntax widerspiegelt:
Code:
void swap(int& x, int& y){...} //Übergabe per Referenz
void swap(int* x, int* y){...} //Übergabe über Zeiger
int main()
{
int x = 1, y = 2;
swap(x,y); //Aufruf bei Übergabe als Referenz
swap(&x,&y); //Aufruf bei Übergabe per Pointern
...
}
Getreu dem Prinzip das eine Referenz ein Alias darstellt.
Das heißt im Aufruf unterscheidet sich eine Übergabe per Referenz (als wirkliche Referenz) nicht von der per value, daher benutzt man Übergabe per Referenz oft, wenn man entweder die Daten ändern muss oder ein Übergabe per value aus Geschwindigkeitsgründen ausfällt (Aufruf von Copy-Konstruktor, Destruktor usw., sehr teuer, wenn Du eine 10000x10000 Matrix übergibst).

Fundamentaler wird es, wenn man zur dynamischen Speicherverwaltung übergeht, hier mußt du Zeiger verwenden, um dir was vom Freispeicher zu besorgen, das geht nicht mit Referenzen, da die Adresse einer Referenz immer die des Alias ist (s. pinky), also zur Kompilierzeit bei einer dynamischen Größe nicht bekannt sein kann, daher brauchst du zumindestens einen Zeiger (dessen Adresse zur Kompilierzeit ja bekannt ist).
Hoffe, das hilft ein wenig.
 
Rechnen mit Referenzen...

Hallo ihr :oldman
Ich bin neu hier aber will mal meinen Senf zum Thema abgeben :D

Also dass man mit Referenzen nicht RECHNEN könnte, muss ich vielleicht in sofern zurückweisen, dass eine Referenz zwar nicht mit sich selbst, aber dennoch mit der Variable rechnet, auf die Referenziert wird! Habe ich schon selbst probiert.

In C kann man keine Referenzen machen? Also ich kenne es so, dass es in C++ Referenzen gibt, ob in normalem C weis ich natürlich nicht.

Aber RECHNEN kann man. Ich kann zum Beispiel folgendes tun

Code:
 #include <iostream>
 using namespace std;

 int main()
{
 int i = 5;
 int& ref_i = i;

 cout << "Wert von i: " << i << endl;
 ref_i += 10;
 cout << "Wert von i: " << i << endl;

 return 0;
}

Man wird zu dem Ergebnis kommen, dass i = 15 ist :rtfm: :))

Unterschied zwischen Referenz und Zeiger ist programmiertechnisch eigentlich nur der Umgang gegenüber mit Zeigern.
 
Hallo,

ich schau mir bei solchen Fragen immer gerne die C++ FAQ an:
http://www.parashift.com/c++-faq-lite/references.html

Was hier noch keiner erwaehnt hat, aber vielleicht ist es auch ein Verstaendnisfehler von mir: Bei Uebergabe eines Zeigers kann ich schnell eine Speicherbereichsverletzung herbeifuehren, wenn ich eine falsche Zeigerarithmetik mache
Code:
int foo (int* p) {
    p += 10;
}
Wer weiss schon, wo p nun hinzeigt? Ich denke, mit einer Referenz macht man solche Fehler nicht ganz so schnell.
 
Zeigererithmetik

Es ist richtig was Du gesagt hast rikola.

Wenn man den kleinen Stern vergisst, kann man einen anderen Speicherbereich erwischen. Danach kann es vorkommen, dass es Abstürze gibt :)) Zeiger sind also GEFÄHRLICHER als Referenzen!
Hier kann mehr Unfug gemacht werden.

Ich habe in diesem Zusammenhang noch etwas anderes gefunden!
Und zwar braucht man Referenzen bei Standardkopierkonstruktoren!

Ich weis nicht in wiefern ihr das Problem bei FLACHEN KOPIEN kennt.

Ich lege eine Klasse an mit einem Zeiger, übergebe die Klasse einer anderen, unabhängigen Funktion. Die Werte werden gemäß BY VALUE kopiert.
Nur beim Zeiger tut sich nix! Der Zeiger reagiert hier wie bei einer Referenz: Ändere ich hier den Wert, ändere ich nicht eine Kopie sondern das Original aus der Klasse.

Um diesem Effekt vorzubeugen, kann ich im Standardkopierkonstruktur sagen, dass ein NEUER Zeiger erstellt werden soll, IHM den Wert aus der alten Klasse zuweisen und damit rumhantieren, ohne dass was in der Originalklasse passiert.

Beispiel:

Code:
#include <iostream>

using namespace std;

class CTest
{
public:
  int x;
  int *zeiger;
  void Zeige_X();
  void Zeige_zeiger();
  CTest();
  CTest(const CTest& k3);
};

CTest::CTest(const CTest& k3)
{
  zeiger = new int;
  *zeiger = k3.x;
  x = k3.x;
}

void kopiereklasse(CTest k2);

CTest::CTest():
  x(5), zeiger(&x)
{

}

void CTest::Zeige_X()
{
  cout << "Wert von X: " << x << endl;
  cout << "Adresse von X: " << &x << endl;
}

void CTest::Zeige_zeiger()
{
  cout << "Wert von zeiger: " << zeiger << endl;
  cout << "Adresse von zeiger: " << &zeiger << endl;
  cout << "Wert auf den zeiger zeigt: "<< *zeiger << endl;
}

void kopiereklasse(CTest k2)
{
  *k2.zeiger = 10;
  cout << endl;
  cout << "In der Funktion: " << endl;
  cout << "Wert von x: "<< k2.x << endl;
  cout << "Adresse von x: " << &k2.x << endl;
  cout << "Wert von zeiger: " << k2.zeiger << endl;
  cout << "Adresse von zeiger: " << &k2.zeiger << endl;
  cout << "Wert auf den zeiger zeigt: " << *k2.zeiger << endl;
  cout << endl;
}


int main()
{
  CTest k;
  cout << "1" << endl;
  k.Zeige_X();
  k.Zeige_zeiger();

  kopiereklasse(k);
  cout << endl;
  cout << "2";
  k.Zeige_X();
  k.Zeige_zeiger();

  return 0;
}

Ich gebe zu es ist ein bisschen langatmig.

Aber hier die wichtige Stelle:

Code:
  CTest(const CTest& k3);

und die Implementierung:

Code:
CTest::CTest(const CTest& k3)
{
  zeiger = new int;
  *zeiger = k3.x;
  x = k3.x;
}

Dem Kopierkonstruktur wird eine konstante REFERENZ der Klasse übergeben.

Nur mal als Beispiel WO man das brauchen kann :))

Dieser Code ist auch nur als Beispiel gedacht...:)
 

Ähnliche Themen

Problem mit Apache2 + MySQL Server

Zurück
Oben