Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

Array value changing for some reason

by Silt (Novice)
on Dec 31, 2018 at 22:18 UTC ( #1227848=perlquestion: print w/replies, xml ) Need Help??

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

I found a problem where I get a different result when printing an array after calling a function, that shouldn't be able to change the array. I got the issue down to this:
use strict; use warnings; main(); sub main { problem([[0,1,2],[3,4,5],[6,7,8]]); } sub problem { print3DArray("\@_",@_);#Output: 0 1 2 3 4 5 6 7 8 reverseArray(@_); print3DArray("\@_",@_);#Output: 6 7 8 3 4 5 0 1 2 } sub reverseArray { for(my $i=0;$i<scalar(@_);$i++){ @{$_[$i]} = reverse @{$_[$i]}; } } sub print3DArray { print shift @_, ":\n"; for(my $i=0;$i<scalar(@_);$i++){ print2DArray(@{$_[$i]}); } } sub print2DArray { for(my $i=0;$i<scalar(@_);$i++){ for(my $j=0;$j<scalar(@{$_[$i]});$j++){ print $_[$i][$j]," "; } print "\n"; } print "\n"; }
@_ should stay the same, since I didn't return anything. I would appreciate any help! Thanks!

Replies are listed 'Best First'.
Re: Array value changing for some reason
by choroba (Archbishop) on Dec 31, 2018 at 22:42 UTC
    return doesn't change @_.

    @_ is an array of aliases to the actual arguments, so changing @_ changes the actual arguments.

    sub { ++$_ for @_ }->(my @arr = 'a' .. 'c'); print "@arr"; # Output: b c d

    In your case, it's bit more complex. Changing the function to

    sub reverseArray { my @arr = @_; for my $i (0 .. $#arr) { @{ $arr[$i] } = reverse @{ $arr[$i] }; } }
    wouldn't have helped, as you're working with an array of arrays. The inner arrays are represented as references, so even if you store the references in a different @arr, they still refer to the same inner arrays.

    To keep the array unchanged, only assign to the copy, don't change the references from the original array.

    sub reverseArray { my @arr = @_; for my $i (0 .. $#arr) { $arr[$i] = [ reverse @{ $arr[$i] } ]; } }
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Thanks, that helped! Even tough I don't understand what "for my $i (0 .. $#arr)" means, changing
      sub reverseArray { for(my $i=0;$i<scalar(@_);$i++){ @{$_[$i]} = reverse @{$_[$i]}; } }
      sub reverseArray { my @arr = @_; for(my $i=0;$i<scalar(@arr);$i++){ $arr[$i] = [reverse @{$arr[$i]}]; } }
      did the trick!

      So, if I understand it correctly, a subroutine can change variables from the function it was called from.

        Even though I don't understand what "for my $i (0 .. $#arr)"

        $#array is the index of the last element of @array. Which is the same as the scalar(@array)-1;

        a subroutine can change variables from the function it was called from

        Yes, if you modify @_, it changes for the caller.

        ... I don't understand what "for my $i (0 .. $#arr)" means ...

        The other point to remember about this type of loop (a so-called Perl-style for-loop) is that is "topicalizes" (see "topic" in perlglossary)  $i or whatever variable you specify, or implicitly  $_ if you don't explicitly specify any variable, to each element of the loop list; see Foreach Loops in perlsyn. Also note that foreach and for are exactly synonymous and completely interchangeable keywords in Perl; the differing behavior of Perl- and C-style for/foreach-loops is determined by the syntax of the loop list expression.

        Give a man a fish:  <%-{-{-{-<

Re: Array value changing for some reason
by kschwab (Vicar) on Dec 31, 2018 at 22:44 UTC
    You don't have to return anything to change an array.
    #!/usr/bin/perl sub plus { for (@_) {$_++} } my @foo=(1,2,3,4); plus(@foo); for(@foo) {print "$_\n"};
    Prints out:
Re: Array value changing for some reason
by AnomalousMonk (Bishop) on Jan 01, 2019 at 00:26 UTC

    Note also that with aliasing of the elements of the special  @_ subroutine arguments array (see perlvar), it's "turtles all the way down:"

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le "sub going_down { sublevel_1(@_); } sub sublevel_1 { sublevel_2(@_); } sub sublevel_2 { sublevel_3(@_); } sub sublevel_3 { $_[-1] = 'foo'; } ;; my @ra = qw(a b c d); dd \@ra; ;; going_down(@ra); dd \@ra; " ["a", "b", "c", "d"] ["a", "b", "c", "foo"]

    Give a man a fish:  <%-{-{-{-<

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1227848]
Approved by marto
Front-paged by haukex
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2021-10-22 08:00 GMT
Find Nodes?
    Voting Booth?
    My first memorable Perl project was:

    Results (85 votes). Check out past polls.