Start off with an array of (references to) arrays: 

    @array = ( [1,2,3], ['a', 'u', 'B', 'Q', 'M'], ['%'] );


Now a shallow copy looks like this: 

    @shallow = ( $array[0], $array[1], $array[2] );


This copies the references over from @array to @shallow. Now @shallow
is ( [1,2,3], ['a', 'u', 'B', 'Q', 'M'], ['%'] ) -- the same as
@array. But there's only one 2 and one 'Q', since there are two
references pointing to the same place.  

Here's what it looks like in the debugger: 

  DB<5> x \@array
 0  ARRAY(0x10e5560)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'B'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'
  DB<6> x \@shallow
 0  ARRAY(0xcaef60)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'B'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'


You can see that @array lives somewhere around 0x10e5560, whereas
@shallow lives around 0xcaef60, but the three references point to
arrays in the same place. If I now change $array[1][2] to 'C', watch
what happens:  

  DB<7> $array[1][2] = 'C'


  DB<8> x \@array
 0  ARRAY(0x10e5560)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'
  DB<9> x \@shallow
 0  ARRAY(0xcaef60)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'

$shallow[1][2] is now also 'C'! This is because it just followed the
pointer to the array at 0x10e5638 and found the modified data there.  

Now see what happens when I do a copy that's one level deeper -- not
just copying the references but the data behind the references:  

 @deep = ( [ @{$array[0]} ], [ @{$array[1]} ], [ @{$array[2]} ] );

This uses the knowledge that @array[0..2] are all references to
arrays, and it only goes one level deeper. A more general algorithm
(such as Storable's dclone, mentioned in `perldoc -q copy`) would do a
walk and copy differently depending on the type of reference it
encounters at each stage.  

Now watch: 

  DB<12> x \@array
 0  ARRAY(0x10e5560)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'
  DB<13> x \@deep
 0  ARRAY(0x10ef89c)
   0  ARRAY(0x10eb298)
      0  1
      1  2
      2  3
   1  ARRAY(0x10eb2c4)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10ef07c)
      0  '%'


The references point to different places. 

Now if you change @array, @deep doesn't change: 

  DB<14> push @{$array[2]}, '$'


  DB<15> x \@array
 0  ARRAY(0x10e5560)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'
      1  '$'
  DB<16> x \@shallow
 0  ARRAY(0xcaef60)
   0  ARRAY(0x10e5464)
      0  1
      1  2
      2  3
   1  ARRAY(0x10e5638)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10e568c)
      0  '%'
      1  '$'
  DB<17> x \@deep
 0  ARRAY(0x10ef89c)
   0  ARRAY(0x10eb298)
      0  1
      1  2
      2  3
   1  ARRAY(0x10eb2c4)
      0  'a'
      1  'u'
      2  'C'
      3  'Q'
      4  'M'
   2  ARRAY(0x10ef07c)
      0  '%'


@deep didn't change, since it's got its own value of the anonymous
array containing '%', but @shallow did.  

Hope this helps a bit. 

Cheers, Philip -- Philip Newton <nospam.newton@gmx.li> 
If you're not part of the solution, you're part of the precipitate