Question

I have this program which does not work as expected. Help me.

I want to print a row heading.

If input is 4, I want 1|2|3|4 to be output.

It does not work as all, if I hard-code $count value it works partially but the last number is missing.

sub printC {
        my $count = @_;
        # count = 4  # works partially only prints 1|2|3
        for(my $i=1;$i<$count;$i++) {
                print "$i|";
        }
        print $i;
}
$count  = 2;
&printC($count);
print "\n";
Was it helpful?

Solution

The problem is here:

my $count = @_;

The assignment is happening in a scalar context which assigns the number of elements in array @_ to $count, which your case is 1, as you are passing 1 argument to the function.

To fix this you can do:

my ($count) = @_; 

or

my $count = $_[0];

here is another problem:

for(my $i=1.....
    ^^

By using my you've made $i local to the body of for and it'll not be available outside it. So your final print outside the for is not printing anything. To fix this move the declaration of $i outside the loop:

sub printC {
        my ($count) = @_;
        my $i;
        ....

Always make it a point to write

use strict;

at the top of your program which enables you to catch such bugs.

The perl way of doing what your function does is:

print join('|',1..$count);

OTHER TIPS

A real Perl hacker might write something like this:

sub printC {
  my $count = shift;
  print join "|", (1 .. $count);
}

Once you understand how this works, you'll find you've learned some more about Perl. :-)

$i does not exist once you've left the for loop because of where it's declared.

You could do

sub printC {
    my ($count) = @_;
    my $i;
    for ($i = 1; $i < $count; $i++) {
        print "$i|";
    }
    print $i;
}

Even simpler:

sub printC {
    my ($count) = @_;
    print join("|", 1 .. $count) . "\n";
}

One other bit of "being more Perlish" is to not use the C-style for loop. There is almost never a need to use a C-style for in Perl.

Instead of

for(my $i=1;$i<$count;$i++) { ... }

use

for my $i (1 .. $count) { ... }

They're almost equivalent, except the latter version is both more easily readable and more resistant to off-by-one errors. (The reason your code was only printing 1|2|3 instead of 1|2|3|4 is because the test in your C-style for was checking $i<$count when it should have been $i<=$count - this is a very common mistake with C-style for loops which for (list) avoids completely.)

Also, don't prefix your sub calls with &. It's a holdover from Perl 4 which is no longer needed in Perl 5 and has side effects which you probably aren't aware of and probably don't want. Just use printC($count) instead of &printC($count).

But, yeah, in this particular case, join is probably a better approach than for anyhow.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top