2009-02-19 9 views
2

L'autre jour, nécessaire pour itérer sur un sous-ensemble d'un tableau à la fois. Au départ, je l'ai fait avec épissure - déchirer le tableau n'a pas posé de problème dans ce cas. Il renverrait N éléments à la fois, ou ce qui restait à la fin de la liste. Tout allait bien.Pourquoi grep sur ma tranche de tableau provoque un débordement de pile en Perl?

Puis il s'est avéré que j'avais besoin du tableau plus tard. Au lieu de splice, je suis passé à des tranches de tableau. BOOM! Le programme a explosé, envoyant un débordement de pile partout. Quelle? Pourquoi? Comment? J'ai joué avec et j'ai trouvé quelques variantes qui fonctionneraient. Voici le script de test pour démontrer ce problème:

use strict; 
use warnings; 

my @array = qw(a b c d e f g h i j k l m n o p q r s t u v z x c v b a s d f g a s d f a se g); 
my $numPerTest = 5; 

my $index = 0; 
print "Separating out the subset before grepping it, good.\n"; 
while ($index < @array) 
{ 
    print "Iteration $index\n"; 
    my @subset = @array[$index..($index+$numPerTest)]; 
    @subset = grep { defined $_ } @subset; 
    $index += $numPerTest; 
} 

$index = 0; 
print "Making a copy of the array before grepping works.\n"; 
while ($index < @array) 
{ 
    print "Iteration $index\n"; 
    my @subset = grep { defined $_ } @{[ @array[$index..($index+$numPerTest)] ]}; 
    $index += $numPerTest; 
} 

$index = 0; 
print "Grepping the array slice directly, explodey!\n"; 
while ($index < @array) 
{ 
    print "Iteration $index\n"; 
    my @subset = grep { defined $_ } @array[$index..($index+$numPerTest)]; 
    $index += $numPerTest; 
} 

(En fait, je viens de comprendre celui-ci, mais je me suis dit que je pourrais aussi bien l'afficher quand même voir si quelqu'un d'autre le voit :)..)

(De plus, si vous ne le voyez pas, this a une autre façon d'expliquer pourquoi cela se produit.)

+0

Ne nous tenez pas en haleine. Je ne le vois pas. –

+0

Est-ce parce que vous allez au-delà des limites du tableau lorsque $ index + $ numPerTest est> @array? –

+0

Cela aiderait si vous aviez bouclé $ index <@array - $ numPerTest. En outre, ce que vous voulez faire est de prendre une tranche de $ index. ($ Index + $ numPerTest -1). En ce moment, vous prenez un élément de plus que $ numPerTest –

Répondre

9

En utilisant la tranche comme lvalue, vous agrandissez la matrice chaque fois qu'elle est trop courte. Par conséquent, il ne sera jamais hors d'éléments.

Dans les deux premiers exemples, vous l'avez uniquement utilisé comme valeur de référence, donc aucun élément supplémentaire n'est créé. Dans le troisième, il s'agit d'une lvalue, et ainsi les éléments sont créés, de sorte que $_ peut être affecté.

Ce comportement n'est pas spécifique aux tranches: dans l'accès au tableau normal, le même comportement est affiché.

+0

Ding ding ding! Si j'avais un cigare à vous donner, monsieur, je le ferais. Mais je ne le fais pas. De plus, c'est l'internet. Serait difficile. –

+0

En outre, avec la copie, les éléments sont encore créés, mais ils sont créés dans la copie et non l'original. Ainsi, y accéder ne pose aucun problème. –

+0

Ces éléments supplémentaires auraient pu être complètement évités si vous aviez construit la boucle différemment. Voir mon commentaire sur la question. –

6

Je pense que ce morceau de code

@array[$index..($index+$numPerTest)] 

crée des éléments vides dans votre tableau. Ensuite, lorsque vous testez

$index < @array 

votre @array vient devenu plus grand, et l'index ne sera jamais plus grand que la taille de votre @array.

+0

Oh, désolé - Leon m'a battu à – BrianH

+0

Mais toujours à droite :) –

+0

Voilà la moitié de la réponse. Ce morceau de code est également présent dans le premier exemple, mais vous n'expliquez pas pourquoi il ne souffle pas là-bas. –

Questions connexes