@_
Array
The
@_
array contains aliases for the arguments,
not copies of their values!
Try this code:
#!/usr/bin/perl use strict; my $height = 165; # cm my $weight = 65; # kg convert($height, $weight); print "Height: $height in. Weight $weight lbs.\n"; # # Because the elements of @_ are aliases for # the arguments, changing $_[0] and $_[1] will # change $height and $weight # sub convert { $_[0] = $_[0] / 2.54; # convert to inches $_[1] = $_[1] * 2.2; # convert to pounds }
If you want to make sure that you don’t accidentally change variables in the caller, copy the values from @_ to another array or to individual variables:
sub do_not_touch { # copies @_ into other variables; # values from calling program will not be changed # my ($copy1, $copy2) = @_; $copy1 *= 3; $copy2 += 4; }
A reference is a scalar that holds the memory location and type of some Perl entity. The following code summarizes what we talked about in class. You are encouraged to copy and paste this into a file and give it a try.
#!/usr/bin/perl # # Here are some variables # $scalar = 27; @array = ( 10, 66 ); %hash = ( "Wladziu" => "Liberace" ); # # You use \ to get references to those variables # $scalar_ref = \$scalar; $array_ref = \@array; $hash_ref = \%hash; # # If you print the references, you will see # that the reference has the variable's memory # address and data type. # print $scalar_ref, "\n"; print $array_ref, "\n"; print $hash_ref, "\n"; # # You use braces to dereference. # print "${$scalar_ref}\n"; print "@{$array_ref}\n"; print %{$hash_ref}, "\n"; # # Getting to an individual element of an array or hash: # Notice that the expression starts with a $, because # an individual entry in an array or hash is a scalar. # print ${$array_ref}[0], "\n"; # prints number 10 # # The first set of curly braces dereferences $hash_ref. # The second set of curly braces indexes into the hash. # print ${$hash_ref}{"Wladziu"}, "\n"; # prints "Liberace" # # All those curly braces can get difficult to read, # so you can use -> as a shortcut. # Here is a shortcut version of the previous lines: # print $array_ref->[0], "\n"; print $hash_ref->{"Wladziu"}, "\n";
So far, this just seems to be a more complicated way to access
a variable, and it appears to be fairly useless. It does
become useful in conjunction with passing parameters to a
subroutine. For example, let’s say you want to write a
subroutine to find the
sum of the products of two lists of numbers (this is a common
thing to do in engineering). That is, if we have the lists
(7, 2, 3)
and (5, 13, 11)
,
the result would be
7*5 + 2*13 + 3*11, or 94. If
the arrays aren’t the same length, it’s an error,
so the subroutine should return zero.
Here is a program that will not work, because arrays get flattened:
#!/usr/bin/perl use strict; my @arr1 = (7, 2, 3); my @arr2 = (5, 13, 11); my $result = sum_of_products( @arr1, @arr2 ); sub sum_of_products { my (@data1, @data2) = @_; my $i; my $sum; # debugging code: print "Length of first array: ", scalar @data1, "\n"; print "Length of second array: ", scalar @data2, "\n"; if (scalar @data1 == scalar @data2 ) { for ($i=0; $i < scalar @data1; $i++) { $sum += $data1[$i] * $data2[$i]; } } else { $sum = 0; } return $sum; }
However, if you pass references to the arrays, you
will (effectively) be passing two different scalars in @_
,
and no flattening will take place:
#!/usr/bin/perl use strict; my @arr1 = (7, 2, 3); my @arr2 = (5, 13, 11); # # pass REFERENCES to the two arrays # my $result = sum_of_products( \@arr1, \@arr2 ); print "Result is $result\n"; sub sum_of_products { my ($data_ref1, $data_ref2) = @_; my $i; my $sum; # # This is the same code as before, except that # we must now dereference every time we need to # access the array. # # # debugging code print "Length of first array: ", scalar @{$data_ref1}, "\n"; print "Length of second array: ", scalar @{$data_ref2}, "\n"; if (scalar @{$data_ref1} == scalar @{$data_ref2} ) { for ($i=0; $i < scalar @{$data_ref1}; $i++) { $sum += ${$data_ref1}[$i] * ${$data_ref2}[$i]; } } else { $sum = 0; } return $sum; }