Previous Page Next Page

Chapter 13. Does This Job Require a Reference?

13.1. What Is a Reference? What Is a Pointer?

You can use the terms "reference" and "pointer" interchangeably in Perl. A reference is a variable that refers to another one. In short, it contains the address of another variable. We have seen the usefulness of references when passing values to a subroutine (Chapter 11). We can also use references, or pointers, to create more complex data types, such as a hash that contains a key followed by a list of values, or an array of arrays, etc. and we will need references in the next chapter when creating Perl objects.

13.1.1. Symbolic versus Hard References

A hard reference is a scalar variable that holds the address of another type of data. It is similar to a pointer found in the C programming language.[1] This chapter will focus on hard references.

[1] Unlike C pointers, Perl pointers are strings and you cannot perform pointer arithmetic with them.

A Perl variable resides in a symbol table and holds only one hard reference to its underlying value. Its value may be as simple as a single number or as complex as a hash. There may be other hard references that point to the same value, but the variable that actually holds the value is unaware of them.

A symbolic reference names another variable rather than just pointing to a value.[2] Typeglobs, variable names preceded by *, are a kind of symbolic reference. They are aliases.

[2] Wall, L., Programming Perl, O'Reilly & Associates: Sebastopol, CA, 1996, p. 244.

You may remember using typeglobs in previous examples. In Chapter 11, we discussed how typeglobs were used in the early days of Perl to pass arguments to subroutines by reference. In Chapter 12, typeglobs were used to import symbols onto the symbol table of a package. The following statement uses typeglobs:

 *town = *city;   # Any type called city can also be referenced as town

The asterisk represents all of the funny characters that prefix variables, including subroutines, filehandles, and formats; i.e., it "globs" onto all the symbols in the symbol table that have that name.[3] *town is an alias for *city. It is your job to determine what symbol you want the alias to reference. This is done by prepending the correct funny character to the alias name when you want to access its underlying value. For example:

[3] This is not the same as the globbing done for filename substitution, as in <p*>.

Given:*town = *city
Then:$town refers to the scalar $city

@town refers to the array @city

$town{"mayor"} refers to an element of a hash $city{"mayor"}


Example 13.1 demonstrates another type of symbolic reference where the value of one variable references the name of another variable.

Example 13.1.

    #!/bin/perl
    # Program using symbolic references
1   $animal="dog";
2   $dog="Lady";
3   print "Your dog is called ${$animal}\n";# Symbolic reference
4   eval "\$$animal='Lassie';";
5   print "Why don't you call her ${$animal}?\n";

(Output)
3   Your dog is called Lady
5   Why don't you call her Lassie?

Explanation

  1. The scalar $animal is assigned the value "dog". The name animal is stored in the symbol table along with a reference to its value dog.

  2. The scalar $dog is assigned the string "Lady".

  3. The variable ${$animal} evaluates to Lady. This is a symbolic reference. $animal, one variable, is evaluated to dog. The second dollar sign causes another variable, $dog, to be evaluated to its underlying value, "Lady". One variable has referenced another.

  4. The eval function evaluates the statement as if in a separate little Perl program. The first dollar sign is escaped. $animal will be evaluated to its value, dog. The literal dollar sign, prepended to the result of the evaluation, leaves $dog="Lassie" as the statement.

  5. After the eval, the value of ${$animal}; i.e., $dog is "Lassie". It is printed.

The strict Pragma

To protect yourself from inadvertently using symbolic references in a program, use the strict pragma with the refs argument. This causes Perl to check that symbolic references are not used in the program. Here, we reexecute the previous example using the strict pragma.

Example 13.2.

    #!/bin/perl
    # Program using symbolic references
1   use strict "refs";
2   $animal="dog";
3   $dog="Lady";
4   print "Your dog is called ${$animal}\n";
5   eval "\$$animal='Lassie';";
6   print "Why don't you call her ${$animal}?\n";

(Output)
Can't use string ("dog") as a SCALAR ref while "strict refs" in use at
symbolic.plx line 4.

Explanation

1The strict pragma ensures that the program uses only hard references and, if it doesn't, will abort during compilation and print an error message as shown in the output of this script.
3This is line number 10 in the script. The program died at this point because of the first use of a symbolic reference, ${$language}.
4This line also includes a symbolic reference but is never reached, because the program had already aborted because strict caught it.


13.1.2. Hard References, Pointers

We discussed pointers in Chapter 11 when passing references to a subroutine. To reiterate: A hard reference is a scalar that holds the address of another data type. A variable that is assigned an address can also be called a pointer because it points to some other address or to another reference. This type of reference can point to a scalar, array, associative array, or a subroutine. The pointer was introduced in Perl 5 to give you the ability to create complex data types, such as arrays of arrays, arrays of hashes, hashes of hashes, etc. In all of the examples where typeglobs were used, we can now opt for pointers instead. Pointers provide a way to pass parameters to subroutines by reference.

The Backslash Operator

The backslash unary operator is used to create a hard reference, similar to the & used in C to get the "address of." In the following example, $p is the reference. It is assigned the address of the scalar $x.

$p = \$x;

An example of hard references from the Perl man page perlref:

$scalarref = \$foo;       # reference to scalar $foo
$arrayref  = \@ARGV;      # reference to array @ARGV
$hashref   = \%ENV;       # reference to hash %ENV
$coderef   = \&handler;   # reference to subroutine handler
$globref   = \*STDOUT;    # reference to typeglob STDOUT
$reftoref  = \$scalarref; # reference to another reference
                             (pointer to pointer, ugh)

Dereferencing the Pointer

If you print the value of a reference (or pointer), you will see an address. If you want to go to that address and get the value stored there—that is, dereference the pointer—the pointer must be prefaced by two "funny" symbols. The first is the dollar sign, because the pointer itself is a scalar, and preceding that goes the funny symbol representing the type of data to which it points. When using more complex types, the arrow (infix) operator can be used.

Example 13.3.

(The Script)
    #!/bin/perl
1   $num=5;
2   $p = \$num;      # $p gets the address of $num
3   print 'The address assigned $p is ', $p, "\n";
4   print "The value stored at that address is $$p\n"; # dereference

(Output)
3   The address assigned $p is SCALAR(0xb057c)
4   The value stored at that address is 5

Explanation

  1. The scalar $num is assigned the value 5.

  2. The scalar $p is assigned the address of $num. This is the function of the backslash operator. $p is called either a reference or a pointer; the terms are interchangeable.

  3. The address stored in $p is printed. Perl also tells you the data type is SCALAR.

  4. To dereference $p, another dollar sign is prepended to $p. This dollar sign tells Perl that you are looking for the value of the scalar that $p references; i.e., $num.

Example 13.4.

    #!/bin/perl
1  @toys = qw( Barbie Elmo Thomas Barney );
2  $num = @toys;
3  %games=("Nintendo"  => "Wii",
           "Sony"      => "PlayStation 3",
           "Microsoft" => "XBox 360",
         );
4  $ref1 = \$num;  # Create pointers
5  $ref2 = \@toys;
6  $ref3 = \%games;

7  print "There are $$ref1 toys.\n"; # dereference pointers
8  print "They are: ",join(",",@$ref2), ".\n";
9  print "Jessica's favorite toy is $ref2->[0].\n";
10 print "Willie's favorite toy is $ref2->[2].\n";

11 while(($key,$value)=each(%$ref3)){
      print "$key => $value\n";
   }
12 print "They waited in line for a $ref3->{'Nintendo'}\n";

(Output)
There are 4 toys.
They are: Barbie,Elmo,Thomas,Barney.
Jessica's favorite toy is Barbie.
Willie's favorite toy is Thomas.
Microsoft => XBox 360
Sony => PlayStation 3
Nintendo => Wii
They waited in line for a Wii

					  

Explanation

  1. A list is assigned to the array @toys.

  2. The array @toys is assigned to the scalar variable $num, returning the number of elements in the array.

  3. The hash %games is assigned key/value pairs.

  4. The pointer $ref1 is a pointer. It is assigned the address of the scalar $num by using the backslash operator.

  5. The pointer $ref2 is assigned the address of the array @toys.

  6. The pointer $ref3 is assigned the address of the hash %games.

  7. The pointer is dereferenced, meaning: Go to the address that $ref1 is pointing to and print the value of the scalar stored there.

  8. The pointer is again dereferenced, meaning: Go to the address that $ref2 is pointing to, get the array, and print it.

  9. The -> arrow operator is used to dereference the pointer and get the first element of the array. (This could also be written as $$ref2[0].)

  10. Again the -> arrow operator is used to dereference the pointer and retrieve the third element of the array.

  11. The each function is used to retrieve the keys and values from the hash via its pointer. To dereference a hash, the % sign precedes the pointer variable.

  12. The -> arrow operator is used to dereference the pointer and get the value of the hash where the key is "Nintendo". (This could also be written as $$ref3{"Nintendo"}.)

13.1.3. References and Anonymous Variables

It is not necessary to name a variable to create a reference (pointer) to it. If a variable or subroutine has no name, it is called anonymous. If an anonymous variable (or subroutine) is assigned to a scalar, then the scalar is a reference to that variable (subroutine).

The arrow operator (–>), also called the infix operator, is used to dereference the reference to anonymous arrays and hashes. Although not really necessary, the arrow operator makes the program easier to read.

Anonymous Arrays

Anonymous array elements are enclosed in square brackets ([]). These square brackets are not to be confused with the square brackets used to subscript an array. Here they are used as an expression to be assigned to a scalar. The brackets will not be interpolated if enclosed within quotes. The arrow (infix) operator is used to get the individual elements of the array.

Example 13.5.

(The Script)
    #!/bin/perl
1   my $arrayref = [ 'Woody', 'Buzz', 'Bo', 'Mr. Potato Head' ];
2   print "The value of the reference, \$arrayref is ",
                                       $arrayref, "\n";
    # All of these examples dereference $arrayref
3   print "$arrayref->[3]", "\n";
4   print $$arrayref[3], "\n";
5   print ${$arrayref}[3], "\n";
6   print "@{$arrayref}", "\n";

(Output)
2   The value of the reference, $arrayref is ARRAY(0x8a6f134)
3   Mr. Potato Head
4   Mr. Potato Head
5   Mr. Potato Head
6   Woody Buzz Bo Mr. Potato Head

Explanation

1The anonymous array elements are assigned to the array reference $arrayref.
2The array reference contains the data type and the hexadecimal address of the anonymous array.
3The fourth element of the array is printed. The pointer variable $arrayref is followed by the arrow operator pointing to the index value that will be retrieved.
4The arrow operator is not really needed here. Instead, the element can be accessed by the two methods in lines 4 and 5.
6The entire array is printed after dereferencing the pointer. Curly braces are required.


Anonymous Hashes

An anonymous hash is created by using curly braces ({}). You can mix array and hash composers to produce complex data types. These braces are not the same braces that are used when subscripting a hash. The anonymous hash is assigned to a scalar reference.

Example 13.6.

(The Script)
    #!/bin/perl
1   my $hashref = { "Name"=>"Woody",
                    "Type"=>"Cowboy"
                  };
2   print $hashref->{"Name"}, "\n\n";
3   print keys %$hashref, "\n";
4   print values %$hashref, "\n";

(Output)
2   Woody

3   NameType
4   WoodyCowboy

Explanation

  1. The anonymous hash contains a set of key/value pairs enclosed in curly braces. The anonymous hash is assigned to the reference $hashref.

  2. The hash pointer $hashref uses the arrow operator to dereference the hash. The key Name is associated with the value Woody.

  3. The keys function returns all the keys in the anonymous hash via the reference (pointer).

  4. The values function returns all the values in the anonymous hash via the reference (pointer).

13.1.4. Nested Data Structures

The ability to create references (pointers) to anonymous data structures lends itself to more complex types. For example, you can have hashes nested in hashes or arrays of hashes or arrays of arrays, etc.

Just as with simpler references, the anonymous data structures are dereferenced by prepending the reference with the correct funny symbol that represents its data type. For example, if $p is a pointer to a scalar, you can write $$p to dereference the scalar, and if $p is a pointer to an array, you can write @$p to dereference the array or $$p[0] to get the first element of the array. You can also dereference a pointer by treating it as a block. $$p[0] could also be written ${$p}[0] or @{p}[0..3]. Sometimes, the braces are used to prevent ambiguity, and sometimes they are necessary so that the funny character dereferences the correct part of the structure.

Lists of Lists

A list may contain another list or set of lists, most commonly used to create a multidimensional array. A reference is assigned an anonymous array containing another anonymous array in Examples 13.7 and 13.8.

Example 13.7.

    #!/bin/perl
    # Program to demonstrate a reference to a list with a
    # nested list
1   my $arrays = [ '1', '2', '3', [ 'red', 'blue', 'green' ]];
2   for($i=0;$i<3;$i++){
3       print $arrays->[$i],"\n";
    }

4   for($i=0;$i<3;$i++){
5       print $arrays->[3]->[$i],"\n";
    }
6   print "@{$arrays}\n";
7   print "--@{$arrays->[3]}--", "\n";

(Output)
3   1
    2
    3
5   red
    blue
    green

6   1 2 3 ARRAY(0x8a6f134)
7   --red blue green--

Explanation

  1. $arrays is a reference (pointer) to a four-element array that contains another anonymous three-element array whose elements are red, blue, and green.

  2. The for loop is used to get the values of the first array, consisting of elements 1, 2, and 3.

  3. The arrow operator is used here to dereference $arrays.

  4. The second for loop is used to iterate through the nested anonymous array. Since this array is the fourth element of the first array, starting at subscript 0, the first index is 3 and the second index references each of its elements.

  5. Each of the elements (red, blue, green) of the nested anonymous array is printed.

  6. By prepending the @ symbol to the block containing the reference, the elements of the anonymous array are retrieved and printed. The third element of the array is a reference (pointer) to another anonymous hash. Its address is printed.

  7. The second nested array is dereferenced and printed.

Example 13.8.

(The Script)
    #!/bin/perl
    # Program to demonstrate a pointer to a two-dimensional array.
1   my $matrix = [
                [ 0, 2, 4 ],
                [ 4, 1, 32 ],
                [ 12, 15, 17 ]
               ] ;

2   print "Row 3 column 2 is $matrix->[2]->[1].\n";

3   print "Dereferencing with two loops.\n";
4   for($x=0;$x<3;$x++){
5       for($y=0;$y<3;$y++){
6          print "$matrix->[$x]->[$y] ";
        }
        print "\n\n";
    }
    print "\n";
7   print "Derefencing with one loop.\n";
8   for($i = 0; $i < 3; $i++){
9      print "@{$matrix->[$i]}", "\n\n";
    }
10  $p=\$matrix;     # Reference to a reference
11  print "Dereferencing a reference to reference.\n"
12  print ${$p}->[1][2], "\n";
(Output)
2   Row 3 column 2 is 15.
3   Dereferencing with two loops.
6   0 2 4
    4 1 32
    12 15 17

7   Dereferencing with one loop.
9   0 2 4
    4 1 32
    12 15 17

11  Dereferencing a reference to reference.
12  32

					  

Explanation

1The reference (pointer) $matrix is assigned an anonymous array of three anonymous arrays; that is, a two-dimensional array (list of lists).
2The arrow operator is used to access the first element of the array. An arrow is implied between adjacent subscript brackets and is not needed. It could have been written as $matrix–>[2][1].
4The outer for loop is entered. This will iterate through the rows of the array.
5The inner for loop is entered. This loop iterates through the columns of the array.
6Each element of the two-dimensional array is printed via the reference (pointer).
8This time, only one for loop will be used to print out the contents of the matrix.
9The block format is used to dereference the pointer. All elements of each list are printed.
10$p is a reference assigned another reference, $matrix. This is more commonly called a pointer to a pointer.
12If you want to access the array elements—that is, dereference $p—an additional dollar sign is needed, one for p and one for matrix. The arrow is implied between the adjacent subscripts; for example, this line could have been written $p–>[1]–>[2].


Array of Hashes

A list may contain a hash or a set of hashes. In Example 13.9, a reference is assigned an anonymous array containing two anonymous hashes.

Example 13.9.

1   my $petref = [   { "name"  => "Rover",
                       "type"  => "dog",
                       "owner" => "Mr. Jones",
                     },
2                    { "name"  => "Sylvester",
                       "type"  => "cat",
                       "owner" => "Mrs. Black",
                     }
3                ];


4   print "The first pet's name is $petref->[0]->{name}.\n";
    print "Printing an array of hashes.\n";
5   for($i=0; $i<2; $i++){
6      while(($key,$value)=each %{$petref->[$i]} ){
7         print "$key -- $value\n";
       }
       print "\n";
    }
    print "Adding a hash to the array.\n";

8   push @{$petref},{ "owner"=>"Mrs. Crow", "name"=>"Tweety",
                      "type"=>"bird" };

9   while(($key,$value)=each %{$petref->[2]}){
10     print "$key -- $value\n";
    }

(Output)
4   The first pet's name is Rover.
    Printing an array of hashes.
7   owner -- Mr. Jones
    type -- dog
    name -- Rover

    owner -- Mrs. Black
    type -- cat
    name -- Sylvester

    Adding a hash to the array.
10  type -- bird
    owner -- Mrs. Crow
    name -- Tweety

					  

Explanation

  1. The reference (pointer) $petref is assigned the address of an anonymous array containing two anonymous hashes.

  2. This is the second element of the list, an anonymous hash with its key/value pairs.

  3. This is the closing square bracket for the anonymous array.

  4. The pointer $petref is used to dereference the list, first by selecting the zeroth element of the array and, with the arrow operator, selecting the key in the hash. The value associated with the key name is displayed.

  5. The for loop is entered to loop through the list.

  6. The while loop is entered. Each time through the loop, a key and a value are extracted from the hash pointed to by $petref–>[$i] and assigned to $key and $value, respectively.

  7. The key/value pairs are displayed.

  8. A new hash is pushed onto the array, @{$petref}, with the push function.

  9. The while loop is entered. Each time through the loop, a key and a value are extracted from the hash pointed to by $petref–>[0] and assigned to $key and $value, respectively. The new hash that was pushed on will be displayed.

  10. After dereferencing $petref, the second element of the array, $petref–>[0], is dereferenced, and each of the key/value pairs of the nested hash is displayed.

Hash of Hashes

A hash may contain another hash or a set of hashes. In Example 13.10, a reference is assigned an anonymous hash consisting of two keys, each of which is associated with a value that happens to be another hash (consisting of its own key/value pairs).

Example 13.10.

    #!/bin/perl
    # Program to demonstrate a hash containing anonymous hashes.
1   my $hashref = {
2                   Math    => {                    # key
                                 "Anna"  => 100,
                                 "Hao"   => 95,     # values
                                 "Rita"  => 85,
                               },
3                   Science => {                    # key
                                 "Sam"   => 78,
                                 "Lou"   => 100,    # values
                                 "Vijay" => 98,
                               },
4                 };

5   print "Anna got $hashref->{'Math'}->{'Anna'} on the Math test.\n";
6   $hashref->{'Science'}->{'Lou'}=90;
7   print "Lou's grade was changed
    to $hashref->{'Science'}->{'Lou'}.\n";
8   print "The nested hash of Math students and grades is: ";
9   print %{$hashref->{'Math'}}, "\n";   # Prints the nested hash, Math
10  foreach $key (keys %{$hashref}){
11     print "Outer key: $key \n";
12     while(($nkey,$nvalue)=each(%{$hashref->{$key}})){
13        printf "\tInner key: %-5s -- Value: %-8s\n",
                                       $nkey,$nvalue;
       }
    }

(Output)
5   Anna got 100 on the Math test.
7   Lou's grade was changed to 90.
8   The nested hash of Math students and grades is: Rita85Hao95Anna100
11  Outer key: Science
13  Inner key: Lou   -- Value: 90
    Inner key: Sam   -- Value: 78
    Inner key: Vijay -- Value: 98
11  Outer key: Math
13  Inner key: Rita  -- Value: 85
    Inner key: Hao   -- Value: 95
    Inner key: Anna  -- Value: 1005
    Anna got 100 on the Math test.

					  

Explanation

1The anonymous hash is defined. It consists of two hash keys, Math and Science, whose values are themselves a hash (key/value pair). The address of the hash is assigned to $hashref. $hashref is a hard reference (pointer).
2Math is the key for its value, a nested hash.
3Science is the key for its value, also a nested hash.
4This is the closing curly brace of the anonymous hash.
5To access Anna's grade, first the key Math is dereferenced, followed by the arrow operator and the nested key Anna. The second arrow is not necessary but may make the construct easier to follow. In fact, you don't need to use the arrow operator at all. This could have been written as $$hashref{Math}{Anna}.
6Using the $hashref reference, you can also change or add new values to the hash. Lou's grade is changed.
7The new grade is printed by dereferencing $hashref.
8, 9The nested hash Math is printed by enclosing the reference $hashref–>Math in curly braces prepended by a %. The % represents the unnamed hash, both keys and values.
10The foreach loop iterates through the list (produced by the keys function) of outer keys in the anonymous hash.
11Each of the outer keys is printed.
12Since each of the outer keys is associated with a value that happens to be another hash, the reference $hashref is dereferenced by placing $hashref–>{$key} in a block prepended by a percent sign.
13The nested keys and their associated values are printed.


Hash of Hashes with Lists of Values

A hash may contain nested hash keys associated with lists of values. In Example 13.11, a reference is assigned two keys associated with values that are also keys into another hash. The nested hash keys are, in turn, associated with an anonymous list of values.

Example 13.11.

(The Script)
    # A hash with nested hash keys and anonymous arrays of values
1   my $hashptr = { "Teacher"=>{"Subjects"=>[ qw(Science Math English)]},
                    "Musician"=>{"Instruments"=>[ qw(piano flute harp)]},
                  };
                  # Teacher and Musician are keys.
                  # The values consist of nested hashes.
2   print $hashptr->{"Teacher"}->{"Subjects"}->[0],"\n";
3   print "@{$hashptr->{'Musician'}->{'Instruments'}}\n";

(Output)
2   Science
3   piano flute harp

Explanation

  1. The pointer $hashptr is assigned an anonymous hash consisting of two keys, Teacher and Musician. The values for Teacher consist of another anonymous hash with a key, Subjects, associated with an anonymous array of values, Science, Math, and English. The key Musician also consists of an anonymous hash with a key, Instruments, associated with an anonymous array of values, piano, flute, and harp.

  2. To dereference the pointer, the arrow operator is used to separate the nested keys. The final arrow refers to the first element of the array of values associated with Subjects, Science.

  3. To get all the values from the anonymous array associated with the key, the @ symbol precedes the pointer and its nested keys, each key separated with the arrow operator. If a variable has no name, you can replace its name with a block preceded by the symbol for the correct data type. Here, the curly braces enclosing the entire structure allow you to dereference the whole block as an array.

13.1.5. References and Subroutines

Anonymous Subroutines

An anonymous subroutine is created by using the keyword sub without a subroutine name. The expression is terminated with a semicolon. For more on using anonymous subroutine, see "Closures" in Chapter 14.

Example 13.12.

(The Script)
    #!/bin/perl
1   my $subref = sub { print @_ ; };
2   &$subref('a','b','c');
    print "\n";

(Output)
1    abc

Explanation

  1. The scalar $subref is assigned an anonymous subroutine by reference. The only function of the subroutine is to print its arguments stored in the @_ array.

  2. The subroutine is called via its reference and passed three arguments.

Subroutines and Passing by Reference

When passing arguments to subroutines, they are sent to the subroutine and stored in the @_ array. If you have a number of arguments, say an array, a scalar, and another array, the arguments are all flattened out onto the @_ array. It would be hard to tell where one argument ended and the other began unless you also passed along the size of each of the arrays, and then the size would be pushed onto the @_ array and you would have to get that to determine where the first array ended, and so on. The @_ could also be quite large if you are passing a 1,000-element array. So, the easiest and most efficient way to pass arguments is by address, as shown in Example 13.13.

Example 13.13.

(The Script)
1   @toys = qw(Buzzlightyear  Woody  Bo);
2   $num = @toys;  # Number of elements in @toys is assigned to $num
3   gifts( \$num, \@toys );    # Passing by reference

4   sub gifts {
5       my($n, $t) = @_;   # Localizing the reference with 'my'
6       print "There are $$n gifts: ";
7       print "@$t\n";
8       push(@$t, 'Janey', 'Slinky');
    }
9   print  "The original array was changed to: @toys\n";

(Output)
6,7 There are 3 gifts: Buzzlightyear Woody Bo
9   The original array was changed to: Buzzlightyear Woody Bo Janey Slinky

Explanation

  1. The array @toys is assigned three values.

  2. The scalar $num is assigned the number of elements in the @toys array. (Remember, a scalar contains only one value, so when you assign an array to a scalar, the number of elements in the array is assigned to the scalar.)

  3. The subroutine gifts is called with two pointers as parameters.

  4. The subroutine is entered.

  5. The @_ array contains the two pointer variables. The values of the pointers are copied into two lexical variables, $n and $t.

  6. The pointer to the scalar is dereferenced. It points to the scalar $n.

  7. The pointer to the array is dereferenced. It points to the array @toys.

  8. The push function adds two new elements to the array pointed to by $t.

  9. After exiting the subroutine, @toys is printed with its new values.

Example 13.14.

Explanation

1The array @list1 is assigned a list of numbers between 1 and 100.
2The array @list2 is assigned the list of numbers 5, 10, 15, and 20.
3The addemup subroutine is called. Two parameters are passed. The backslash preceding each of the arrays causes the addresses (pointers) to be passed.
4The subroutine addemup is declared and defined.
5The pointers are passed to the @_ array and assigned to my variables $arr1 and $arr2, respectively.
6The my variable $total is declared.
7, 8The addresses of the pointers are printed.
9The foreach loop is entered. @$arr1 and @$arr2 dereference the pointers, creating a list of array elements to be processed, one at a time.
10Each time through the loop, $total accumulates the sum of $total + $num.
11The sum is returned to where the subroutine was called on line 3. Since the subroutine was called as an argument to the print function, the results will be printed after they are returned from the subroutine.


13.1.6. Filehandle References

One of the only ways to pass a filehandle to a subroutine is by reference. You can use a typeglob to create an alias for the filehandle and then use the backslash to create a reference to the typeglob. Wow...

Example 13.15.

(The Script)
    #!/bin/perl
1   open(README, "/etc/passwd") || die;

2   &readit(\*README);     # Reference to a typeglob

3   sub readit {
4       my ($passwd)=@_;
5       print "\$passwd is a $passwd.\n";
6       while(<$passwd>){
7          print;
        }
    }

9   seek(README,0,0) || die "seek: $!\n";
                      # Reset back to begining of job
(Output)
5   $passwd is a GLOB(0xb0594).
7   root:x:0:1:Super-User:/:/usr/bin/csh
    daemon:x:1:1::/:
    bin:x:2:2::/usr/bin:
    sys:x:3:3::/:
    adm:x:4:4:Admin:/var/adm:
    lp:x:71:8:Line Printer Admin:/usr/spool/lp:
    smtp:x:0:0:Mail Daemon User:/:
    uucp:x:5:5:uucp Admin:/usr/lib/uucp:
    nuucp:x:9:9:uucp Admin:/var/spool/uucppublic:/usr/lib/uucp/uucico
    listen:x:37:4:Network Admin:/usr/net/nls:
    nobody:x:60001:60001:Nobody:/:
    noaccess:x:60002:60002:No Access User:/:
    nobody4:x:65534:65534:SunOS 4.x Nobody:/:
    ellie:x:9496:40:Ellie Quigley:/home/ellie:/usr/bin/csh
9   seek: Bad file number

					  

Explanation

1The /etc/passwd file is attached to the README filehandle and opened for reading.
2The readit subroutine is called. The filehandle is passed by creating a reference to a typeglob. First, the filehandle symbol is globbed with the asterisk. Then, the reference to the typeglob is created by prefixing the typeglob with a backslash.
3The readit subroutine is defined.
4The @_ variable contains the reference. It is assigned to a local scalar variable called $passwd. $passwd is a reference to the filehandle.
5The reference $passwd, when printed, shows that it contains the address of a typeglob (alias).
6, 7The expression in the while loop causes a line to be read from the /etc/passwd file and assigned to the $_ variable. The line is printed to the screen. The loop will continue until all the lines have been read and printed.
9The seek function resets the read pointer for this file back to the begining of the file.


13.1.7. The ref Function

The ref function is used to test for the existence of a reference. If the argument for ref is a pointer variable, ref returns the type of data the reference points to; e.g., SCALAR is returned if the reference points to a scalar, and ARRAY is returned if it points to an array. If the argument is not a reference, the null string is turned. Table 13.1 lists the values returned by the ref function

Table 13.1. Return Values from the ref Function
What Is ReturnedMeaning
REFPointer to pointer
SCALARPointer to scalar
ARRAYPointer to array
HASHPointer to hash
CODEPointer to subroutine
GLOBPointer to typeglob


Example 13.16.

(The Script)
1   sub gifts;     # Forward declaration
2   $num = 5;
3   $junk = "xxx";
4   @toys = qw/Budlightyear Woody Thomas/ ;
5   gifts( \$num, \@toys, $junk );
6   sub gifts {
7       my( $n, $t, $j) = @_;
8       print "\$n is a reference.\n" if ref($n);
        print "\$t is a reference.\n" if ref($t);
9       print "\$j is a not a reference.\n" if ref($j);
10      printf "\$n is a reference to a %s.\n", ref($n);
11      printf "\$t is a reference to an %s.\n", ref($t);
    }

(Output)
8   $n is a reference.
    $t is a reference.
9
10  $n is a reference to a SCALAR.
11  $t is a reference to an ARRAY.

Explanation

  1. The subroutine gifts is a forward declaration, allowing Perl to know it is a subroutine defined somewhere in the program. You will not need an ampersand to call the subroutine if it is declared before it is defined.

  2. The scalar $num is assigned 5.

  3. The scalar $junk is assigned the string xxx.

  4. The array @toys is assigned a list.

  5. The subroutine gifts is called. The first two variables are passed as references by preceding them with a backslash. The last variable, $junk, is not passed as a reference.

  6. The subroutine gifts is defined.

  7. The values assigned to the @_ array, in this case, two references (addresses) and one nonreference, will be assigned to $n, $t, and $j, respectively, and made local with the my function.

  8. The ref function is called with a reference, $n, as its argument. The line will be printed only if the variable $n is a reference.

  9. $j is not a reference. The return value for the ref function is null.

  10. The printf function prints the value of the data type returned from ref, a scalar.

  11. The printf function prints the value of the data type returned from ref, an array.

Previous Page Next Page