2014-02-23 112 views
3

試圖學習Perl。我有一個數組填充城市。我想通過引用子例程來傳遞數組,並打印每個城市輸出。不過,我有以下問題:Perl中的二維數組訪問

1)我可以訪問子例程中我的while循環之前的每個元素。但是我無法訪問我的while循環中的元素。我收到錯誤信息:

... 
Use of uninitialized value in print at <filename> line 44, <GEN2> line 997 (#1) 
Use of uninitialized value in print at <filename> line 44, <GEN2> line 998 (#1) 
... 

以下是代碼。我有評論打印什麼,什麼不(我試圖削減的是不需要對我的解釋代碼...):

@cities; 

#Assume cities is loaded successfully 
&loadCities(getFileHandle('cities.txt'), $NUM_CITIES, \@cities); 
&printElements(getFileHandle('names.txt'), \@cities); 

sub printElements{ 

    my $counter = 0; 
    my $arraySize = scalar $_[1]; 

    # Prints fine!!! 
    print @{$_[1][($counter)%$arraySize]; 

    while ((my $line = $_[0]->getline()) && $counter < 1000){ 

     #Doesn't print. Generates the above error 
     print @{$_[1][($counter)%$arraySize]; 

     $counter += 1; 
    } 
} 

2)Perl的語法有我的超級困惑。我不明白@ {$ _ [1]} [0]是怎麼回事。試圖解決它。

  1. $ _ [1],治療在此位置作爲標量值(存儲器陣列的地址 )
  2. @ {...},解釋什麼被存儲在該存儲器 地址作爲值陣列
  3. @ {...} [X],在索引訪問元素x

我在正確的軌道上?

回答

3

我的第一個技巧是,你應該把use strict;use warnings;在你的腳本的頂部。這通常揭示了很多事情。

此行:print @{$_[1][($counter)%$arraySize];沒有關閉}。您也不需要圍繞$counter的括號。

就像你提到的那樣,獲得數組長度的最好/最清晰的方法是my $arraySize = scalar @{$_[1]};


您可以查看文檔here以瞭解使用參考文獻的情況。我會給你一個快速的概述。

你可以聲明數組作爲正常

my @array = (1, 2, 3); 

然後你可以使用反斜槓引用它。

my $array_ref = \@array; 

如果要使用參考,請使用@{...}。這就像使用常規數組一樣。

print @{$array_ref}; 

你也可以聲明它作爲開始使用方括號的參考。

my $array_ref = [1, 2, 3]; 
print @{$array_ref}; # prints 123 

在Perl中,二維數組實際上是一個數組引用的數組。下面是一個例子:

my @array = (['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']); 
print @{$array[1]}; # prints def 

現在讓我們嘗試將一個數組引用傳遞給子例程。

my @array = (['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']); 

example(\@array); # pass in an array reference 

sub example { 
    my @arr = @{$_[0]}; # use the array reference to assign a new array 
    print @{$arr[1]}; 

    print @{$_[0][1]}; # using the array reference works too! 
} 

現在讓我們把它放在一起打印整個二維陣列。

my @array = (['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']); 
example(\@array); 
sub example { 
    my @arr = @{$_[0]}; 
    for my $ref (@arr) { 
     print @{$ref}; 
    } 
} # prints abcdefghi 

如果您想將它用於printElements子例程,您可以很容易地修改這個例子。


有關在陣列中打印元素的另一個注意事項。讓我們走這條線從過去的例子:

print @{$ref}; 

由於我們通過循環每次調用它,我們可能要在它的結束打印新的生產線。

print @{$ref} . "\n"; 

這是什麼打印?嘗試一下!它工作嗎?

這是內置子程序join派上用場。

print join(" ", @{$ref}) . "\n"; 

For循環通常是遍歷數組的最佳方法。在這裏,我的回答談到一些關於while循環做:https://stackoverflow.com/a/21950936/2534803 您也可以看看這個問題:Best way to iterate through a Perl array

+1

感謝您抽出寶貴時間回覆Matt – donsiuch

0

我想如何解決我的#1問題(如果有人可以在我的#2上仍然尋求幫助)。

我改變

my $arraySize = scalar $_[1]; 

my $arraySize = @{$_[1]}; 

我的第二個打印語句打印我想要的方式。

似乎標量$ _ [1]正在獲取數組的內存地址,我對此進行了修改,這使得我的$ counter可以超出數組元素的數量。

+0

是的,你對#2的解釋是正確的。 – jimtut

+0

嘿@donsiuch我正在解答一些問題,以解釋一些事情。還想指出'my $ arraySize = @ {$ _ [1]};'基本上與'my $ arraySize = scalar @ {$ _ [1]};'相同。這裏的錯誤是使用數組引用'$ _ [1]'作爲數組。 – chilemagic

+0

http://perlmonks.org/?node=References+quick+reference – ysth

0

參考資料也混淆了我!我總是喜歡儘快解除它們的引用。這個工作對我來說:

sub printElements{ 

    my $counter = 0; 
    my $fh = $_[0]; 
    my @array = @{$_[1]}; 
    my $arraySize = scalar @array; 

    # Prints fine!!! 
    print @array[($counter)%$arraySize]; 

    while ((my $line = $fh->getline()) && $counter < 1000){ 

     #Doesn't print. Generates the above error 
     print @array[($counter)%$arraySize]; 

     $counter += 1; 
    } 
} 

我相信別人能在他們爲什麼認爲與基準工作是一種更好的方式(請這麼做),註釋說明,但口頭禪下「保持簡單」,我不喜歡和他們一起工作。可能是因爲我從來沒有C程序員...

+1

感謝您花時間回覆我的問題jimtut! – donsiuch

1

這段代碼實際上不會編譯。

print @{$_[1][($counter)%$arraySize]; 

可能想爲:

print $_[1]->[($counter)%$arraySize]; 

你解決ARRAYSIZE後。

如果結果是一個莫名其妙的指針數組,然後

print "@{$_[1]->[($counter)%$arraySize]}"; 
3

要引用一點比較容易理解,我更喜歡->語法而不是Munge時間,IT-全能的語法。

相反的:

@{$_[1]}[0]. 

嘗試

$_[1]->[0]; 

這意味着同樣的事情。它更容易,而且看起來更清晰。您可以看到$_[1]是一個數組引用,並且您引用該數組引用中的第一個元素。

但是,更好的方法是在@_中爲各種元素設置變量。你必須輸入更多的字母,但是你的代碼更容易理解,而且更容易調試。現在

sub print_elements { 
    my $file_handle  = shift; # This isn't a "reference", but an actual file handle 
    my $cities_array_ref = shift; # This is a reference to your array 

    my @cities = @{ $cities_array_ref }; # Dereferencing makes it easier to do your program 

,你的子程序處理的是有名字的變量以及數組引用是一個數組,這使得事情更清潔。此外,您不能意外影響主程序中的值。當您使用@_時,它將直接鏈接到您傳遞給它的值。修改@_會修改主程序中的值,這可能不是您想要執行的操作。

所以,要通過你的子程序:

sub printElements { 
    my file_handle  = shift; 
    my $cities_array_ref = shift; 

    my @cities = @{ $cities_array_ref }; 
    my $counter; 
    my $array_size = @cities;  # No need for scalar. This is automatic 
    while (my $line = $file_handle->getline and $counter < 1000) { 
     chomp $line; 
     my $city_number = $counter % $array_size; 
     print $cities[$city_number]. "\n"; 
     $counter += 1; 
    } 
} 

注意,這是多麼容易,看看發生了什麼事情就只需通過分配幾個變量,而不是試圖塞進一切融合在一起。我可以很容易地看到你的子程序的參數是什麼。如果用不正確的參數順序調用子程序,則可以很容易地發現它。另請注意,我爆發了$counter % $array_size並將其分配給了一個變量。突然之間,我很明顯想擺脫它。

但是,我無法看到您使用getline時所用的$line。我錯過了什麼?

順便說一句,我可以這樣做,而不引用數組中的while環太:

sub printElements { 
    my file_handle  = shift; 
    my $cities   = shift; # This is an array reference! 

    my $counter; 
    my $array_size = @{ $cities }; # I need to deref to get an array 
    while (my $line = $file_handle->getline and $counter < 1000) { 
     chomp $line; 
     my $city_number = $counter % $array_size; 
     print $cities->[$city_number]. "\n"; # That's it! 
     $counter += 1; 
    } 
} 

請參閱->語法如何可以很容易地看到,$cities是指向數組的引用?比${$cities}[$city_number]更清潔並更易於理解。

+0

您使用了不同的參數#來表示printElements(),而不是op,在其示例中使用了printElements(),但對於使用「 - >」的示例,使用了+1。 – jimtut

+1

感謝您花時間回覆大衛 – donsiuch

+0

@jimtut是的,當您將參數拼寫出來時,更容易看到類似這樣的問題......(更新答案以消除多餘的參數)。 –