ein Kapitel zurück                                           ein Kapitel weiter

In Perl sind die Referenzen nicht mit denen in der Sprache C gleichzusetzen. In Perl können Referenzen nur auf definierten Variablen verweisen und nicht in irgendeinem Adressraum. Ein simples Beispiel des Einsatzes von Referenzen.......

$var=5;
$referenz=\$var;

Zuerst definieren wir eine Variable $var und geben ihr den Wert 5. Anschließend übergeben wir der Variablen $referenz die Adresse der Variablen $var. Die können sie Anhand des Adressoperators '\' (Backslash) erkennen. Somit ist $referenz die Referenz auf der Variablen $var. Im nächsten Programm demostiere ich Ihnen diese Aussage...........

#!/usr/bin/perl -w

$var=5;
$referenz=\$var;
print $referenz , "\n";  #Referenz von $var Ausgabe:Adresse $var
print \$var, "\n";       # Ausgabe: Adresse von $var


In diesem Beispiel wird 2x die selbe Adresse von der Variablen $var ausgegeben. Wie schon in der Programmiersprache C z.B. setzt sich eine Variable immer aus dem Namen, den Wert und der Adresse im Speicher zusammen. Durch das Backslash in der zweiten print-Anweisung sorgen wir dafür das die Adresse von $var ausgegeben wird.
Die Ausgabe von $referenz stellt dagegen die Adresse da auf die sie verwiesen wurde. In diesem Fall $var. Wenn sie die Adresse des Referenzen $referenz selber erfahren wollen müssen sie nur den Adressoperator '\' davor setzen.................


print \$referenz , "\n";

Genauso wie eben funktioniert dies auch bei Arrays und Hashs.........

#!/usr/bin/perl -w

$var=5;
@array= (3,5,3,90,2,4);
%hash = ("Name" => "Udo", "Vorname" => "Lindenberg");

$referenz=\$var;
print "Adresse von der Variablen var auf die referenz verweist : ";
print $referenz .":". \$var, "\n"#Referenz von $var Ausgabe:Adresse $var

$referenz=\@array;
print "Adresse vom Array array auf die referenz verweist : ";
print $referenz .":". \@array, "\n"#Referenz von @array Ausgabe:Adresse @array

$referenz=\%hash;
print "Adresse vom Hash hash auf die referenz verweist : ";
print $referenz .":". \%hash, "\n"#Referenz von %hash Ausgabe:Adresse %hash


An diesem Beispiel können sie erkennen wir Referenzieren immer gleich.

Nun wollen wir uns doch mal ansehen wir auf den Wert zugreifen auf dessen Adresse unser Referenz verwiesen wurde.........

#!/usr/bin/perl -w

$var=5;

$referenz=\$var;

print "Die Adresse von referenz selber : " . \$referenz . "\n";
print "Die Adresse auf die referenz verweist : " . $referenz . "\n";
print "Der Wert der Adresse auf die referenz verweist : " . ${$referenz} . "\n\n";

print "Die Adresse von var : " . \$var . "\n";
print "Der Wert von var : " . $var . "\n";


In diesem Beispiel haben sie also gesehen wie sie auf den Wert von Referenzen zugreifen können auf diese sie verweisen. Der Zugriff auf den Wert des Referenzen erfolgt also einfach zwischen geschweifte Klammern. Man spricht beim Zugriff auf eine Referenz von der Dereferenzierung. Nun sehen wir uns mal an was wir hier Derefenzieren können..........

#!/usr/bin/perl -w

$var=5;

$referenz=\$var;

print "Der Wert auf den referenz verweist : " . ${$referenz} . "\n";
print "Der Wert von var : " . $var . "\n\n";

${$referenz}*=2;      #Dereferenzierung

print "Der Wert auf den referenz verweist : " . ${$referenz} . "\n";
print "Der Wert von var : " . $var . "\n";


Hier Derefernzieren wir den Wert auf den $referenz zeigt. Was logischerweise auch nach sich zieht das der Wert von $var sich ebenfalls verändert da ja $var und ${$referenz} das selbe Objekt beinhalten.

Das ganze nun mit einem Array und einem Hash...........

#!/usr/bin/perl -w

@array = (33,66,99);
%hash = ("Name" => "Becker", "Vorname" => "Boris");

$ref1=\@array;     #ref1 verweist array
$ref2=\%hash;      #ref2 verweist hash

print "@{$ref1}" , "\n";
print %{$ref2} , "\n";


Wenn sie nun z.B in einem Array auf ein einzelnes Element zugreifen wollen so benötigen sie nur den Index a la...........

@{$ref1}[1]

Somit würden sie im oberen Beispiel auf den Wert 99 zugreifen. Um bei einem Hash auf ein spezielles Element zuzugreifen gehen wir ähnlich vor und benutzen statt des Indexes einfach den Schlüssel.........

%{$ref2}{'Name'}    

In diesem Fall würden wir auf den Nachnamen Becker zugreifen. Nun zugegeben diese beiden Schreibweisen....

@{$ref1}[1]
%{$ref2}{'Nachname'}

...sehen nicht gerade sehr Lese.-und Schreibfreundlich aus. Daher haben die Perl-Entwickler auch dafür gesorgt diese Schreibweise zu vereinfachen. Und aus.........

@{$ref1}       .....wird.........      @$ref1
@{$ref1}[1]   ......wird.........      $ref->[1]
%{$ref2}      ......wird........       %$ref2
%{$ref2}{'Nachname'} ......wird....... $ref2->{'Nachname'}


Das ließt sich doch schon viel besser, oder? Das ganze wollen wir anhand unseres Programms anschauen...........

#!/usr/bin/perl -w

@array = (33,66,99);
%hash = ("Name" => "Becker", "Vorname" => "Boris");

$ref1=\@array;      #ref1 verweist array
$ref2=\%hash;       #ref2 verweist hash

print "@$ref1" , "\n";
print %$ref2 , "\n";

print $ref1->[2];#99
print $ref2->{'Name'};#Becker


Mit Referenzen haben wir also die Möglichkeiten komplexere Datenstrukturen zu erstellen.......

Array von Arrays
Nehmen wir mal an wir haben mehrere Arrays mit Werten und wollen diese an einer Funktion übergeben............

@array1 = (22,55,11);
@array2 = (4,7,1);
@array3 = (99,2,7);

Nun hätten wir die Möglichkeit alle drei Arrays an die Funktion mittels.....

func(\@array1, \@array2, \@array3);

....übergeben. Es geht aber auch einfacher. Wir machen einfach daraus ein Array aus Arrays........

@array1 = (22,55,11);
@array2 = (4,7,1);
@array3 = (99,2,7);
@allarray = (\@array1, \@array2, \@array3);

Hier nun das Beispiel..........

#!/usr/bin/perl -w

@array1 = (22,55,11);
@array2 = (4,7,1);
@array3 = (99,2,7);

@allarray = (\@array1, \@array2, \@array3);

gib_aus(\@allarray);

gib_aus
 {
  my $array_ref = $_[0];
  foreach $elem (@$array_ref)#Anfangsadresse der einzelnen Array in $elem
    {
      #printf "x="; #Zur Kontrolle wird 3x ausgegen da 3 Arrays
      foreach $wert (@$elem)
      #Durchläuft die einzelnen Arrays jeweils 3x da 3 Werte pro Array
        {
           print $wert , "\t";
        }
    }
  print "\n";


Nun zur Erklärung. In der Hauptfunktion übergeben wir mittels Referenzen die einzelnen Arrays an ein Array. Anschließend geben wir an die Funktion gib_aus die Anfangsadresse unserem Array in dem wir die Anfangsadressen der einzelnen Arrays übergeben haben. Um nun da Referenzen ja auch einfache skalare sind übergeben wir in der Funktion gib_aus den Parameter $_[0] an my $array_ref.
Was nun kommt werden wir auch so bei den nächsten Beispielen verwenden. Die erste foreach-Schleife durchläuft die einzelnen Arrays im Array. Beim ersten Durchlauf als @array1. Somit steht jetzt in $elem die Anfangsadresse vom @array1. In der zweiten foreach-Schleife durchlaufen wir jetzt die einzelnen Werte von @array1 (22,55,11).
Anschließend ist die innere foreach-Schleife wieder fertig. Nun war die Äußere ja noch nicht fertig. Diese erhöht Ihren "Index" sozusagen auch um eins und dort haben wir nun @array2. Den weiteren Verlauf kennen wir ja nun.

Was sich hier so komplex anhört ist gar nicht so schlimm. Denn wenn wir eine Array von Arrays durchlaufen wollen müssen wir ja zwei foreach-Schleifen verwenden damit wir in das Innere Array kommen. Das ja wie folgt aussieht......

@allarray = ( [22,55,11] , [4,7,1], [99,2,7]);

Diese Möglichkeit von Referenzen auf Listen können wir übrigens auch verwenden.

Array von Hashes
Array von Hashes funktionieren im Übrigen genauso wie die eben schon erklärten Array von Arrays. Daher will ich nicht genauer darauf eingehen sondern nur ein Programmbeispiel hinstellen..........

#!/usr/bin/perl -w

%hash1 = ("Marke" => "BMW",
          "Baujahr" => 2000,
%hash2 = ("Marke" => "Opel",
          "Baujahr" => 1999,
%hash3 = ("Marke" => "Audi",
          "Baujahr" => 2001);

@array_hash = (\%hash1, \%hash2, \%hash3);

gib_aus(\@array_hash);



sub gib_aus
 {
  my $array_ref = $_[0];
  foreach $elem (@$array_ref)
  #Anfangsadresse der einzelnen Array in $elem
    {
      #printf "x="; #Zur Kontrolle wird 3x ausgegen da 3 Hash im Array
      foreach $key (keys %$elem)  #Gibt den Inhalt des Hash aus
        {
          print "$key : " , "$elem->{$key}" #$key=Marke und Baujahr
        }
    }
  print "\n";
}


Hier also im Prinzip der selbe Vorgang wie schon bei Array von Arrays.

Was schon etwas Interessanter sein dürfte sind wohl Hashes mit Listen.........

%hash = ("Marke" => "BMW",
         "PS" => [105, 120, 180]);


Um in einem einem solchen Fall auf die einzelnen Elemente der Liste im Hash zuzugreifen ist folgende Schreibweise nötig.......

@$hash{$key};

Wollen wir das mal wieder in der Praxis anschauen........

#!/usr/bin/perl -w

%hash1 = ("Marke" => "BMW",
                  "PS" => [105, 120, 180]);


foreach $key (keys %hash1)
  {
    print "$key : ";
    if(ref($hash1{$key}))  #Referenz?
      {
        foreach $elem (@{$hash1{$key}})
          {
             print "$elem " ;
          }
      }
    else
      {
         print "$hash1{$key} ";
      }
  print "\n";
 }


Das meiste in diesem Programm dürfte Ihnen ja schon bekannt sein. Mit dem Schlüsselwort ref überprüfen wir ob der Wert des Schlüssels eine Referenz ist. Wenn ja durchlaufen wir die einzelnen Werte dieser Liste mit...

 foreach $elem (@{$hash1{$key}})

Was sich hier als ziemlich kryptisch liest ist gar nicht so schlimm. In unserem Beispiel lesen wir den ersten Wert des Arrays in $key ("PS") aus dem Hash hash1 aus und übergeben diesen Wert der Variablen $elem um diesen gleich darauf auszugeben. Dann lesen wir den zweiten Wert des Arrays im Hash mit dem Schlüssel (PS) aus u.s.w.

Und als letztes hätten wir noch die Möglichkeit eines Hash von Hashes.
Dazu will ich jetzt aber nicht eingehen. Dies soll in einem späteren Kapitel behandelt werden.
Nur ein Snippet wie man sich dies Vorstellen kann........

%hash1 = ("Marke" = "BMW",
          "Baujahr" => 2000);
%hash2 = ("Marke" => "Audi",
          "Baujahr" => 1999);

%hash_hash = ("h_key1" => \%hash1, "h_key2" => \%hash2);


Wie gesagt wir kommen später darauf zurück und gehen genauer darauf ein.

Nochmals kurz zusammengefasst, da diese ein Umfangreicheres Kapitel ist........

Folgende Bedeutung für folgende Dereferenzierungen............

  • $$referenz = Skalar
  • ${$referenz}[1] und $referenz->[1]= einzelnes Array-Element
  • @$referenz und @{$referenz} = gesamtes Array
  • %$hash und %{$hash} = gesamtes Hash
  • ${$hash}{'key'} und $hash->{'key'}= einzelne Hash-Elemente

Referenz auf Subroutinen

Natürlich ist es auch möglich eine Referenz auf Subroutinen festzulegen. Es muss dabei aber darauf geachtet werden das hierzu das Präfix & nach dem Backslash erfolgt......


sub funkion{..}

$funcref = \&funktion;

Hiermit speichern wir die Adresse der Funktion funktion in $funcref. Sie werden diese Methode noch öfters in sogenannte Dispatcher sehen. Im Kapitel GUI's mit Perl und Tk zum Beispiel............


$m_file->command(-label => "Speichern",
                 -command => [\&save, "speichern"] );

Hier haben wir zum Beispiel Menü-Buttons. Dieser ist Beschriftet mit "Speichern". Wenn sie diesen Button mit der linken Maustaste betätigen, wird die Adresse der Subroutine \&save ausgeführt, was in unserem Fall das Abspeichern von Daten bedeutet.

Referenz auf Filehandles

Es ist auch Möglich Referenzen auf Filehandles zu verwenden. Hier #ist zu beachten, dass sie das Präfix * nach dem Backslash stehen #haben. Wir wollen das ganze anhand eines einfachen Beispiels demonstrieren....


#!/usr/bin/perl -w

sub input{
 my($stdin, $stdout, $prompt) = ($_[0],$_[1],$_[2]);
 print $stdout, $prompt;
 return scalar <$stdin>;
 }

$scalar = input(\*STDIN, \*STDOUT, "Eingabe : ");
print "Sie gaben ein : $scalar\n";

Hier geben wir als Funktionsparameter die Standard-Filhandles STDIN und STDOUT an die Funktion input. Als Rückgabewert bekommen wir den Skalaren Wert von der Variable $stdin.

Rückgabe von lokale Referenzen aus Subroutinen

Was in C nicht möglich ist, funktioniert in Perl tadellos. Nur wozu soll das gut sein? Mit dieser Methode können sie Variablen Temporär Zwischenspeichern. Beispiel............

#!/usr/bin/perl -w

sub input{
 my @refarray;
 my $scalar;

 print "Bitte Eingabe machen : ";
 chomp($scalar = <>);
 @refarray=split(" ", $scalar);

 return \@refarray;
 }


$ref1=input;
$ref2=input;

print "@{$ref1}" , "\n";  #Überrascht?!
print "@{$ref2}" , "\n";

C-Programmierer dürften bei diesem Programm überrascht sein, das hier keine Fehlermeldung ausgegeben wurde. Wir haben eine lokale Variable einer Funktion an unsere Hauptfunktion zurückgegeben. Dies ist in C unmöglich. Wir haben praktisch mit jedem Aufruf.....

$ref=input

...den Inhalt unserer Liste refarray in der Skalaren Variable $ref gesichert. Mit diesen beiden Referenzen kann anschließend normal weitergerabeitet werden.

Refernztyp idenfizieren mit ref

Wir haben die Funktion ref bereits Verwendet. Nun noch eine Erklärung dazu. Mit der Funktion ref können sie überprüfen was für ein Referenztyp gerade verwendet wird. Folgende Rückgabewerte sind dabei möglich........

SCALAR,ARRAY,HASH,REF,CODE,GLOB,LVALUE

Überprüfen können sie dies Idealerweise folgendermaßen...

foreach(@liste){
 if(ref($_) eq 'SCALAR'){ #Scalar
 }
 elsif(ref($_) eq 'ARRAY'){ #Array
 }
 .........
 .........

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf