As someone had mentioned the module "Data Dumper" is really helpful. Even i am still learning and its really fun playing around with these references and derefences until you figure out what is happening. :)
Hope it helped

Not that it'll make a difference here, but you should always enable warnings in your code - either via '-w' in the shebang, or 'use warnings' right below it. It'll save you lots of grief.

As to your code - whenever you see that 'ARRAY(0xDEADBEEF)' output that you didn't expect, it's a sure sign that you forgot to dereference the variable you're trying to print. If that variable is something simple, like '$x', and you know that it's supposed to be an array, just stick an '@' sigil in front of it - @$x - and Perl will do the right thing. When it's more complex than that - say, $x is a pointer to an anonymous list and you want the first element - then use the IDO ("little arrow") syntax, '$x->[0]'. Last of all, when it's some ungodly mess that you don't even feel like figuring out - e.g., '($bar->(qw/fiddle glop/))[1][9]', and you want to get at the underlying array, just wrap the whole thing in curly braces and treat it like an array name. I.e.,

Not that it'll make a difference here, but you should always enable warnings in your code ...

Actually, it could have made a big difference, at least in the OPed code, had jlnh been aware of the significance of warnings.

In that code, the statement my @ref01 = shift;
creates and initializes an array that has (and can have) only one element upon initialization. The statement print "$i: ${$ref01[0]}{$i} ${$ref01[1]}{$i} ${$ref01[2]}{$i}\n";
then tries to access non-existent elements at indices 1 and 2 ($ref01[1] and $ref01[2]) of that array, yielding undefined values to print. This would have produced a slew of warnings, had they been enabled, that might have directed jlnh to the essential problem (of many).