2

Consider:

sub abc()
{

}

abc(@array, $a);

How do I access @array and $a in subroutine abc()?

I know about $_[0] and $_[1], but I wasn't sure if I can use it for arrays.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Daanish
  • 1,061
  • 7
  • 18
  • 29
  • 3
    I'm going to suggest my writeup here: http://stackoverflow.com/questions/5680147/perl-passing-2-or-more-arrays-to-a-subroutine/5681178#answer-5681178 – Axeman Oct 18 '12 at 11:34

4 Answers4

6

You access a sub's arguments with the @_ array. The first argument is $_[0], the second - $_[1], etc. In this particular case, your array will be unrolled to list of its elements, so $_[0] is $array[0], $_[1] is $array[1] and then after all those elements, last element of @_ will be the value of $a.

If you want to avoid unrolling that always happens when you use an array in a list context, use a reference to the array instead. References to arrays and hashes are created using \. So call your function like:

abc(\@array, $a);

After that, $_[0] will have reference to @array and $_[1] will be $a. To access array elements through reference, use -> operator. $_[0]->[2] is same as $array[2]. Actually you can even drop -> as long as it is between brackets, so $_[0][2] will work too. See more details on references in perlref.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Oleg V. Volkov
  • 21,719
  • 4
  • 44
  • 68
6

You have two options:

  1. Pass the scalar variable first (the dirty way)

    abc($a, @array);
    

    Then receive the parameters in subroutine as

    my ($a, @array) = @_;
    
  2. Pass your array as reference by adding a backslash before the array variable (recommended)

    abc(\@array, $a);
    

    Then receive the parameters in subroutine as

    my ($array_ref, $a) = @_;
    

    And dereference the $array_ref

    my @array = @$array_ref;
    

More information about perlref.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jchips12
  • 1,177
  • 1
  • 11
  • 27
  • 7
    The first way isn't dirty in my humble opinion. It has [different semantics](https://gist.github.com/3910729). – memowe Oct 18 '12 at 09:36
  • I agree it has different semantics. I say dirty because it will lead to something else if you have a third variable to pass other than scalar. – jchips12 Oct 18 '12 at 09:56
  • 2
    The first method is used by various built-in functions (`join` and `sprintf`, for example). There is nothing wrong with it as long as it fits what you are doing. – dan1111 Oct 18 '12 at 11:43
2

The other answers explained the two basic approaches. However, it is important to note that there is a big difference between the two: When you pass an array by reference, any changes you make to it also change the original array. Here is an example:

use warnings;
use strict;

my @array = (1, 2, 3, 4, 5);

sub by_ref
{
    my $array_ref = $_[0];
    @$array_ref = (0, 0, 0);
    print "Array inside by_ref: @$array_ref\n";
}

sub by_val
{
    my @array_copy = @_;
    @array_copy = (0,0,0);
    print "Array inside by_val: @array_copy\n";
}

by_val(@array);

print "Original array after calling by_val: @array\n";

by_ref(\@array);

print "Original array after calling by_ref: @array\n";

If you do pass by reference, you need to keep this behavior in mind, making a copy of the referenced array if you don't want changes made in your sub to affect the original.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dan1111
  • 6,576
  • 2
  • 18
  • 29
  • 2
    You can change without reference just as easily. Try: `sub change { $_[1] = 42 }; my @arr = (1, 2, 3); change(@arr); print $arr[1], "\n";` – Oleg V. Volkov Oct 18 '12 at 12:29
  • 2
    @OlegV.Volkov, yes, that is a good point. However, I think the distinction between the two is still important. Normal convention is to copy passed parameters from `@_` into lexical variables, but with pass-by-reference that doesn't stop you from modifying the original. – dan1111 Oct 18 '12 at 12:49
  • If I need the changes to reflect in my original array what will I have to do. If the answer is too big please post it as another answer...Thank you dan1111. – Daanish Oct 19 '12 at 06:16
  • @Daanish, using pass-by-reference, as illustrated above in the sub `by_ref`, will change the original array. Alternatively, you could alter `@_` directly as Oleg V. Volkov showed in his comment. – dan1111 Oct 19 '12 at 07:42
0

It would be nice if you pass the array reference instead of an array as mentioned by Oleg V. Volkov like

sub abc()
{
    my ( $array, $a ) = @_; #receiving the paramters
    my @arr = @{$array}; # dereferencing the array
}

abc(\@array,$a);
Nikhil Jain
  • 8,232
  • 2
  • 25
  • 47