BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to access a list of arrays from IC, but I'm walking off the end of the data. Not too surprising as I'm getting the third element instead of the first, but I'm damned if I can see why that is? Cluebats anyone?

#! perl -sw use 5.010; use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'LoA', CLEAN_AFTER_BUILD => 0; #include <stdarg.h> SV *test( SV *dummy, ... ) { Inline_Stack_Vars; int i; int n = Inline_Stack_Items; printf( "Got %d items\n", n ); for( i = 0; i < n; ++i ) { int j; SV *sv = Inline_Stack_Item( i ); AV *av = (AV *)SvRV( sv ); if( !SvROK( sv ) || SvTYPE( SvRV( sv ) ) != SVt_PVAV ) croak( "Requires a list of array refs (%d => type %d)\n", i, SvTYPE( SvRV( sv ) ) ); printf( "Item %d has %d elements\n", i, av_len( av ) ); for( j = 0; j <= av_len( av ); ++j ) { SV *sv2 = (SV*)av_fetch( av, j, 0 ); printf( "[%d][%d] %x %d '%s'\n", i, j, sv2, SvTYPE( sv2 ), SvPVX( SvRV( sv2 ) ) ); } } printf( "here\n" ); Inline_Stack_Reset; return &PL_sv_yes; } END_C use Data::Dump qw[ pp ]; my @a = map [ 'A' .. 'J' ], 1 .. 5; pp \@a; test( @a ); __END__ __OUPUT__ [ 0:58:24.60] C:\test>IC-LoA.pl [ ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ] Got 5 items Item 0 has 9 elements [0][0] 3b27918 0 'C' [0][1] 3b27920 0 'D' [0][2] 3b27928 0 'E' [0][3] 3b27930 0 'F' [0][4] 3b27938 0 'G' [0][5] 3b27940 0 'H' [0][6] 3b27948 0 'I' [0][7] 3b27950 0 'J' segfault:Memory violation.

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re: LoA from XS
by syphilis (Archbishop) on Apr 21, 2009 at 00:55 UTC
    The 'for' loop is not quite correct.
    This rendition of it works for me:
    for( j = 0; j <= av_len( av ); ++j ) { SV **sv2 = av_fetch( av, j, 0 ); char * str = SvPVX(*sv2); if(sv2 != NULL) printf( "[%d][%d] %x %d '%s'\n", i, j, *sv2, SvTYPE( *sv2 ), str ); }
    Cheers,
    Rob

        Now I just need to undestand the changes.

        Two problems were fixed.

        • av_fetch returns a pointer to a SV* (which may be NULL). It needs to be dereferenced into a SV*, not casted to SV*.

        • Each element of the array is a string, not a reference to the string. The SvRV was extraneous.

Re: LoA from XS
by almut (Canon) on Apr 21, 2009 at 00:30 UTC

    Shouldn't that be for( j = 0; j < av_len( av ); ++j ) { ?

      No.

      Returns the highest index in the array. The number of elements in the array is av_len(av) + 1 . Returns -1 if the array is empty

      No. According to the docs:

      av_len Returns the highest index in the array.

      It's basically the equivalent of Perl's $#{ aref }, hence the unusual condition. I think if I could pursuade it to start at the right place, it would stop correctly too. I just cannot see why it doesn't?


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Then, you shouldn't printf( "Item %d has %d elements\n", i, av_len( av ) );, if it has in fact av_len(av)+1 (i.e. 10). :)

        Anyhow, I think the problem is with reading the string out of sv2 — at least I don't get any sensible values here at all, like 'A'..'J' (only random junk out of memory instead).  I'll take a closer look ... well, no longer required, syphilis has already done so (—> av_fetch is returning an SV**, not SV*)