The better &max subroutine that don't care about arguments' number.
$maximum=&max(3,5,10,4,6);
sub max{
my($max_so_far)=shift @_;
foreach(@_){
if($_>$max_so_far){
$max_so_far=$_;
}
}
$max_so_far;
}
my($max_so_far)=shift @_;
foreach(@_){
if($_>$max_so_far){
$max_so_far=$_;
}
}
$max_so_far;
}
If there's 0 argument, then shift @_ will return undef, foreach(@_) won't start its loop.
$max_so_far will be undef too, the return value of &max will be undef. Maximim of nothing is undef! Yes that's the truth.
$max_so_far will be undef too, the return value of &max will be undef. Maximim of nothing is undef! Yes that's the truth.
The private variables created by my() will only be seen by its block, if there're {} then it's seen in { ... }.
If my() variables are not in {}, then it's seen in everywhere of file, the perl program.
If my() variables are not in {}, then it's seen in everywhere of file, the perl program.
And, my() doesn't change the context;
And, NOTE if there's no () then my only defines one variable (scalar or list) !!!
And, NOTE if there's no () then my only defines one variable (scalar or list) !!!
my $fred, $barney; # error! $barney not defined
my ($fred, $barney); # right. both defined
my @fred; # right, defines an array
my ($fred, $barney); # right. both defined
my @fred; # right, defines an array
If the new variable is not given a value, then scalar will be undef while array be empty list.
Perl provides warnings/strict pragma to examine to grammar. Many perl programs are wriiten as:
#!/usr/bin/perl
use strict;
use warnings;
use warnings;
All lines below "use strict/warnings" will be examined. Strict is stricter than warnings.
Operation 'return' can immediately return a value from subroutine and end the subroute call.
If 'return' doesn't happen (ex: false condition), then the last expression returns.
If 'return' doesn't happen (ex: false condition), then the last expression returns.
my @names=qw/fred barney betty dino Wilama pebbles bam-bamm/;
my $result=&which_element_is("dino", @names);
my $result=&which_element_is("dino", @names);
sub which_element_is{
my($what,@array)=@_;
foreach(0..$#array){
if($what eq $array[$_]{
return $_;
}
}
-1;
}
my($what,@array)=@_;
foreach(0..$#array){
if($what eq $array[$_]{
return $_;
}
}
-1;
}
Here @_=("dino",@names), then my($what,@array)=("dino",@names): $what gets a copy of "dino", @array gets a copy of @names.
foreach go through indexes 0..$#array, ($#array is the last index of array), if "dino" equals $array[$_], immediately returns $_. If no matching is found after foreach loop, then returns -1
When you're sure your subroutine is not a builtin function in Perl, you can call the subroutine without a '&'.
But if it is a builtin function, then Perl will call that function instead your subroutine.
But if it is a builtin function, then Perl will call that function instead your subroutine.
And, when you call without '&', your subroutine has to be defined before called to let Perl know what it is.
So, always calling with '&' is not bad for you. No one can know all the builtin functions except Larry ^_^
So, always calling with '&' is not bad for you. No one can know all the builtin functions except Larry ^_^
Subroutine can also return a list, besides a scalar, when it's called in a list context.
sub list_from_fred_to_barney{
if($fred<$barney){
$fred .. $barney
}else{
reverse $barney .. $fred;
}
}
if($fred<$barney){
$fred .. $barney
}else{
reverse $barney .. $fred;
}
}
$fred=11;
$barney=6;
my @c=&list_from_fred_to_barney;
$barney=6;
my @c=&list_from_fred_to_barney;
Execsices:
1. Write a subroutine named &total, returns the summary of a list of numbers. Note the subroutine handles arguments and returns value to caller.
The subroutine should not do any I/O operation.
#!/usr/bin/perl
sub total{
my $sum;
chomp(my @num=@_);
foreach(@num){
$sum+=$_;
}
$sum;
}
my $sum;
chomp(my @num=@_);
foreach(@num){
$sum+=$_;
}
$sum;
}
my @fred=qw{1 3 5 7 9};
my $fred_total=&total(@fred);
print "The total of \@fred is $fred_total.\n";
print "Enter some numbers on separate lines: ";
my $user_total=&total();
print "The total of those numbers is $user_total.\n";
########################################################
my $fred_total=&total(@fred);
print "The total of \@fred is $fred_total.\n";
print "Enter some numbers on separate lines: ";
my $user_total=&total(
print "The total of those numbers is $user_total.\n";
########################################################
2. Use above subroutine, write a program to caculate the summary from 1 to 1000.
#!/usr/bin/perl
sub total{
my $sum;
chomp(my @num=@_);
foreach(@num){
$sum+=$_;
}
$sum;
}
my $sum;
chomp(my @num=@_);
foreach(@num){
$sum+=$_;
}
$sum;
}
my @fred=(1 .. 1000);
my $fred_total=&total(@fred);
print "The total of \@fred is $fred_total.\n";
########################################################
my $fred_total=&total(@fred);
print "The total of \@fred is $fred_total.\n";
########################################################
3. Write a subroutine named &above_average, use a list of numbers as arguments, return all the numbers bigger than average. You can write another subroutine &average to get the average.
#!/usr/bin/perl
use strict;
use warnings;
use warnings;
sub average{
my $sum;
chomp(my @nums=@_);
foreach(@nums){
$sum+=$_;
}
$sum/@nums ;
}
my $sum;
chomp(my @nums=@_);
foreach(@nums){
$sum+=$_;
}
$sum/@nums ;
}
sub above_average{
chomp(my @nums=@_);
my @above;
foreach(@nums){
if($_>&average(@nums)){
push @above,$_;
}
}
@above;
}
chomp(my @nums=@_);
my @above;
foreach(@nums){
if($_>&average(@nums)){
push @above,$_;
}
}
@above;
}
my @fred = &above_average(1..10);
print "\@fred is @fred\n";
print "(Should be 6 7 8 9 10)\n";
my @barney = &above_average(100, 1..10);
print "\@barney is @barney\n";
print "(Should be just 100)\n";
########################################################
print "\@fred is @fred\n";
print "(Should be 6 7 8 9 10)\n";
my @barney = &above_average(100, 1..10);
print "\@barney is @barney\n";
print "(Should be just 100)\n";
########################################################
Tips: the last program marked in blue is not good, but it guided me to think more than itseft. Thanks to Mcshell, we found the problem. Though I've modified it to below one, I'd like to keep it there for memory.
#!/usr/bin/perl
sub average{
chomp(my @nums=@_);
my $sum;
foreach(@nums){
$sum+=$_;
}
$sum/@nums
;
}
sub above_average{
chomp(my @nums=@_);
my $average=&average(@nums);
my @above;
foreach(@nums){
if($_>$average){
push @above,$_;
}
}
@above;
}
my @fred = &above_average(1..10);
print "\@fred is @fred\n";
print "(Should be 6 7 8 9 10)\n";
my @barney = &above_average(100, 1..10);
print "\@barney is @barney\n";
print "(Should be just 100)\n";
########################################################
4. Write a sub greet(), use the given name as argument, print the welcome words and tell him the name who came before him.
greet ("Fred");
greet ("Barney");
should print:
Hi Fred! You are the first one here!
Hi Barney! Fred is also here!
#!/usr/bin/perl
sub greet{
chomp(my $name=$_[0]);
push @names,$name;
while($index<=$#names){
if($index==0){
print "Hi $names[$index]! You are the first one here!\n";
}else{
print "Hi $names[$index]! $names[$index-1] is also here!\n";
}
$index++;
}
}
&greet("Fred");
&greet("Barney");
###############################################
5. Modify above program, tell all users all the names came before him.
greet ("Fred");
greet ("Barney");
greet ("Wilma");
greet ("Betty");
should print:
Hi Fred! You are the first one here!
Hi Barney! I've seen: Fred
Hi Wilma! I've seen: Fred Barney
Hi Betty! I've seen: Fred Barney Wilma
#!/usr/bin/perl
sub greet{
chomp(my $name=$_[0]);
push @names,$name;
while($index<=$#names){
if($index==0){
print "Hi $names[$index]! You are the first one here!\n";
}else{
$guy=pop @names;
print "Hi $guy! I've seen: @names \n";
push @names,$guy;
}
$index++;
}
}
&greet("Fred");
&greet("Barney");
&greet("Wilma");
&greet("Betty");
greet ("Fred");
greet ("Barney");
should print:
Hi Fred! You are the first one here!
Hi Barney! Fred is also here!
#!/usr/bin/perl
sub greet{
chomp(my $name=$_[0]);
push @names,$name;
while($index<=$#names){
if($index==0){
print "Hi $names[$index]! You are the first one here!\n";
}else{
print "Hi $names[$index]! $names[$index-1] is also here!\n";
}
$index++;
}
}
&greet("Fred");
&greet("Barney");
###############################################
5. Modify above program, tell all users all the names came before him.
greet ("Fred");
greet ("Barney");
greet ("Wilma");
greet ("Betty");
should print:
Hi Fred! You are the first one here!
Hi Barney! I've seen: Fred
Hi Wilma! I've seen: Fred Barney
Hi Betty! I've seen: Fred Barney Wilma
#!/usr/bin/perl
sub greet{
chomp(my $name=$_[0]);
push @names,$name;
while($index<=$#names){
if($index==0){
print "Hi $names[$index]! You are the first one here!\n";
}else{
$guy=pop @names;
print "Hi $guy! I've seen: @names \n";
push @names,$guy;
}
$index++;
}
}
&greet("Fred");
&greet("Barney");
&greet("Wilma");
&greet("Betty");