Werbung einblenden Werbung ausblenden


Home / Tutorials / Perl Handbuch / Referenzen

Was sind Referenzen?
Auf einen Zeiger zugreifen
Auf einen gesamten Array zugreifen
Einem Array Werte zuweisen
Alternative Möglichkeiten, um auf einzelne Elemente eines Arrays zuzugreifen
Auf einen gesamten Hash zugreifen
Einem Hash Werte zuweisen
Alternative Möglichkeiten, um auf einzelne Werte eines Hashs zuzugreifen
Auf Variablen zugreifen
Anonymous Arrays/-Hashs
Mehrdimensionale Arrays/-Hashs
Anzeigen, was der Zeiger zeigt - Die Funktion ref.
Arrays mit Zeigern auf anonymous Arrays/-Hashs

Was sind Referenzen?

Unter Referenzen versteht man Zeiger auf Variablen, Arrays, assoziative Arrays(Hashs) oder Subroutinen.
Die Frage ist, wozu sollen diese Referenzen gut sein. Die Antwort auf diese Frage kann pragmatisch ausfallen, weil Perl in der objektorientierten Programmierung mit Referenzen arbeitet (Objektorientierte Programmierung). Will man also objektorientiert programmieren oder Module verwenden, dann macht es Sinn, eine Vorstellung zu haben, welche Bedeutung Referenzen haben.
Wer dies intensiv studieren will, der kann zum Kapitel das Cgi.pm Modul hopsen. Dort wird ausführlich beschrieben wie ein Modul mit Referenzen arbeitet.
Im übrigen tauchen Referenzen immer wieder in diesem Handbuch auf. Auch bei XML auslesen mit Perl spielen sie eine entscheidende Rolle. Das heißt nicht, dass es ohne ein Verständnis von Referenzen nicht möglich ist, mit Perl XML Dokumente zu parsen oder mit Modulen zu arbeiten, aber es erleichtert das Verständnis.
Mit Referenzen kann man auch mehrdimensionale Arrays in Perl nachbauen, ja man kann sogar Konstrukte bauen, die noch weit komplexer sind. Einführend ein kleines Beispiel zur Verwendung von Referenzen. Komplexere Beispiele werden folgen. Normalerweise ist es nicht möglich, mehrere Arrays einem Array zuzuweisen. z.B.:

@banane=("Maier ","Müller ","Schulze ","Schmidt ");    
@pampelmuse=("machen ","jede ","Scheisse ","mit");
(@Namen,@Spruch)=(@banane,@pampelmuse);
print @Namen;

Man würde erwarten, dass in den Array @Namen die Namen und in den Array @Spruch der Spruch eingelesen wird. Das ist aber nicht der Fall. Der Array Namen kriegt alles, in dem @Spruch steht gar nichts mehr. Just try it!

@banane=("Maier ","Müller ","Schulze ","Schmidt "); 
@pampelmuse=("machen ","jede ","Scheisse ","mit");
(@Namen,@Spruch)=(@banane,@pampelmuse);
print @Spruch;

Was kommt hier raus? Nichts! Referenzen können hier die Erwartungen erfüllen, nämlich den Array @banane in den Array @Namen einlesen und den Array @pampelmuse in den Array @Spruch.
Siehe folgende Beispiele!

Auf einen Zeiger zugreifen
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $zeiger;

Et voilà!  Ein Zeiger auf den array @banane. Eine Referenz wird also mit dem Querbalken (backslash) gebildet. Was da rauskommt sieht so aus.
ARRAY(0x1765690)
Der Wert in der Klammer ist immer ein anderer. Davor steht aber immer ARRAY (Hash etc.). Der Zeiger zeigt auf den Speicherplatz des Rechners, wo der Array abgespeichert ist. Es stellt sich die Frage, wie die Werte des ursprünglichen Arrays über den Zeiger da wieder rausgefischt werden. Das heißt, wie dereferenziert man den Zeiger?

@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $$zeiger[0];

Ergebnis!
Es

Alles was man mit einem Array machen kann, kann man auch mit der Referenz auf den Array machen, wie die folgenden Beispiele zeigen.

Auf einen gesamten Array zugreifen
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
foreach (@$zeiger)
{
   print "$_ \n";    
}

Ergebnis!
Es ist der Wahnsinn

Hier werden alle Werte des @banane über den Zeiger ausgelesen.
Das heißt, will man auf den gesamten Array zugreifen, weil man eine Funktion ausführen will, die nur im Zusammenhang mit der Gesamtheit Sinn macht, dann verwendet man. @$zeiger;

Einem Array Werte zuweisen

Einem Array kann man über Referenzen auch Werte zuweisen.

@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
push(@$zeiger,".Nicht? ");
foreach (@$zeiger)
{
   print "$_ \n";
}

Ergebnis!
Es ist der Wahnsinn .Nicht?

Alternative Möglichkeiten, um auf einzelne Elemente eines Arrays zuzugreifen

Es gibt drei Möglichkeiten, um auf das erste Element des Arrays @banane zuzugreifen.
Dies zeigen die folgenden Beispiele.
In allen drei Fällen ist das Ergenis:
 
Es

@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $$zeiger[0];

erste Variante

@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $zeiger->[0];

zweite Variante

@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print ${$zeiger}[0];

dritte Variante
Um auf das erste Element des Arrays @banane zuzugreifen haben wir also drei Möglichkeiten:
$$zeiger[0];
${$zeiger}[0];
$zeiger->[0];

Mit assoziativen Arrays, Variablen und Subroutinen läuft das Verfahren völlig parallel.

%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $zeiger;

Was erhalten wir? HASH(0x1765678) - ein Zeiger auf den Speicherplatz ist, wo der Hash geparkt wurde.
Die Dereferenzierung erfolgt wie oben.

%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $$zeiger{'SPD'};

Ergebnis! 
Gerhard Schröder

Auf einen gesamten Hash zugreifen

Will man auf den ganzen Hash über eine Referenz zugreifen, sieht das so aus.

%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
foreach (keys(%$zeiger))
{
  print "Schlüssel ist $_ und Wert dazu $$zeiger{$_} \n";
}

Ergebnis!
Schlüssel ist  SPD und Wert dazu  Gerhard Schröder ect.

Einem Array Werte zuweisen

Wir können dem HASH auch über eine Referenz Werte zuweisen.

%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
$$zeiger{'PDS'}="Claudia Zimmer";
print $$zeiger{'PDS'};

Ergebnis! 
Claudia Zimmer

Alternative Möglichkeiten, um auf einzelne Werte eines Hashs zuzugreifen

Auch bei Hashes gibt es die schon bei Arrays beschriebenen Varianten des Zugriffs.
Um auf den Wert des ersten Schlüssels von %banane zuzugreifen haben wir folgende drei Möglichkeiten:

%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $zeiger->{'SPD'};

%banane=("SPD"=>"Gerhard Schröder","Grüne"=> "Joschka Fischer","CDU"=>"Angela Merkel","FDP"=>"Guido Westerwelle"); $zeiger=\%banane; print ${$zeiger}{'SPD'};

%banane=("SPD"=> "Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>"Angela Merkel","FDP"=>"Guido Westerwelle"); $zeiger=\%banane; print $$zeiger{'SPD'};

Wir erhalten also mutatis mutandis wieder die drei Möglichkeiten der Dereferenzierung, die wir bei Arrays schon hatten.
$$zeiger{'SPD'};
${$zeiger}{'SPD'};
$zeiger->{'SPD'};

Auf Variablen zugreifen

Mit Zeigern kann man natürlich auch auf Variablen zugreifen.(\$)

$banane="Die Kuh die auf der Weide steht, sie träumt von einem Salat so schön";
$zeiger=\$banane;
print "$zeiger \n";
print "$$zeiger \n";
Anonymous Array/Hash

Anonymous Arrays/Hashs sind Arrays bzw. Hashs, die keinen Namen haben und nur über einen Zeiger angesprochen werden können.

$zeiger=["Man ","muss ","das ","Chaos ","in ","sich ","tragen ","um ","einen ","Stern ","zu ","gebären "];
print $$zeiger[9];

Was kommt da raus? 
Stern

Wie deutlich zu sehen, hat der Array keinen Namen, sondern nur einen Zeiger. Das heißt, die einzelnen Elemente dieses Arrays können nur über einen Zeiger angesprochen werden. Anonymous Arrays haben keinen Namen und werden mit eckigen Klammern [ ] geschrieben.
Ähnlich sieht es bei den anonymous Hashs aus:

$zeiger={"Indien"=>"Neu Delhi","Iran"=>"Teheran","Russland"=>"Moskau","Frankreich"=>"Paris"};
print $$zeiger{'Iran'};

Was kommt da raus? 
Teheran

Wie auch hier deutlich zu erkennen ist, hat der anonymous Hash keinen Namen. Gebildet wird er mit derngeschweiften Klammern { }.

Mehrdimensionale Arrays

Schreiten wir voran zum grossen Show down: zur Bildung mehrdimensionaler Arrays über Referenzen.

@menue=(["Kartoffeln","Sauerbraten","Preiselbeeren"],["Yoghurt","Obst"],
["Cognac","Apfelsaft","Kaffee"]); 
print $menue[1][1]; 

Das ist jetzt nicht mehr so einfach? Ich verrate es. Obst kommt raus. $menue[1] ist ein Zeiger auf einen Array, genau wie $menue[0] und $menue[2]. Von dem angesprochenen Array (Yoghurt, Obst), suchen wir das Element mit dem Index 1, also das Obst.
Zwei weitere mögliche Schreibweisen (bereits oben beschrieben):

@menue=(["Kartoffeln","Sauerbraten","Preiselbeeren"],["Yoghurt","Obst"],
["Cognac","Apfelsaft","Kaffee"]);
print ${$menue[1]}[1];
@menue=(["Kartoffeln","Sauerbraten", "Preiselbeeren"],["Yoghurt","Obst"],
["Cognac","Apfelsaft","Kaffee"]); print $menue[1]->[1];

Mit Hashs sieht dies folgendermaßen aus:

@menue=(
{'Maier'=>'Ernst','Ehmann'=>'Andres','Müller'=>'Peter'},
{'Maier'=>'030-454567','Ehmann'=>'030-47301388','Müller'=>'030-45345476'},
{'Maier'=>'Briefmarken sammeln','Ehmann'=>'dösen','Müller'=>'mit dem grossen Zeh wackeln'}
);
print $menue[2]{'Müller'};

Wenn es den Müller nur einmal gäbe, wäre es einfach. Den gibt es aber dreimal. Also raten kann man nicht. Es kommt raus:  mit dem großen Zeh wackeln. $menue[2] ist ein Zeiger auf den dritten Array, der die Hobbys abspeichert. Davon wollen wir das Hobby mit dem Schlüssel Müller haben.
In den alternativen Schreibweisen, sieht das dann so aus:

@menue=(
{'Maier'=>'Ernst','Ehmann'=>'Andres','Müller'=>'Peter'},
{'Maier'=>'030-454567','Ehmann'=>'030-47301388','Müller'=>'030-45345476'},
{'Maier'=>'Briefmarken sammeln','Ehmann'=>'dösen','Müller'=>'mit dem grossen Zeh wackeln'}
);
print ${$menue[2]}{'Müller'};
@menue=( {'Maier'=>'Ernst','Ehmann'=>'Andres','Müller'=>'Peter'}, {'Maier'=>'030-454567','Ehmann'=>'030-47301388','Müller'=>'030-45345476'}, {'Maier'=>'Briefmarken sammeln','Ehmann'=>'dösen','Müller'=>'mit dem grossen Zeh wackeln'} ); print $menue[2]->{'Müller'};

Im eigentlichen Sinne wird kein zweidimensionaler Array gebildet, da der zweite Array keine Untereinteilung des ersten ist. Mit diesem Verfahren lässt sich aber leicht das gleiche erreichen. In letzter Konsequenz ist dieser Ansatz leistungsfähiger, insbesondere auch deswegen, weil man Konstrukte bauen kann, bei denen alle möglichen Typen von Variablen, Arrays, Hashs, Skalarvariablen miteinander verknüpft sein können.

@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Der Zauberg"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Goethe wurde ". $banane[0]{'Goethe'}." in ".$banane[3][0].
" geboren. Ein Werk der Klassik ist ". $banane[1][0];

Was kommt raus?
Goethe wurde 1749 in Frankfurt am Main geboren. Ein Werk der Klassik ist  Torquato Tasso 

In den zwei alternativen Schreibweisen sieht das dann so aus:

@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Der Zauberg"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Goethe wurde ". ${$banane[0]}{'Goethe'}." in ".${$banane[3]}[0].
" geboren. Ein Werk der Klassik ist ". ${$banane[1]}[0];
@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Der Zauberg"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Goethe wurde ". $banane[0]->{'Goethe'}." in ".$banane[3]->[0].
" geboren. Ein Werk der Klassik ist ". $banane[1]->[0];
Anzeigen, auf was der Zeiger zeigt - Die Funktion ref.

Komplizierter wird es, wenn man alle Werte innerhalb einer foreach Schleife auslesen will. Da Arrays anders aufgeknackt werden als Hashs braucht man eine Möglichkeit um herauszufinden, auf was der Zeiger eigentlich zeigt. Das passiert mit der Funktion ref.

@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Faust"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Zuerst kommt ein  ". ref($banane[0]). " dann ein ". ref($banane[1]). 
" dann ein ". ref($banane[2]) . " und schluss endlich ein ". ref($banane[3]);

Der Skript zeigt dann "Zuerst kommt ein HASH dann ein ARRAY dann ein HASH und schluss endlich ein ARRAY".
Beispielhaft soll hier einmal der ganze Array @banane ausgelesen werden. In einem real live Beispiel, müsste man wohl dafür sorgen, dass das Konstrukt an sich geeignet ist.

@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Faust"],
);

foreach $himbeere(@banane)
{
        if(HASH eq ref($himbeere))
         {
                 foreach (keys(%$himbeere))
                  {
                      print "$_ wurde ${$himbeere}{$_} geboren \n";
                  }
          }

         if (ARRAY eq ref($himbeere))
          {
                   foreach (@$himbeere)
                   {
                       print "$_ ist ein wichtiges Werk der deutschen Klassik \n";
                   }
          }
}
Arrays mit Zeigern auf anonymous Arrays/-Hashs

Man kann auch einen Array basteln, der nichts anderes enthält als Zeiger, die wiederum auf anonyme Arrays bzw. anonyme Hashs zeigen. Das machen wir jetzt noch!

@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print $superbanane[0];

Die $superbanane[0] ist jetzt ein Zeiger auf den Array @banane.
Will man jetzt z.B. auf die Kapern und auf Stuttgart zugreifen, dann sieht das so aus.

@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print $$superbanane[0][0][2]."\n";
print $$superbanane[1][0]{'Baden-Württemberg'};

In der alternativen Schreibweise sieht das so aus.

@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print ${${$superbanane[0]}[0]}[2]. "\n";
print ${${$superbanane[1]}[0]}{'Baden-Württemberg'}."\n";

Das am besten nochmal step by step.
$superbanane[0] => ist der Zeiger auf den Array @banane.
${$superbanane[0]}[0] => ist der Zeiger auf das den ersten anonymen Array von @banane,
${${$superbanane[0]}[0]}[2] => ist das dritte Element des ersten anonymen Arrays, der in dem Array @banane steckt.

Und dann gibt es, wie oben beschrieben, noch diese Schreibweise.

@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print $superbanane[0]->[0]->[2] . "\n";
print $superbanane[1]->[0]->{'Baden-Württemberg'}."\n";

Was haben wir gelernt? Perl hat zwar keine mehrdimensionalen Arrays im eigentlichen Sinne, aber mit Referenzen lassen sich diese nachbauen, bzw. es ist möglich sogar Konstrukte beliebiger Komplexität zusammenzubauen. Gebraucht werden Referenzen insbesondere anonyme Hashs und anonyme Arrays in der objektorientierten Programmierung. Darüber hinaus arbeitet Perl intern sehr oft mit Referenzen. Die Aussage allerdings, die man manchmal antrifft, dass man Perl ohne ein Verständnis von Referenzen nicht nutzen kann, ist nicht zutreffend.

vorhergehendes Kapitel