1

How do I dereference an array of arrays when passed to a function?

I am doing it like this:

my @a = {\@array1, \@array2, \@array3};

func(\@a);


func{
    @b = @_;

    @c = @{@b};
}

Actually I want the array @c should contain the addresses of @array1, @array2, and @array3.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jack
  • 491
  • 2
  • 7
  • 14
  • 3
    I don't think `@a={\@array1, \@array2, \@array3}` does what you think it does. – mob Oct 13 '10 at 15:05
  • 7
    So many misunderstandings in so few lines of code. – Dave Cross Oct 13 '10 at 15:10
  • 1
    Perl has references, not pointers (like C). You can't get the address of a variable, and you don't need to. (To any sufficiently skilled Perl hackers who feel compelled to point out that this isn't 100% accurate: Don't. The OP is confused enough already.) – Michael Carman Oct 13 '10 at 15:16
  • 2
    If you don't first try running your code with `use strict; use warnings;`, you are wasting everyone's time (including your own, which I assume is most precious to you). – Ether Oct 13 '10 at 16:12

5 Answers5

8
my @a = {\@array1, \@array2, \@array3};

The above is an array with a single member -> a hash containing:

{ ''.\@array1 => \@array2, ''.\@array3 => undef }

Because as a key in the hash, Perl coerces the reference to @array1 into a string. And Perl allows a scalar hash reference to be assigned to an array, because it is "understood" that you want an array with the first element being the scalar you assigned to it.

You create an array of arrays, like so:

my @a = (\@array1, \@array2, \@array3);

And then in your function you would unpack them, like so:

sub func {
    my $ref = shift;
    foreach my $arr ( @$ref ) {
        my @list_of_values = @$arr;
    }
}

Or some variation thereof, like say a map would be the easiest expression:

my @list_of_entries = map { @$_ } @$ref;

In your example, @c as a list of addresses is simply the same thing as a properly constructed @a.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Axeman
  • 29,660
  • 2
  • 47
  • 102
6

You may want to read perldoc perlreftut, perldoc perlref, and perldoc perldsc You can say:

sub func {
    my $arrayref = shift;

    for my $aref (@$arrayref) {
        print join(", ", @$aref), "\n";
    }
}

my @array1 = (1, 2, 3);
my @array2 = (4, 5, 6);
my @array3 = (7, 8, 9);

my @a = \(@array1, @array2, @array3);

func \@a;

or more compactly:

sub func {
    my $arrayref = shift;

    for my $aref (@$arrayref) {
        print join(", ", @$aref), "\n";
    }
}

func [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
0

Read the perlreftut documentation.

Edit: Others point out a good point I missed at first. In the initialization of @a, you probably meant either @a = (...) (create array containing references) or $arrayref = [...] (create reference to array), not {...} (create reference to hash). The rest of this post pretends you had the @a = (...) version.

Since you pass one argument (a reference to @a) to func, @_ is a list containing that one reference. You can get that reference and then dereference it by doing:

sub func {
  my $arrayref = shift;
  my @c = @{$arrayref};
}

Or in one line, it would look like:

sub func {
  my @c = @{shift()};
}

(If you hadn't used the backslash in func(\@a), @_ would be equal to @a, the array of three references.)

brian d foy
  • 129,424
  • 31
  • 207
  • 592
aschepler
  • 70,891
  • 9
  • 107
  • 161
0

The following function is designed to take either an array or an array reference and give back a sorted array of unique values. Undefined values are removed and HASH and GLOB are left as is.

#!/usr/bin/perl
use strict; use warnings;

my @one = qw / dog rat / ;
my @two = qw / dog mice / ;
my @tre = ( "And then they said it!", "No!??  ", );
open my $H, '<', $0 or die "unable to open $0 to read";
my $dog; # to show behavior with undefined value
my %hash; $hash{pig}{mouse}=55; # to show that it leaves HASH alone
my $rgx = '(?is)dog'; $rgx = qr/$rgx/; # included for kicks

my @whoo =  (
    'hey!',
    $dog, # undefined
    $rgx,
    1, 2, 99, 999, 55.5, 3.1415926535,
    %hash,
    $H,
    [ 1, 2, 
              [ 99, 55, \@tre, ],
    3, ],
        \@one, \@two,
        [ 'fee', 'fie,' ,
            [ 'dog', 'dog', 'mice', 'gopher', 'piranha', ],
            [ 'dog', 'dog', 'mice', 'gopher', 'piranha', ],
        ],
        [ 1, [ 1, 2222, ['no!', 'no...', 55, ], ], ],
        [ [ [ 'Rat!', [ 'Non,', 'Tu es un rat!' , ], ], ], ], 
        'Hey!!',
        0.0_1_0_1,
        -33,
);


print join ( "\n", 
    recursively_dereference_sort_unique_array( [ 55, 9.000005555, ], @whoo, \@one, \@whoo, [ $H ], ),
    "\n", );
close $H;
exit;

sub recursively_dereference_sort_unique_array
{
    # recursively dereference array of arrays; return unique values sorted. Leave HASH and GLOB (filehandles) as they are.
    # 2020v10v04vSunv12h20m15s
    my $sb_name = (caller(0))[3];
    @_ = grep defined, @_; #https://stackoverflow.com/questions/11122977/how-do-i-remove-all-undefs-from-array
    my @redy = grep { !/^ARRAY\x28\w+\x29$/ } @_; # redy==the subset that is "ready"
    my @noty = grep {  /^ARRAY\x28\w+\x29$/ } @_; # noty==the subset that is "not yet"
    my $countiter = 0;
    while (1)
    {
        $countiter++; 
        die "$sb_name: are you in an infinite loop?" if ($countiter > 99);
        my @next;
        foreach my $refarray ( @noty )
        {
            my @tmparray = @$refarray;
            push    @next, @tmparray;
        }
        @next = grep defined, @next;
        my @okay= grep { !/^ARRAY\x28\w+\x29$/ } @next;
        @noty   = grep {  /^ARRAY\x28\w+\x29$/ } @next;
        push @redy, @okay;
        my %hash = map { $_ => 1 } @redy; # trick to get unique values
        @redy    = sort keys %hash;
        return @redy unless (scalar @noty);
    }
}

Jacob Wegelin
  • 1,304
  • 11
  • 16
-1

Should be

func {
    $b = shift;
}

if you're passing in a reference. Hope that helps some.

Mark C
  • 739
  • 1
  • 7
  • 16