Help with a bad bug: why is my original array being altered??

A

Alf McLaughlin

Hello all-
Please look at the code at the code listed below. It produces the
result also listed below. My question is, I have absolutely no idea
why the values in my original array are changing when I perform
operations on the second array. I am totally stumped... I do not
understand why the @match array seems to share the same memory address
as @array. Any help is much appreciated!

Thanks, Alf

THE RESULT:

In match array:
===============
70 c
75 d
77 e
88 f
In original array:
==================
4 a
6 b
700000 c
750000 d
770000 e
880000 f
99 g
100 h
105 i
200 j
300 k

THE CODE:

#!/usr/bin/perl

MAIN: {
my $ra_array = get_array();
my $low_range = 68;
my $high_range = 90;
my @match = grep {my $i = $_; $i->[0] >= $low_range and $i->[0] <=
$high_range} @$ra_array;
print "In match array:\n";
print "===============\n";
foreach my $i (@match) {
print "$i->[0]\t$i->[1]\n";
$i->[0] *= 10000;
}
print "In original array:\n";
print "==================\n";
foreach my $i (@$ra_array) {
print "$i->[0]\t$i->[1]\n";
}
}

sub get_array {
my @array; #= (4, 6, 70, 75, 77, 88, 99, 100, 105, 200, 300);
$array[0] = [(4, 'a')];
$array[1] = [(6, 'b')];
$array[2] = [(70, 'c')];
$array[3] = [(75, 'd')];
$array[4] = [(77, 'e')];
$array[5] = [(88, 'f')];
$array[6] = [(99, 'g')];
$array[7] = [(100, 'h')];
$array[8] = [(105, 'i')];
$array[9] = [(200, 'j')];
$array[10] =[(300, 'k')];
return \@array;
}
 
T

takarov2003

Alf said:
Hello all-
Please look at the code at the code listed below. It produces the
result also listed below. My question is, I have absolutely no idea
why the values in my original array are changing when I perform
operations on the second array. I am totally stumped... I do not
understand why the @match array seems to share the same memory address
as @array. Any help is much appreciated!

Thanks, Alf

THE RESULT:

In match array:
===============
70 c
75 d
77 e
88 f
In original array:
==================
4 a
6 b
700000 c
750000 d
770000 e
880000 f
99 g
100 h
105 i
200 j
300 k

THE CODE:

#!/usr/bin/perl

MAIN: {
my $ra_array = get_array();
my $low_range = 68;
my $high_range = 90;
my @match = grep {my $i = $_; $i->[0] >= $low_range and $i->[0] <=
$high_range} @$ra_array;
print "In match array:\n";
print "===============\n";
foreach my $i (@match) {
print "$i->[0]\t$i->[1]\n";
$i->[0] *= 10000;

aren't you multiplying your array content here by 10,000?
}
print "In original array:\n";
print "==================\n";
foreach my $i (@$ra_array) {
print "$i->[0]\t$i->[1]\n";
}
}
 
U

Uri Guttman

AM> Please look at the code at the code listed below. It produces the
AM> result also listed below. My question is, I have absolutely no idea
AM> why the values in my original array are changing when I perform
AM> operations on the second array. I am totally stumped... I do not
AM> understand why the @match array seems to share the same memory address
AM> as @array. Any help is much appreciated!

AM> MAIN: {
AM> my $ra_array = get_array();
AM> my @match = grep {my $i = $_; $i->[0] >= $low_range and $i->[0] <=
AM> $high_range} @$ra_array;

that copies the array refs in the input array. they are the same anon
arrays as in the input. you did a shallow copy (filtered by grep). you
need to loop over each of those and make a deeper copy. if you know that
you will have just that data structure a map will do a proper deep copy
(untested):

my @copies = map [ @{$_} ], @match ;

now if you modify anything in @copies it won't touch the original
anon arrays in @match. you can combine that map with the grep if you
want.

AM> print "In match array:\n";
AM> print "===============\n";
AM> foreach my $i (@match) {
AM> print "$i->[0]\t$i->[1]\n";
AM> $i->[0] *= 10000;
AM> }

use some white space and better formatting.
AM> sub get_array {

if the array is fixed why regenerate it each time in this code?

AM> my @array; #= (4, 6, 70, 75, 77, 88, 99, 100, 105, 200, 300);
AM> $array[0] = [(4, 'a')];
AM> $array[1] = [(6, 'b')];
AM> $array[2] = [(70, 'c')];

ewww, i hate seeing repetitive code like that. just assign the anon
arrays in a single list:

my @array = (
[(4, 'a')],
[(6, 'b')],
) ;

uri
 
B

Brian McCauley

Alf said:
Please look at the code at the code listed below. It produces the
result also listed below. My question is, I have absolutely no idea
why the values in my original array are changing when I perform
operations on the second array. I am totally stumped... I do not
understand why the @match array seems to share the same memory address
as @array.

It does not. The elements of @match are independant of those of @array.
But the elements of @array are refereneces to things (anonymous arrays
as it happens) and the elements of @match are references to the very
same things.

So in the code below $match[0] is not the same thing as $array[2] it
just happens to have the same value. But consequently $match[0][0] is
the same thing as $array[2][0].
MAIN: {
my $ra_array = get_array();
my $low_range = 68;
my $high_range = 90;
my @match = grep {my $i = $_; $i->[0] >= $low_range and $i->[0] <=
$high_range} @$ra_array;
print "In match array:\n";
print "===============\n";
foreach my $i (@match) {
print "$i->[0]\t$i->[1]\n";
$i->[0] *= 10000;
}
print "In original array:\n";
print "==================\n";
foreach my $i (@$ra_array) {
print "$i->[0]\t$i->[1]\n";
}
}

sub get_array {
my @array; #= (4, 6, 70, 75, 77, 88, 99, 100, 105, 200, 300);
$array[0] = [(4, 'a')];
$array[1] = [(6, 'b')];
$array[2] = [(70, 'c')];
$array[3] = [(75, 'd')];
$array[4] = [(77, 'e')];
$array[5] = [(88, 'f')];
$array[6] = [(99, 'g')];
$array[7] = [(100, 'h')];
$array[8] = [(105, 'i')];
$array[9] = [(200, 'j')];
$array[10] =[(300, 'k')];
return \@array;
}
 
A

Alf McLaughlin

my @copies = map [ @{$_} ], @match ;

Thanks, that's just what I needed; your explanation makes sense.
if the array is fixed why regenerate it each time in this code?

Just for an example (the real array in my actual program comes from
something else).
ewww, i hate seeing repetitive code like that. just assign the anon
arrays in a single list:

Sure, that works too. Again, I usually automate array generation :)
 
X

xhoster

Alf McLaughlin said:
Hello all-
Please look at the code at the code listed below. It produces the
result also listed below. My question is, I have absolutely no idea
why the values in my original array are changing when I perform
operations on the second array.

Your original arrays contains references to other two-element arrays.
The values (i.e. references) in your original array are not changing. It
is the values in the small arrays being referenced by the values in the
original array that are changing.

I am totally stumped... I do not
understand why the @match array seems to share the same memory address
as @array. Any help is much appreciated!

That is how references work. Either make a deep(er) copy of the small
arrays, or simply don't change them.

@match = map [@$_], grep {...} @$ra_array;

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top