2014-02-23 4 views
3

Perl을 배우려고합니다. 나는 도시로 채워진 배열을 가지고있다. 서브 루틴을 참조하여 배열을 전달하고 출력 할 각 도시를 인쇄하고 싶습니다. 그러나 다음과 같은 문제가 있습니다 :Perl에서 2 차원 배열 액세스

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. @ {$ _ [1]} [0]에서 무슨 일이 벌어지고 있는지 이해할 수 없습니다. 그것을 해결하려고 노력합니다.

  1. 을 $ _ [1], 스칼라 값이 위치 (메모리 어레이의 주소) @
  2. {...} int로서이 메모리 어드레스에 저장되는 해석의 값을 치료 @ 어레이
  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에서 2 차원 배열은 실제로 배열 참조의 배열입니다. 다음은 그 예입니다 :

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! 
} 

이제 전체 2 차원 배열을 인쇄 해 봅시다. 당신이 당신의 printElements 서브 루틴을 위해 사용하기를 원한다면

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 

당신은 아주 쉽게이 예제를 적용 할 수있다.


배열의 요소 인쇄에 대한 또 다른 참고 사항. 의 마지막 예에서이 줄을 보자 :

print @{$ref}; 

우리가 그것을 루프를 때마다 호출되기 때문에, 우리는 그것의 끝에 새 줄을 인쇄 할 수 있습니다.

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

인쇄 내용 시도 해봐! 작동합니까?

여기에 내장 된 서브 루틴 join이 유용합니다.

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

일반적으로 루프를 사용하면 배열을 반복하는 가장 좋은 방법입니다.https://stackoverflow.com/a/21950936/2534803 당신은이 질문을 확인 할 수 있습니다 : Best way to iterate through a Perl array

+1

응답 시간을내어 주셔서 감사합니다 Matt – donsiuch

0

나는 누구나 할 수 있다면 내 # 2에 대한 도움을 찾고있는 나의 # 1 문제를 해결하는 방법을 알아 냈습니다.

나는

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

my $arraySize = scalar $_[1]; 

을 변경 그리고 내 두 번째 인쇄 문은 내가 원하는 방식으로 인쇄됩니다.

스칼라 $ _ [1]이 (가) 배열의 메모리 주소를 차지하고 있으며이 배열을 수정하여 $ $ 카운터가 배열의 요소 수를 초과 할 수 있도록했습니다.

+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

이해하기 참조가 좀 더 쉽게 만들려면을, 내가 대신로 찾으면-IT-의 -> 구문을 선호하는 내 대답은 여기에 while 루프와 함께 그 일에 대해 조금 이야기 모두 함께 사용하는 구문.

대신 :

@{$_[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을 어디에서 사용할 수 있는지 알 수 없습니다. 내가 뭐 놓친 거 없니?

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 배열을 가리키는 참조 인 것을보고 쉽게 만드는 방법 : 그런데

, 나는 너무 while 루프에서 배열을 참조하지 않고이 작업을 할 수 있었다 ? ${$cities}[$city_number]보다 훨씬 깨끗하고 이해하기 쉽습니다.

+0

그의 예에서는 op보다 printElements()에 다른 수의 args를 사용했지만 "->"를 사용하는 데는 +1이 좋습니다. – jimtut

+1

응답 시간을내어 주셔서 감사합니다. – donsiuch

+0

@jimtut 예, 매개 변수를 철자하면이 문제를 쉽게 볼 수 있습니다 ...(여분의 매개 변수를 제거하는 대답을 업데이트하십시오). –