To get a reference (pointer) from an object we need to use the back-slash operator:
| Pointer at | Named object |
|---|---|
| scalar | \$scalar |
| array | \@array |
| hash | \%scalar |
| function | \&scalar |
my @data = qw / This is an array of data /;
my $ref = \@data;
for($i=0;$i<=$#data;$i++){
print $ref->[$i] . "\n";
}
To get an element from an array referenced by a pointer we use a new operator ->. Thus,
$ref->[2] gives us the element of the array pointed at by $ref with index 2. We can also syntax
like $$ref[2] to reach the same element. We can think of this syntax like that since $ref
points to an array @data we will use $ref instead of the name of the array data.
That is, instead of using $data[2] we use $$ref[2]. The same rule works for hashes as well:
my %hash = (name => "Bob", city => "Atlanta", zip => "30033");
my $ref = \%hash;
foreach ( keys(%hash) ){
print "$_ => $$ref{$_} \n";
}
The only thing we need to remember reaching hash elements through a reference is to use curly brackets instead of square
brackets.
$pointer = [ array_elements ];Similar syntax works for pointers to anonymous hashes
$pointer = { hash_keys_and_elements };
The following example illustrates the syntax
# create a new anonymous array and store the pointer to it at ref
$ref = [qw / This is another array (anonymous) /];
foreach ( @$ref ){
print "$_\n";
}
# create a new anonymous hash and store the pointer to in ref
$ref = { this => "is", another => "hash", an => "anonymous"};
foreach ( keys(%$ref) ){
print "$_ => $ref->{$_} \n";
}
Bob 4.0 Atlanta Bill 3.5 Boston Sam 2.0 Chicagowhere each line contains some data for one student. We need to read all the data and keep it in one array. The difficult part is the data itself contains name, GPA, and city. Thus, we need to have an array of hashes. We cannot have an array of hashes, but we can have an array of pointers to hashes. The solution to the problem is the following, we read a line from file, split it into three pieces (name, GPA, and city), create an anonymous hash and store the pointer to that has in the next array element:
my @student = (); # create an empty array
my $ind = 0; # initialize the counter
while (<>){
chomp;
($name, $GPA, $city) = split(/\s+/, $_);
# create an anonymous hash and save the pointer to it in the array element
$student[$ind] = { name => $name, GPA => $GPA, city => $city };
$ind++;
}
for($i=0;$i<$ind;$i++){
printf "%2d: %10s %.2f %10s\n", $i+1, $student[$i]->{name}, $student[$i]->{GPA}, $student[$i]->{city};
}
As you can see each element of the array is a pointer to a hash.
For example, let we have a file like this:
Bob: 89 76 89 90 100 101 Bill: 100 89 76 80 34 0 Sam: 102 99 87 78 90 69For each student mentioned in the file we would like to keep her or his grades. To do that we will write the following code:
%grades = (); # create an empty hash
while( <> ){
chomp;
($name, $grds) = split(/:\s*/, $_);
$grades{$name} = [ split(/\s+/, $grds) ];
}
for ( keys(%grades) ){
printf "%8s : %.2f\n", $_, avg( @{$grades{$_}} );
}
sub avg
{
my @arr = @_;
my $sum = 0;
my $count = $#arr + 1;
for(my $i=0;$i<$count;$i++){
$sum += $arr[$i];
}
$sum/$count;
}
The very first loop just reads the file line by line and splits the line into name and grades, then it uses
split function again to get an array of grades, then in the assignment
$grades{$name} = [ split(/\s+/, $grds) ]; we initialize an element of the has with the key
$name and the value is a pointer to an anonymous array that contains all the grades for the student.
To create a pointer we use square brackets around the functions split. In the second loop we call
function avg to compute the average grade for each student. Please notice that we use @ in front
of the hash element to specify that we pass an array not a pointer to the function.