Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Konvertieren, int ceil sprintf hex oct floor Runden AbschneidenPerl Kurs Skripting Referenzen Adressoperator Dereferenzieren Array von Arrays ref Arrays von Hashes Referenzen Adressoperator Dereferenzieren Array von Arrays ref Arrays von Hashes Perl Kurs Kapitel 11

11.1. Referenzen           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

In Perl sind  Referenzen nicht mit denen der Sprache C gleichzusetzen. In Perl können Referenzen nur auf definierte Variablen verweisen und nicht auf irgend einem Adressraum. Ein simples Beispiel des Einsatzes von Referenzen ...

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

Zuerst wird eine Variable $var definiert und mit dem Wert 5 initialisiert. Anschließend wurde der Variablen $referenz die Adresse der Variablen $var übergeben. Dies können Sie anhand des Adressoperators '\' (Backslash) erkennen. Somit ist $referenz die Referenz auf der Variablen $var. Im nächsten Programm wird dies Demonstriert ...

#!/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 zweimal die selbe Adresse von der Variablen $var ausgegeben. Wie schon in der Programmiersprache C, setzt sich eine Variable immer aus dem Namen, dem Wert und der Adresse im Speicher zusammen. Durch den Backslash in der zweiten print-Anweisung sorgen Sie dafür, dass die Adresse von $var ausgegeben wird. Die Ausgabe von $referenz stellt dagegen die Adresse da, auf die diese verwiesen wurde. In diesem Fall $var. Wenn Sie die Adresse des Referenzen $referenz erfahren wollen, müssen Sie auch dort nur den Adressoperator '\' davor setzen ...

print \$referenz , "\n";

Genauso wie eben gesehen, funktioniert dies auch bei den Arrays und Hashes ...

#!/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

Nun wollen wir uns doch mal ansehen, wie 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 gesehen, wie Sie auf den Wert von Referenzen zugreifen können, auf den Sie verweisen. Der Zugriff auf den Wert des Referenzen erfolgt einfach zwischen geschweifte Klammern. Man spricht beim Zugriff auf eine Referenz von der Dereferenzierung. Nun sehen wir uns mal an was wir hiermit 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 verweist. Was logischerweise auch nach sich zieht, dass der Wert von $var sich ebenfalls verändert, da ja $var und ${$referenz} das selbe Objekt beinhalten.

Das ganze jetzt 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 ...

@{$ref1}[1]

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

%{$ref2}{'Name'}

In diesem Fall würden Sie 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 Schreibweisen zu vereinfachen ...

@{$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 nun anhand eines Skripts ...

#!/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] , "\n";  #99
print $ref2->{'Name'};    #Becker

Mit Referenzen haben Sie nun die Möglichkeiten, komplexere Datenstrukturen zu erstellen ...

Array von Arrays
Beispiel: Sie haben mehrere Arrays mit Werten und wollen diese an eine Funktion übergeben ...

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

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

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

... zu übergeben. Es geht aber auch einfacher. Sie 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);

sub gib_aus
 {
  my $array_ref = $_[0];
  foreach $elem (@$array_ref)#Anfangsadresse der einzelnen Arrays 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 Sie mittels Referenzen die einzelnen Arrays an ein Array. Anschließend geben Sie an die Funktion gib_aus die Anfangsadresse von dem Array, in dem Sie die Anfangsadressen der einzelnen Arrays übergeben haben. Da Referenzen ja auch einfache skalare Variablen sind, übergeben Sie in der Funktion gib_aus den Parameter $_[0] an my $array_ref. Was nun kommt, werden Sie auch so, bei den nächsten Beispielen verwenden. Die erste foreach-Schleife durchläuft die einzelnen Arrays im Array. Beim ersten Durchlauf @array1. Somit befindet sich jetzt in $elem die Anfangsadresse vom @array1. In der zweiten foreach-Schleife werden jetzt die einzelnen Werte von @array1 (22,55,11) durchlaufen. Anschließend ist die innere foreach-Schleife  fertig. Nun war die Äußere ja noch nicht fertig. Diese erhöht Ihren Index sozusagen auch um eins und dort befindet sich nun @array2. Den weiteren Verlauf kennen Sie bereits.

Was sich hier so komplex anhört ist gar nicht so schlimm. Denn wenn Sie ein Array von Arrays durchlaufen wollen, müssen Sie  zwei foreach-Schleifen verwenden, damit Sie in das Innere Array kommen. Das ja intern 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 Skript dazu zeigen ...

#!/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}\n" #$key=Marke und Baujahr
        }
    }
  print "\n";
}

Hier ist  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 zu zugreifen, 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, stellt sich als Harmlos heraus. In unserem Beispiel lesen Sie den ersten Wert des Arrays in $key ("PS"), dem Hash hash1, aus und übergeben diesen Wert der Variablen $elem, um diesen gleich darauf auszugeben. Dann lesen Sie den zweiten Wert des Arrays im Hash mit dem Schlüssel (PS) aus u.s.w.

Hash von Hashes
Auf diese Möglichkeit wird hier nicht genauer eingegangen. Nur ein Snippet wie Sie sich dies Vorstellen können ...

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

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

Nochmals alles in diesem Kapitel kurz zusammengefasst, da diese ein etwas Schwierigeres war ...

Folgende Bedeutung gelten für folgende Dereferenzierungen:

Referenz auf Subroutinen
Es ist auch möglich, eine Referenz auf Subroutinen zu definieren. Dabei muss aber darauf geachtet werden, dass hierzu das Präfix & nach dem Adressoperator (Backslash) verwendet wird ...

sub funkion{..}

$funcref = \&funktion;

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

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

Hier haben Sie zum Beispiel einen Menü-Buttons. Dieser ist Beschriftet mit der Aufschrift "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. Hierbei ist zu beachten, dass Sie das Präfix * nach dem Backslash stehen haben. Dies können Sie sich an folgendem Skript näher betrachten ...

#!/usr/bin/perl -w

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

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

Hier geben Sie als Funktionsparameter die Standard-Filhandles STDIN und STDOUT an die Funktion input. Als Rückgabewert bekommen Sie den skalaren Wert 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önnten Sie beispielsweise Variablen Temporär Zwischenspeichern ...

#!/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. Hier wurde eine lokale Variable aus einer Funktion, an unsere Hauptfunktion zurückgegeben. Dies ist in C unmöglich. Es wurde praktisch mit jedem Aufruf ...

$ref=input

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

Refernztyp idenfizieren mit ref
Sie haben die Funktion ref bereits Verwendet. Nun noch eine kurze 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
 }
 .........
 .........

11.2. Anonyme Strukturen           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Anonyme Strukturen sind Referenzen, die auf einem Speicherbereich verweisen, die keiner Variablen gebunden sind. Da Sie keinen Namen haben heißen diese anonyme Strukturen.

Anonyme Listen
Anonyme Listen werden mit Hilfe von eckigen Klammern erzeugt ...

$ref = ["Hallo", "Welt", "in", "Perl"];

Hier haben Sie eine Liste mit vier Elementen ohne Namen angelegt. Zugreifen können Sie nun auf diese vier Elementen mit dem Refernzen $ref  ...

#!/usr/bin/perl -w

$ref = ["Hallo", "Welt", "in", "Perl"];

print $ref->[0] , " ";  #Hallo
print $ref->[1] , " ";  #Welt
$ref->[2] = "mit";      #in -> mit
print $ref->[2] , " ";  #mit
print $ref->[3] , "\n"; #Perl

#...oder alles auf einmal...
print "@{$ref}" , "\n";

Natürlich können Sie an die anonyme Liste auch weitere Elemente anfügen ...

#!/usr/bin/perl -w

$ref = ["Hallo", "Welt", "in", "Perl"];
@array = ("Perl", "ist", "toll");

print "@{$ref}" , "\n";

#Liste @array hinten anhängen
push( @{$ref}, @array );

print "@{$ref}" , "\n";

Anonyme Hashes
Mit anonymen Hashes funktioniert das ganze genauso wie schon bei anonymen Listen ...

$ref = { name => 'Argon Miller' , telefon => '0800-200200' };

Zugreifen auf die einzelnen Werte können Sie mit Hilfe des Schlüssels und dem Referenzen $ref ...

#!/usr/bin/perl -w

$ref = { name => 'Argon Miller' , telefon => '0800-200200' };

print $ref->{'name'} , "\n";
print $ref->{'telefon'} , "\n";

Natürlich können Sie auch die Inhalte verändern und neue hinzufügen ...

#!/usr/bin/perl -w

$ref = { name => 'Argon Miller' , telefon => '0800-200200' };

print $ref->{'name'} , "\n";
print $ref->{'telefon'} , "\n\n";

$ref->{'name'} = "Argon Mueller";

$ref->{'gehalt'} = "5400 Euro";

print $ref->{'name'} , "\n";
print $ref->{'telefon'} , "\n";
print $ref->{'gehalt'} , "\n";

Die Ausgabe mit einer foreach-Schleife ist dieser hier gezeigten vorzuziehen ...

#!/usr/bin/perl -w

$ref = { name => 'Argon Miller' , telefon => '0800-200200' };

$ref->{'name'} = "Argon Mueller";

$ref->{'gehalt'} = "5400 Euro";

foreach (keys %{$ref} ){
 print $_ , " : " , $ref->{$_} , "\n";
 }

Anonyme Subroutinen
Auch die Subroutinen können anonym sein ...

#!/usr/bin/perl -w

$sub1 = sub { return my $ergebnis = $_[0] + $_[1] };
$sub2 = sub { print "Ich bin die Subfunktion2\n" };

print &{$sub1}(20,25) , "\n";
print &{$sub2} , "\n";

Solche Möglichkeiten werden Sie in Perl/Tk häufiger verwenden. Das klassische Beispiel stellt auch hier wieder einen Dispatcher da ...

$code_ende = sub { print "bye\n"; exit (0); };

%dispatch = { 'input' => sub { print "Eingabe : " };
              'output'=> sub { print "Sie gaben ein : " } ;
              'ende'  => $code_ende;
            }