Passing a hash by reference

Discussion in 'Perl Misc' started by Niall Macpherson, Dec 12, 2003.

  1. Apologies if this has been covered before - I have seen a number of
    posts on this subject but I still cannot work out my code doesn't
    work.

    I have been working with C / C++ for over 10 years and am fully
    conversant with pointers and passing by reference in C. However ,
    passing by reference in perl is causing me some problems.

    Here is a little bit of test code -

    ##----------------------------------------------------------------------
    sub AddHashEntries
    {
    my($rh_hashref) = @_;
    for($cnt = 0; $cnt < 10; $cnt ++)
    {
    $value = "value " . $cnt;
    $key = "key" . $cnt;
    $$rh_hashref{$key} = $value;
    }
    return;
    }
    ##----------------------------------------------------------------------
    sub PrintHashEntries
    {
    my($rh_hashref) = @_;

    foreach my $key (keys $$rh_hashref)
    {
    print("\nKey = [$key], value = $$rh_hashref{$key}");
    }
    return;
    }
    ##----------------------------------------------------------------------
    my %testhash = {};
    AddHashEntries(\%testhash);
    print("\nAdded all entries OK");
    foreach my $lkey (keys %testhash) ## *** 1 ****
    {
    print("\nKey = [$lkey], value = $testhash{$lkey}");
    }
    PrintHashEntries(\%testhash);
    ##----------------------------------------------------------------------


    The values appear to get added to hash OK - the call at *** 1 ****
    produces output as I would expect , eg

    Added all entries OK
    Key = [key7], value = value 7
    Key = [HASH(0x1abefac)], value =
    Key = [key8], value = value 8
    Key = [key9], value = value 9
    Key = [key0], value = value 0
    Key = [key1], value = value 1
    Key = [key2], value = value 2
    Key = [key3], value = value 3
    Key = [key4], value = value 4
    Key = [key5], value = value 5
    Key = [key6], value = value 6

    However , I can't even get the PrintHashEntries routine to compile - I
    get

    Type of arg 1 to keys must be hash (not scalar dereference) at
    C:\MoreTestStuff\
    GMPriceConf\hashreftest.pl line 20, near "$rh_hashref)
    "
    Execution of C:\MoreTestStuff\GMPriceConf\hashreftest.pl aborted due
    to compilat
    ion errors.


    Can anyone tell me what I am doing wrong ?

    Thanks
    Niall Macpherson, Dec 12, 2003
    #1
    1. Advertising

  2. Niall Macpherson

    Tore Aursand Guest

    On Fri, 12 Dec 2003 09:02:29 -0800, Niall Macpherson wrote:
    > sub AddHashEntries
    > {
    > my($rh_hashref) = @_;
    > for($cnt = 0; $cnt < 10; $cnt ++)
    > {
    > $value = "value " . $cnt;
    > $key = "key" . $cnt;
    > $$rh_hashref{$key} = $value;
    > }
    > return;
    > }


    sub AddHashEntries {
    my $rh_hashref = shift;

    for ( 1..10 ) {
    my $value = 'value ' . $_;
    my $key = 'key' . $_;
    $rh_hashref->{$key} = $value;
    }
    }

    > sub PrintHashEntries
    > {
    > my($rh_hashref) = @_;
    >
    > foreach my $key (keys $$rh_hashref)
    > {
    > print("\nKey = [$key], value = $$rh_hashref{$key}");
    > }
    > return;
    > }


    sub PrintHashEntries {
    my $rh_hashref = shift;

    foreach ( keys %$rh_hashref ) {
    print "\nKey = [$key], value = $rh_hashref->{$_}";
    }
    }


    --
    Tore Aursand <>
    "I didn't have time to write a short letter, so I wrote a long one
    instead." -- Mark Twain
    Tore Aursand, Dec 12, 2003
    #2
    1. Advertising

  3. Niall Macpherson

    Uri Guttman Guest

    >>>>> "TA" == Tore Aursand <> writes:

    > sub AddHashEntries {
    > my $rh_hashref = shift;


    > for ( 1..10 ) {
    > my $value = 'value ' . $_;
    > my $key = 'key' . $_;
    > $rh_hashref->{$key} = $value;
    > }
    > }


    $rh_hashref->{"key$_"} = "value$_" for 1 .. 10 ;

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Dec 12, 2003
    #3
  4. Niall Macpherson

    Bob Walton Guest

    Niall Macpherson wrote:

    > Apologies if this has been covered before - I have seen a number of
    > posts on this subject but I still cannot work out my code doesn't
    > work.
    >
    > I have been working with C / C++ for over 10 years and am fully
    > conversant with pointers and passing by reference in C. However ,
    > passing by reference in perl is causing me some problems.
    >
    > Here is a little bit of test code -
    >
    > ##----------------------------------------------------------------------



    use strict;
    use warnings;

    If you had used warnings, Perl would have told you what was wrong. Let
    Perl help you.


    > sub AddHashEntries
    > {
    > my($rh_hashref) = @_;
    > for($cnt = 0; $cnt < 10; $cnt ++)
    > {
    > $value = "value " . $cnt;
    > $key = "key" . $cnt;
    > $$rh_hashref{$key} = $value;
    > }
    > return;
    > }
    > ##----------------------------------------------------------------------
    > sub PrintHashEntries
    > {
    > my($rh_hashref) = @_;
    >
    > foreach my $key (keys $$rh_hashref)


    %-----------------------------^
    That won't compile. Keys expects a hash, not a scalar.


    > {
    > print("\nKey = [$key], value = $$rh_hashref{$key}");
    > }
    > return;
    > }
    > ##----------------------------------------------------------------------
    > my %testhash = {};


    ()---------------^^
    Using {} generates a scalar value which is a reference to an anonymous
    hash. That is the "weird" value that is showing up in your printed hash
    contents. This hash reference goes in as a key; keys must be strings,
    so it is stringified, and this stringified hash reference is the
    HASH(0x1abefac) key in your output. The value is the empty string
    because %testhash = expects to find a list with an even number of
    entries; if an odd number (like one) is present, Perl emits a warning
    (if you asked for warnings as you should during development) and assigns
    undef as the value.


    > AddHashEntries(\%testhash);
    > print("\nAdded all entries OK");
    > foreach my $lkey (keys %testhash) ## *** 1 ****
    > {
    > print("\nKey = [$lkey], value = $testhash{$lkey}");
    > }
    > PrintHashEntries(\%testhash);
    > ##----------------------------------------------------------------------
    >
    >
    > The values appear to get added to hash OK - the call at *** 1 ****
    > produces output as I would expect , eg
    >
    > Added all entries OK
    > Key = [key7], value = value 7
    > Key = [HASH(0x1abefac)], value =
    > Key = [key8], value = value 8
    > Key = [key9], value = value 9
    > Key = [key0], value = value 0
    > Key = [key1], value = value 1
    > Key = [key2], value = value 2
    > Key = [key3], value = value 3
    > Key = [key4], value = value 4
    > Key = [key5], value = value 5
    > Key = [key6], value = value 6
    >
    > However , I can't even get the PrintHashEntries routine to compile - I
    > get
    >
    > Type of arg 1 to keys must be hash (not scalar dereference) at
    > C:\MoreTestStuff\
    > GMPriceConf\hashreftest.pl line 20, near "$rh_hashref)
    > "
    > Execution of C:\MoreTestStuff\GMPriceConf\hashreftest.pl aborted due
    > to compilat
    > ion errors.

    ....

    --
    Bob Walton
    Email: http://bwalton.com/cgi-bin/emailbob.pl
    Bob Walton, Dec 13, 2003
    #4
  5. -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    (Niall Macpherson) wrote in
    news::

    > foreach my $key (keys $$rh_hashref)


    In C/C++, * is used for all dereferencing. In Perl, you can
    dereference with $, @, or %, depending on what sort of thing you're
    dereferencing.

    The 'keys' operator expects to work on a real hash, not a reference
    or anything, so you need to dereference it with %. The next
    nonwhitespace character after the word keys *must* be a %.
    (Similarly, the character following 'each' must be a %; the character
    following 'push' must be @).

    What you want is: keys %$rh_hashref.

    - --
    Eric
    $_ = reverse sort $ /. r , qw p ekca lre uJ reh
    ts p , map $ _. $ " , qw e p h tona e and print
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.1 (MingW32) - WinPT 0.5.13

    iD8DBQE/2u6XY96i4h5M0egRAkBXAKCbY1Jbxhdr7FKe5nm0JlNFHy7IcACfVemR
    +bSgHZI/sdM89CV/XEAL6/E=
    =qSNr
    -----END PGP SIGNATURE-----
    Eric J. Roode, Dec 13, 2003
    #5
  6. Niall Macpherson

    Web Surfer Guest

    [This followup was posted to comp.lang.perl.misc]

    In article <>,
    says...
    > Apologies if this has been covered before - I have seen a number of
    > posts on this subject but I still cannot work out my code doesn't
    > work.
    >
    > I have been working with C / C++ for over 10 years and am fully
    > conversant with pointers and passing by reference in C. However ,
    > passing by reference in perl is causing me some problems.
    >
    > Here is a little bit of test code -
    >
    > ##----------------------------------------------------------------------
    > sub AddHashEntries
    > {
    > my($rh_hashref) = @_;
    > for($cnt = 0; $cnt < 10; $cnt ++)
    > {
    > $value = "value " . $cnt;
    > $key = "key" . $cnt;
    > $$rh_hashref{$key} = $value;
    > }
    > return;
    > }
    > ##----------------------------------------------------------------------
    > sub PrintHashEntries
    > {
    > my($rh_hashref) = @_;
    >
    > foreach my $key (keys $$rh_hashref)


    This should be

    foreach my $key ( keys %$rh_hashref )


    > {
    > print("\nKey = [$key], value = $$rh_hashref{$key}");
    > }
    > return;
    > }
    > ##----------------------------------------------------------------------
    > my %testhash = {};
    > AddHashEntries(\%testhash);
    > print("\nAdded all entries OK");
    > foreach my $lkey (keys %testhash) ## *** 1 ****
    > {
    > print("\nKey = [$lkey], value = $testhash{$lkey}");
    > }
    > PrintHashEntries(\%testhash);
    > ##----------------------------------------------------------------------
    >
    >
    > The values appear to get added to hash OK - the call at *** 1 ****
    > produces output as I would expect , eg
    >
    > Added all entries OK
    > Key = [key7], value = value 7
    Web Surfer, Dec 13, 2003
    #6
  7. Thanks for your help everyone - I will try this out !
    Niall Macpherson, Dec 14, 2003
    #7
  8. Niall Macpherson

    G Klinedinst Guest

    TORE> sub PrintHashEntries {
    TORE> my $rh_hashref = shift;
    TORE>
    TORE> foreach ( keys %$rh_hashref ) {
    TORE> print "\nKey = [$key], value = $rh_hashref->{$_}";
    TORE> }
    TORE> }

    TORE> sub AddHashEntries {
    TORE> my $rh_hashref = shift;
    TORE>
    TORE> for ( 1..10 ) {
    TORE> my $value = 'value ' . $_;
    TORE> my $key = 'key' . $_;
    TORE> $rh_hashref->{$key} = $value;
    TORE> }
    TORE> }

    URI> $rh_hashref->{"key$_"} = "value$_" for 1 .. 10 ;

    Thank you Uri and Tore for "Perlizing" his code. I also write Perl
    code which looks suspiciously like C, so seeing how everyone else does
    it is a great help to me. I particularly like the "1..10" and shifting
    the first value out of @_ at the beginning of each function...I mean
    subroutine.

    -Greg
    G Klinedinst, Dec 17, 2003
    #8
  9. Niall Macpherson

    Toby Guest

    On G Klinedinst wrote:
    > TORE> sub PrintHashEntries {
    > TORE> my $rh_hashref = shift;
    > TORE>
    > TORE> foreach ( keys %$rh_hashref ) {
    > TORE> print "\nKey = [$key], value = $rh_hashref->{$_}";


    surely:
    print "\nKey = [$_], value = $rh_hashref->{$_}";

    > TORE> }
    > TORE> }


    --
    print 'Just learning to be another Perl Hacker'
    Toby, Dec 17, 2003
    #9
  10. Niall Macpherson

    Uri Guttman Guest

    >>>>> "GK" == G Klinedinst <> writes:

    TORE> sub PrintHashEntries {
    TORE> my $rh_hashref = shift;

    TORE> sub AddHashEntries {
    TORE> my $rh_hashref = shift;

    URI> $rh_hashref->{"key$_"} = "value$_" for 1 .. 10 ;

    > Thank you Uri and Tore for "Perlizing" his code. I also write Perl
    > code which looks suspiciously like C, so seeing how everyone else does
    > it is a great help to me. I particularly like the "1..10" and shifting
    > the first value out of @_ at the beginning of each function...I mean
    > subroutine.


    well, since you are in a learning mode, i prefer to assign with @_
    instead of shift (except where shifting @_ does something important).

    my ( $arg, $foo ) = @_ ;

    that style will usually mean fewer lines of code and it is easier to add
    more args or slurp the rest with an array or hash:

    my ( $file, %opts ) = @_ ;

    but as i said shift has its place there but IMO only when you need to
    have a shorter @_ for use later on.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Dec 17, 2003
    #10
  11. Niall Macpherson

    Anno Siegel Guest

    Uri Guttman <> wrote in comp.lang.perl.misc:
    > >>>>> "GK" == G Klinedinst <> writes:

    >
    > TORE> sub PrintHashEntries {
    > TORE> my $rh_hashref = shift;
    >
    > TORE> sub AddHashEntries {
    > TORE> my $rh_hashref = shift;
    >
    > URI> $rh_hashref->{"key$_"} = "value$_" for 1 .. 10 ;
    >
    > > Thank you Uri and Tore for "Perlizing" his code. I also write Perl
    > > code which looks suspiciously like C, so seeing how everyone else does
    > > it is a great help to me. I particularly like the "1..10" and shifting
    > > the first value out of @_ at the beginning of each function...I mean
    > > subroutine.

    >
    > well, since you are in a learning mode, i prefer to assign with @_
    > instead of shift (except where shifting @_ does something important).
    >
    > my ( $arg, $foo ) = @_ ;
    >
    > that style will usually mean fewer lines of code and it is easier to add
    > more args or slurp the rest with an array or hash:
    >
    > my ( $file, %opts ) = @_ ;
    >
    > but as i said shift has its place there but IMO only when you need to
    > have a shorter @_ for use later on.


    One such place is, in my praxis, the first parameter of a method. It
    is a good rule to always shift it off the parameter list (and probably
    call it $class for a class method, and $self, or an abbreviation of the
    class name, for an object method). That way, the parameters left after
    the shift correspond to the (method-) call parameters the way they do
    with normal sub calls. It also gives methods a distinctive style that
    may help tell them from other subs.

    Anno
    Anno Siegel, Dec 18, 2003
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. rp
    Replies:
    1
    Views:
    499
    red floyd
    Nov 10, 2011
  2. Srijayanth Sridhar
    Replies:
    19
    Views:
    598
    David A. Black
    Jul 2, 2008
  3. Steve

    hash reference as a hash key

    Steve, Sep 26, 2003, in forum: Perl Misc
    Replies:
    6
    Views:
    110
    Steve
    Sep 28, 2003
  4. Replies:
    14
    Views:
    231
    Tomi Häsä
    Jan 10, 2005
  5. Arvin Portlock
    Replies:
    6
    Views:
    135
    Arvin Portlock
    Sep 2, 2005
Loading...

Share This Page