parsifal has asked for the wisdom of the Perl Monks concerning the following question:

How can I pass an array to a sub? Here is my attempt:
@data = ($thing1, $thing2); &doStuff($arg1, $arg2, $arg3, $ar4, @data); ... sub doStuff { @info = $_[4]; print "@info"; }
The above code only outputs $thing1. I have tried using @_[4] with no luck, either.

Edit: chipmunk 2001-03-30

Replies are listed 'Best First'.
Re: passing an array
by Masem (Monsignor) on Mar 28, 2001 at 07:32 UTC
    Use references (see perlref). For example...
    my @data = qw( Mon Tue Wed Thurs Fri Sat Sun ); print get_day( $today, \@data ); sub get_day { my ( $index, $datar ) = @_; return $datar->[$index]; }

    Update: You know, it helps to have a @_ in a sub too :-/


    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
(Ovid - prototypes?) Re: passing an array
by Ovid (Cardinal) on Mar 28, 2001 at 12:15 UTC
    Also, you could consider using prototypes:
    use warnings; use strict; sub multipop(\@$); my @array = (1 .. 10); my @result = multipop @array, 3; print "@array\n"; print "@result\n"; sub multipop(\@$) { my $count = pop; my @vars; $count = 1 if ! defined $count; # default to normal pop behavior if ( $count =~ /^\d+$/ ) { my $length = scalar @{$_[0]}; $count = $length if $count > $length; # Using @{$_[0]} to ensure that we modify original array push @vars, splice ( @{$_[0]}, -$count, $count ) if $count > 0 +; return @vars; } else { warn "Second argument to multipop must be numeric: '$count'"; } }
    Notice the sub call:
    my @result = multipop @array, 3;
    Yup, you're passing an array to it, but Perl converts it to a reference to the array. Pretty handy, huh? You may want to read this discussion of prototypes and their limitations

    And yeah, that code above is a bit of a hack. If anyone sees problems with it, I'd love to know. It's basically the same thing as pop, but with an optional second argument specifying the number of elements to remove. It could be expanded to take a third argument specifying if the order of elements to remove is to be reversed. It does have a couple of advantages over splice (IMHO): it's easier to read and will not die if you try to pop more elements than the array has. Of course, some may not appreciate the latter "feature".

    Oh, and it's slower than splice, too :)

    Cheers,
    Ovid

    Update: Ugh! Stupid me. No third argument. Just make the second one negative for a reverse pop (and add the appropriate code, of course). Sheesh. I try to make things too hard, at times :)

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      A sledgehammer for a nut in his/her case I think,
      Nice sledgehammer though.....

Re: passing an array
by Xxaxx (Monk) on Mar 28, 2001 at 07:19 UTC
    One thing you may do is:
    sub doStuff { my($arg1, $arg2, $arg3, $ar4, @data) = @_; ..... # other stuff here }
    That will get the data in.
    I'm curious to see about better answers. I've been wondering about shift and other such alternate forms recently since I've noticed code examples using that form.

    Meanwhile this should get the the array.
    Now if your array were huge (not the two element array mentioned here) then passing by reference might be the way to go.

    But I figure if you're scaling the challenge of just getting data in, there's no point throwing variables by reference at you just yet.

    But do bookmark the thought it can be useful.
    HTH
    Claude p.s.

    my($arg1, $arg2, $arg3, $ar4, @data, $arg5) = @_;
    will not work. The @data will suck up all the vars leaving nothing in $arg5. Just a warning from someone who didn't know this at 3 a.m.
      I use shift and references like in the following example. Hope this helps.
      Roberto
      #!/usr/bin/perl use strict; my %hash; my @array; # here you pass the references and get them back my ($ref_hash,$ref_array) = load_variables(\%hash,\@array); # and then you pass these for printout print_variables($ref_hash,$ref_array); ################## sub load_variables { ################## my %hash1 = %{ shift() }; my @array1 = @{ shift() }; ### Load array @array1 = ('a','b','c'); ### Populate the hash (for each character ### set the hash to the next map { my $tmp = ++$_; $hash1{$_} = qq($tmp); } @array1; ### Return the references return (\%hash1,\@array1); } ################### sub print_variables { ################### my %hash2 = %{ shift() }; my @array2 = @{ shift() }; map { printf q(hash: ).qq($hash2{$_}\n) } keys %hash2; }
Re: passing an array
by the_slycer (Chaplain) on Mar 28, 2001 at 08:10 UTC
    Just to expand on the above answers. In your example you pass arg1, $arg2, $arg3, $ar4, @data to the sub. What @_ gets is
    $_[0] = $arg1, $_[1] = $arg2, $_[2] = $arg3, $_[3] = $arg4, $_[4] = $data[0], $_[5] = $data[1]
    So you can see by the above what is happening.

    The ways to do this are as mentioned above, pass a reference to the array and dereference it, or assign all of the arguments to variables and then assign the rest of the @_ array to @info..

    Update: per merlyn's comments below, have updated appropriately. Normally I would have written it like that, really not sure why I didn't in this case.
      Ouch. Please. @foo[0] hurts my eyes. Surely you meant to say:
      $_[0] = $arg1, $_[1] = $arg2, $_[2] = $arg3, $_[3] = $arg4, $_[4] = $data[0], $_[5] = $data[1]
      A single-element slice is almost never what people want. Warnings-on would have told you that.

      -- Randal L. Schwartz, Perl hacker

Re: passing an array
by stephen (Priest) on Mar 28, 2001 at 07:58 UTC
    '@_' contains all parameters passed to a subroutine. Read perlman:perlsub.
    sub doStuff { @info = @_; print "@info"; }
    That will copy everything that you passed to &doStuff into @info.

    stephen

Re (tilly) 1: passing an array
by tilly (Archbishop) on Mar 28, 2001 at 10:09 UTC
    Please use CODE tags rather than doing your layout.

    Among other advantages is that there will be a d/l link that people can use to get your code directly so they can test it...

Re: passing an array
by ProfessorHaroldHill (Initiate) on Mar 28, 2001 at 18:36 UTC
    Perl treats everything passed as scalar, so as the good brothers before me agree use a reference
    $array = \@array; pass_this($anythingelse,$array); sub pass_this(){ my($firstpassedthing,$array_ref) = (@_); @local_array = @{$array_ref}; # now you can play with $local_array[] }
    The sadder but wiser Perl for me ...

    Edit: chipmunk 2001-03-30

Re: passing an array
by tame1 (Pilgrim) on Mar 28, 2001 at 19:55 UTC
    Given the tedious nature of stripping @_, perhaps using references would make your life easier. That way you could use -> notation, or break the ref back into an array, etc. Either way, it's gotta be better that manually setting things with my $var = $_[0], etc.

    What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"