Die Webseiten der Fachschaft Informatik am ERG Saalfeld
Subroutinen (Prozeduren und Funktionen)
Wenn in einem Programm bestimmte Programmteile mehrfach vorkommen ist meistens sinnvoll, diese
Programmteile in ein Unterprogramm auszulagern und dieses Unterprogramm aufzurufen. Dadurch wird das Programm
kürzer und damit (in den meisten Fällen) auch besser lesbar. Bei Änderungen / Anpassungen muss nur an einer Stelle
geändert werden. Es gibt aber auch weitere Gründe für die Nutzung von Subroutinen (Prozeduren und Funktionen).
Im Beispiel mit dem Primzahlsieb werden Subroutinen nur zur besseren Strukturierung
eingesetzt. Ein weiterer Grund könnte sein, dass für die Umsetzung einer Aufgabe Funktionen gebraucht werden,
die Perl von Haus aus nicht bereitstellt. Dann stellt
diese Subroutine einen Baustein für das Programm dar.
Prozeduren
Unterprogramme, die kein Ergebnis zurückliefern, nennt man Prozeduren.
Anmerkung: Prozeduren haben üblicherweise die Aufgabe, etwas auszugeben. Sie können aber auch globale Variable ändern.
Beispiel (Programm "Einmaleins")
Der Quelltext und die Ausgabe dazu sahen so aus:
use strict;
use warnings;
foreach my $y (1 .. 10) {
foreach my $x ( 1 .. 10) {
print $x * $y, ' ';
}
print "\n";
}
|
|
|
Ein möglicher Ansatz um die Ausgabe schöner zu formatieren geht sicherlich über die Nutzung des Tabulators.
Allerdings wird dann die Zeile voll ausgefüllt. Es bleibt dann keine Möglichkeit, eine Tabellenbeschriftung (für
die Zeile) zu ergänzen. Es soll deshalb hier ein Unterprogramm geschrieben werden, was die Zahl $x immer als
dreistellige Zahl ausgibt. Das bedeutet, ist $x einstellig (also kleiner als 10), dann werden 2 Leerzeichen davor gesetzt.
Ist $x zweistellig (also kleiner als 100), dann wird ein Leerzeichen davor gesetzt. Andernfalls wird $x genommen wie es ist.
Das Unterprogramm (die Subroutine) sieht dazu so aus:
sub dreistellig {
my $hilf;
if ($z < 10) {
$hilf = ' ' . $z;
print $hilf;
}
elsif ($z < 100) {
$hilf = ' ' . $z;
print $hilf;
}
else {
$hilf = $z;
print $hilf;
}
}
Wichtig: Die Subroutine (Prozedur) greift auf die Variable $z zu und gibt diese nach der Formatierung aus. Das Hauptprogramm
muss also die auszugebende Zahl in einer (globalen) Variablen $z übergeben. Die (lokale) Variable $hilf im Unterprogramm gilt auch nur in dieser
Subroutine. Sollte es im Hauptprogramm auch eine (globale!) Variable $hilf geben, dann sind diese beiden Variablen völlig unabhängig voneinander
und stören sich gegenseitig nicht. Bei der Programmausführung innerhalb der Subroutine ist dann nur die lokale Variable sichtbar. Eine
globale Hilfsvariable mit gleichem Namen ist dann nicht sichtbar ("überdeckt").
Jetzt muss noch das (Haupt-)Programm für dieses Unterprogramm angepasst werden. Die Subroutine &dreistellig() erwartet
die Zahl in der globalen Variablen $z. Also muss das Hauptprogramm diese Variable $z bereitstellen. Außerdem gibt die Subroutine
den formatierten Zahlenwert schon aus. Im Hauptprogramm werden also nur noch die Leerzeichen und der Zeilenumbruch erledigt.
Damit ergibt sich unser Programm nun so:
use strict;
use warnings;
my $z;
foreach my $y (1 .. 10) {
foreach my $x ( 1 .. 10) {
$z = $x * $y;
&dreistellig(), print ' ';
}
print "\n";
}
###### Ende des Hauptprogramms ######
sub dreistellig {
my $hilf;
if ($z < 10) {
$hilf = ' ' . $z;
print $hilf;
}
elsif ($z < 100) {
$hilf = ' ' . $z;
print $hilf;
}
else {
$hilf = $z;
print $hilf;
}
}
Die Ausgabe sieht nun so aus:
Funktionen
Unterprogramme, die ein Ergebnis zurückliefern, nennt man Funktionen.
Anmerkung: Dieses Ergebnis kann auch eine Liste sein und in der Liste sind dann mehrere Elemente.
Beispiel
Es soll im Folgenden mit 2 Würfeln gespielt werden, wie z.B. beim bekannten Spiel
Lügenmax. Allerdings soll es hier nur darum gehen solange zu würfeln,
bis zweimal die gleiche Zahl gewürfelt wird. Die Würfe sollen zeilenweise ausgegeben werden.
Ein Wurf besteht also aus 2 Würfeln. Jeder einzelne Würfel wird so implementiert:
my $wuerfel1 = int(rand(6) + 1);
my $wuerfel2 = int(rand(6) + 1);
Den Wurf implementieren wir als Liste aus $wuerfel1 und $wuerfel2. Wir erhalten damit:
my $wuerfel1 = int(rand(6) + 1);
my $wuerfel2 = int(rand(6) + 1);
my @wurf = ($wuerfel1, $wuerfel2);
Wir schreiben das jetzt als Subroutinen. Alles was zurückgeben werden soll, wird hinter 'return' angegeben.
sub wurf {
my $wuerfel1 = int(rand(6) + 1);
my $wuerfel2 = int(rand(6) + 1);
my @wurf = ($wuerfel1, $wuerfel2);
return @wurf;
}
Das Hauptprogramm sieht so aus:
#!/usr/bin/perl
use warnings;
use strict;
do {
($wuerfel1, $wuerfel2) = &wurf(); # hier erfolgt der Aufruf der Subroutine wurf
print $wuerfel1, ' ', $wuerfel2, "\n"; # beide gewürfelte Zahlen ausgeben
} while ($wuerfel1 != $wuerfel2);
Das gesamte Programm sieht dann so aus:
#!/usr/bin/perl
use warnings;
use strict;
my ($w1, $w2);
do {
($w1, $w2) = &wurf(); # hier erfolgt der Aufruf der Subroutine wurf
print $w1, ' ', $w2, "\n"; # beide gewürfelte Zahlen ausgeben
} while ($w1 != $w2);
###### Ende des Hauptprogramms ######
sub wurf {
my $wuerfel1 = int(rand(6) + 1);
my $wuerfel2 = int(rand(6) + 1);
my @wurf = ($wuerfel1, $wuerfel2);
return @wurf;
}
__END__
Das Programm brachte bei mir folgende Ausgabe:
Aufgaben
- Bringen Sie die beiden Programme einmaleins.pl und wuerfeln.pl zum Laufen.
- Kommentieren Sie beide Programme (jede Zeile bzw. jeden Block).
- Schreiben Sie im Programm einmaleins.pl die Prozedur &dreistellig zu einer Funktion um. Passen Sie das Hauptprogramm entsprechend an.
- Geben Sie für alle Variablen im Programm wuerfeln.pl an, ob diese globale oder lokale Variable sind.
- Am Ende des Programms wuerfeln.pl (also nach der Zeile mit 'while') soll die Variable $wuerfel1 ausgegeben werden.
Was erwarten Sie? Überprüfen Sie das!
- Ergänzen Sie beide Programme um eine Überschrift (Unterstrichen, mit Leerzeile, eingerückt). Schreiben und verwenden Sie dazu eine Prozedur &ueberschrift() .
zurück
© ERG Saalfeld - Hans-Dietrich Kirmse 17.01.2015
|