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

Greetings to all, I am trying to pass the array @data_one from the sub print_search_results{) to another subroutine I found as a program named &words() that I ran acrossed in the O'REILLY perl cookbook. I really liked the formatting of the text. I can get the words() program to work ok passing a hard coded filename.
I am still new to perl . What am I doing wrong.
Thanks for any help Tim
#!/usr/local/bin/perl -w use strict; use warnings; use CGI::Carp qw(fatalsToBrowser); use Time::Local; use CGI qw(:standard); require "/u/web/cmpsf/cgi-local/schedules/cleaners/FileDB.pm"; my $fileDB = FileDB->new( FILE => $fileName ,DELIMITER => "::"); print_search_results($fileDB); sub print_search_results{ my ($db)= @_; my @records = $db->get_all(); foreach(sort{$a->[0]cmp$b->[0]}map{["$_->[3]#$_->[2]",$_]}@records) { my $rec = $_->[1]; push @{$values{$rec->[3]}}, $rec->[2]; if ($rec->[3]== 1) { my $full_name = $rec->[1].' '.$rec->[2]."," ; push(@data_one,$full_name); }; } } sub words{ my @data_one; my @data_two; my ($item, $cols, $rows, $maxlen); my ($xpixel, $ypixel, $mask, @data); my($database) = ($_[0]); getwinsize(); # first gather up every line of input, # remembering the longest line length seen $maxlen = 1; open(DATABASE, "$database"); while (<DATABASE>) { my $mylen; s/\s+$//; $maxlen = $mylen if (($mylen = length) > $maxlen); push(@data, $_); } $maxlen += 1; # to make extra space # determine boundaries of screen $cols = int($cols / $maxlen) || 1; $rows = int(($#data+$cols) / $cols); # pre-create mask for faster computation $mask = sprintf("%%-%ds ", $maxlen-1); # subroutine to check whether at last item on line sub EOL { ($item+1) % $cols == 0 } # now process each item, picking out proper piece for this position for ($item = 0; $item < $rows * $cols; $item++) { my $target = ($item % $cols) * $rows + int($item/$cols); my $piece = sprintf($mask, $target < @data ? $data[$target] : ""); $piece =~ s/\s+$// if EOL(); # don't blank-pad to EOL print $piece; print "\n" if EOL(); } # finish up if needed print "\n" if EOL(); # not portable -- linux only sub getwinsize { my $winsize = "\0" x 8; my $TIOCGWINSZ = 0x40087468; if (ioctl(STDOUT, $TIOCGWINSZ, $winsize)) { ($rows, $cols, $xpixel, $ypixel) = unpack('S4', $winsize); } else { $cols = 80; } } }

Replies are listed 'Best First'.
Re: passing an array to a subroutine
by sauoq (Abbot) on Jul 10, 2003 at 23:25 UTC

    I think you are asking a general question about passing arrays into subroutines and have confused people with the lengthy example you have provided...

    It looks like @data_one is a private variable in the words() subroutine. You also attempt to use it in the print_search_results() subroutine. Maybe you are trying to use it as a global array and are shadowing it in your words() sub?

    You might try removing the my @data_one; declaration in the words() sub. Better would be to actually pass it in. There are two ways to do that. You can pass it in directly or by reference. By reference is better.

    Perl subs get their arguments in the @_ array. Here's how to pass an array by reference:

    sub mysub { my @array = @$_[0]; # Makes a copy. Not efficient. print $array[0], "\n"; } my @a = (1 .. 10); mysub(\@a); # \@a is a reference to the array @a.
    In the interest of keeping the example simple, that makes a copy of the data which isn't particularly efficient. You can avoid references entirely but doing so isn't very efficient either and it doesn't work very well if you have to pass in more than one array.
    mysub { my @array = @_; # Copying again. Not efficient. print $array[0], "\n"; } my @a = (1 .. 10); mysub(@a); # Send the array as @_
    My suggestion is to learn how to use references right away. You can start with some of the Tutorials right here like references and References quick reference. Ideally, your code would look more like this:
    mysub { my ($arrayref) = @_; print $arrayref->[0], "\n"; } my @a = (1 .. 10); mysub( \@a );

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: passing an array to a subroutine
by Zaxo (Archbishop) on Jul 10, 2003 at 22:18 UTC

    What errors and warnings do you get?

    Lines 7-9 look fishy to me. The require of FileDB.pm happens at runtime, too late for the definition of FileDB->new() in line 9. Try replacing line 7 with,

    use lib '/u/web/cmpsf/cgi-local/schedules/cleaners'; use FileDB;

    There are several ways to pass an array to a subroutine. You can either pass a reference to it as one arg, or else just add the array to the argument list. The former is best if the sub modifies the array, the latter if you just want to see the values. At least that's the convention I use.

    After Compline,
    Zaxo

Re: passing an array to a subroutine
by CountZero (Bishop) on Jul 10, 2003 at 22:24 UTC

    Sorry, it must be because it is getting late, but I don't really understand your query.

    Could you perhaps post a shorter code example with only the problem you have?

    One guess (before I go to sleep): Is your problem how to return values out of a subroutine? If that's the case, check the return-function. If the subroutine is called in a list context, it can return a list.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      How do I pass array @data_one from the sub print_search_results{) to the words() subroutine ? Thanks
Re: passing an array to a subroutine
by pzbagel (Chaplain) on Jul 10, 2003 at 22:31 UTC

    You provided us with the words subroutine, but you failed to give us the code where you actually call the words subroutine. Is this the whole script? Or is there something missing?

      I am not sure how to make the call.