Reputation: 569
I am new to perl and couldn't find any info on my problem, so apologies in advance if this is a duplicate or I am completely out to lunch.
Actual question a little lower.
#!/usr/bin/perl
use strict;
my @root = undef;
myfunc(\@root);
sub myfunc()
{
my ($ptr_parent) = @_;
print "root => ";
print \@root;
print "\n";
print "ptr_parent => $ptr_parent\n";
my @stuff = split(',', 'test1,test2,test3');
$ptr_parent = \@stuff;
print "stuff => ";
print \@stuff;
print "\n";
print "root => ";
print \@root;
print "\n";
print "ptr_parent => $ptr_parent\n";
}
Not surprisingly my output is as follows:
root => ARRAY(0x7f903182e890)
ptr_parent => ARRAY(0x7f903182e890)
stuff => ARRAY(0x7f9031838548)
root => ARRAY(0x7f903182e890)
ptr_parent => ARRAY(0x7f9031838548)
What I am trying to achieve is the following:
root => ARRAY(0x7f903182e890)
ptr_parent => ARRAY(0x7f903182e890)
stuff => ARRAY(0x7f9031838548)
root => ARRAY(0x7f9031838548) <---- Note this changes.
ptr_parent => ARRAY(0x7f9031838548)
So I have a suspicion that this is impossible to do like this because of scoping as I would imagine that the @stuff memory pointer gets released.
I feel like I could make @root a $root where it is a pointer to a pointer. But I am stuck on how to write this. The syntax for pointers is still not 100% in my head.
But the general requirement is that whatever list is generated in myfunc would need to survive in @root. And I cannot modify @root directly from myfunc();
Thanks in advance. Let me know if I need to clarify.
Upvotes: 2
Views: 102
Reputation: 6553
In your code, $ptr_parent
is a variable that holds a reference, and you are modifying the variable, not the referent. You need to use some dereference syntax if you want to modify the actual thing the reference points to. See perlreftut for an introduction and perlref for all the gory details.
use strict;
use warnings;
use Data::Dump;
my @arr;
dd(\@arr);
foo(\@arr);
dd(\@arr);
bar(\@arr);
dd(\@arr);
sub foo {
my $aref = shift;
@$aref = split(/,/, 'test1,test2,test3'); # notice the dereference
}
sub bar {
my $aref = shift;
$aref->[0] = 42; # individual element dereference
$aref->[1] = 'ponies';
}
Output:
[]
["test1", "test2", "test3"]
[42, "ponies", "test3"]
Upvotes: 3
Reputation: 385655
Perl passes by reference, which means that changing the argument in the sub will change it in the caller too. But you're not modifying the argument ($_[0]
); you're modifying a lexical variable ($ptr_parent
).
All of the following will work with myfunc($root)
:
# Create the object as needed, and pass it back explicitly on exit.
sub myfunc {
my $parent = $_[0] // [];
push @$parent, split(/,/, 'test1,test2,test3');
$_[0] = $parent;
}
# Create the object, and pass it back explicitly up front.
sub myfunc {
my $parent = shift //= [];
push @$parent, split(/,/, 'test1,test2,test3');
}
# Create the object as needed by using a layer of indirection.
sub myfunc {
my $parent_ref = \shift;
push @{ $$parent_ref }, split(/,/, 'test1,test2,test3');
}
Or you could be less "magical" and pass a reference to myfunc
(myfunc(\$root)
):
sub myfunc {
my $parent_ref = shift;
push @{ $$parent_ref }, split(/,/, 'test1,test2,test3');
}
By the way, the prototype was incorrect. I fixed this issue by removing it.
Upvotes: 3
Reputation: 17710
Indeed, you need to use a reference, and pass a reference to that reference if you want to modify it from a different place.
#!/usr/bin/perl
use strict;
my $root = [];
myfunc(\$root);
sub myfunc()
{
my ($ptr_parent) = @_;
print "root => ";
print $root;
print "\n";
print "ptr_parent => $$ptr_parent\n";
my @stuff = split(',', 'test1,test2,test3');
$$ptr_parent = \@stuff;
print "stuff => ";
print \@stuff;
print "\n";
print "root => ";
print $root;
print "\n";
print "ptr_parent => $$ptr_parent\n";
}
Output:
root => ARRAY(0x7f8143001ee8)
ptr_parent => ARRAY(0x7f8143001ee8)
stuff => ARRAY(0x7f8143022ad8)
root => ARRAY(0x7f8143022ad8)
ptr_parent => ARRAY(0x7f8143022ad8)
Upvotes: 0