none
gestion d'un tableau dans une fonction récursive (Résolu) RRS feed

  • Question

  • Bonjour,

    sur une petite fonction récursive sous Microsoft Visual Basic 2015 je passe une petite table de byte comme argument.

    comme c'est récursif, je veux manipuler ce tableau dans la procédure sans modifier le tableau de l'appelant, puisque ce tableau servira d'argument pour les appels suivants récursifs.

    La table contient un nombre raisonnable d'éléments (variable de 1 à 10), 

    1 - est-il possible de passer cette table en valeur seulement ? (Byval non fonctionnel pour les tableaux)

    2 - sinon, comment copier les valeurs de ce tableau dans un tableau local autrement que par une boucle, puisque tab_loc=tab_arg copie, comme j'ai compris, la référence ?

    3 - dans ma procédure (en utilisant une boucle pour copier les valeurs dans un tableau local), j'utilise un Array.IndexOf sur cette table (byte) locale et j'ai constaté une fois que le résultat de la recherche ne correspondait pas aux valeurs espion de cette table que je voyais. Lors de cette observation (sur point d'arrêt) je n'ai pas pensé à observé les variables locales. 

    Mon code "semble" fonctionnel jusqu'à une certaine profondeur, mais il me manque la connaissance des subtilités sur la manipulation de tableaux, arguments, références afin de blindé et d'optimiser, et partir sur de bonnes bases pour déboguer les couches profondes !!

    merci de vos conseils.

    Bruno


    samedi 21 mai 2016 13:52

Réponses

  • Le plus simple est de passer un Clone du tableau:

    Dim ClonePourPassage() as Integer = UnTableau.Clone

    puis appeller la ProcedureModification(ClonePourPassage)...:

    et le code:

    Public Class Form1
        Private UnTableau() As Integer
    
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'Lancement de la Form
            'Création de l'array
            ReDim UnTableau(10)
            RichTextBox1.AppendText("Création du tableau" & Environment.NewLine)
            Dim intIndex As Integer
            For intIndex = 0 To UnTableau.Length - 1
                UnTableau(intIndex) = intIndex
                RichTextBox1.AppendText(UnTableau(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
    
        End Sub
    
        Private Sub ModifByval(ByVal TableauByVal() As Integer)
            Dim intIndex As Integer
            For intIndex = 0 To TableauByVal.Length - 1
                TableauByVal(intIndex) = TableauByVal(intIndex) * 2
                RichTextBox1.AppendText(TableauByVal(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Passage ByVal
            RichTextBox1.AppendText("Modification du tableau passé ByVal" & Environment.NewLine)
            ModifByval(UnTableau)
            RichTextBox1.AppendText("Après ModifByVal " & Environment.NewLine)
            Dim intIndex As Integer
            For intIndex = 0 To UnTableau.Length - 1
                RichTextBox1.AppendText(UnTableau(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            'Passage ByVal
            Dim TableauClone() As Integer
            TableauClone = UnTableau.Clone
            RichTextBox1.AppendText("Création d'un Clone et Modification du tableau Cloné " & Environment.NewLine)
            ModifByval(TableauClone)
    
            RichTextBox1.AppendText("Après ModifByVal du clone " & Environment.NewLine)
            RichTextBox1.AppendText("Le tableau original n'est pas modifié = " & Environment.NewLine)
            Dim intIndex As Integer
            For intIndex = 0 To UnTableau.Length - 1
                RichTextBox1.AppendText(UnTableau(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
        End Sub
    End Class


    Pour référence, le ByVal pour un paramètre qualifie en fait l'objet, ici un "Array" pas les valeurs ...subtil mais dévastateur lorsqu'on l'oublie...

    Et le Clone fait toute la "profondeur" de l'objet, donc toutes les dimensions, tous les éléments si c'est un objet complexe...

    samedi 21 mai 2016 22:42

Toutes les réponses

  • Le plus simple est de passer un Clone du tableau:

    Dim ClonePourPassage() as Integer = UnTableau.Clone

    puis appeller la ProcedureModification(ClonePourPassage)...:

    et le code:

    Public Class Form1
        Private UnTableau() As Integer
    
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'Lancement de la Form
            'Création de l'array
            ReDim UnTableau(10)
            RichTextBox1.AppendText("Création du tableau" & Environment.NewLine)
            Dim intIndex As Integer
            For intIndex = 0 To UnTableau.Length - 1
                UnTableau(intIndex) = intIndex
                RichTextBox1.AppendText(UnTableau(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
    
        End Sub
    
        Private Sub ModifByval(ByVal TableauByVal() As Integer)
            Dim intIndex As Integer
            For intIndex = 0 To TableauByVal.Length - 1
                TableauByVal(intIndex) = TableauByVal(intIndex) * 2
                RichTextBox1.AppendText(TableauByVal(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Passage ByVal
            RichTextBox1.AppendText("Modification du tableau passé ByVal" & Environment.NewLine)
            ModifByval(UnTableau)
            RichTextBox1.AppendText("Après ModifByVal " & Environment.NewLine)
            Dim intIndex As Integer
            For intIndex = 0 To UnTableau.Length - 1
                RichTextBox1.AppendText(UnTableau(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            'Passage ByVal
            Dim TableauClone() As Integer
            TableauClone = UnTableau.Clone
            RichTextBox1.AppendText("Création d'un Clone et Modification du tableau Cloné " & Environment.NewLine)
            ModifByval(TableauClone)
    
            RichTextBox1.AppendText("Après ModifByVal du clone " & Environment.NewLine)
            RichTextBox1.AppendText("Le tableau original n'est pas modifié = " & Environment.NewLine)
            Dim intIndex As Integer
            For intIndex = 0 To UnTableau.Length - 1
                RichTextBox1.AppendText(UnTableau(intIndex) & " ")
            Next
            RichTextBox1.AppendText(Environment.NewLine)
        End Sub
    End Class


    Pour référence, le ByVal pour un paramètre qualifie en fait l'objet, ici un "Array" pas les valeurs ...subtil mais dévastateur lorsqu'on l'oublie...

    Et le Clone fait toute la "profondeur" de l'objet, donc toutes les dimensions, tous les éléments si c'est un objet complexe...

    samedi 21 mai 2016 22:42
  • Euh..j'suis pas sur.

    La méthode Clone de Array fait un MemberwiseClone.

    Or MemberwiseClone fait une copie superficielle. (https://msdn.microsoft.com/fr-fr/library/system.object.memberwiseclone.aspx)

    "MemberwiseClone méthode crée une copie superficielle en créant un nouvel objet, puis en copiant les champs non statiques de l'objet actuel vers le nouvel objet. Si un champ est un type valeur, une copie bit par bit du champ est effectuée. Si un champ est un type référence, la référence est copiée, mais l'objet référencé ne l'est pas. Par conséquent, l'objet d'origine et son clone font référence au même objet."


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone



    dimanche 22 mai 2016 08:43
  • Il faut savoir que l'interface IClonable et la méthode Clone est une erreur du Framework (erreur reconnue par les designers du Framework) car on ne sait pas si c'est une copie superficielle ou profonde (deep copy).

    Je ne sais pas exactement ce que vous cherchez à faire mais si vous voulez travailler sur une copie de l'objet, si ce dernier possède des props de type référence (or string), la copie doit se faire à la main (tous les autres mécanismes qui existent sont la plupart du temps boguées et difficilement deboguables).


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    dimanche 22 mai 2016 08:47
  • L'OP veut utiliser un tableau de Byte, on ne fait pas plus simple...

    Richard, je vois la différence sur Deep et Shallow copy (this msdn: https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone%28v=vs.110%29.aspx)

    Dans le cas d'un tableau de byte il n'y a pas de référence d'un autre Objet à l'intérieur de l'Objet, donc la copie récursive (Deep copy) n'est pas nécessaire.... Mais il faut bien se rappeler de cet exemple dans le cas d'objets plus complexes... l'exemple dans le MSDN est très parlant

    dimanche 22 mai 2016 09:04
  • merci à tous ...

    Sur la base du clone que je découvre j'ai essayé de passer le tableau en clone directement en argument et cela semble marcher !

    - le premier appel de la fonction se fait depuis un array TM (Dim TM() As Byte, environ une dizaine au maximum) 

            ....

    For i As Byte = 0 To 3
                Explore("", TM.Clone, i)
            Next

    ....

    Private Sub Explore(ByVal parcours As String, tmr() As Byte, ByVal sens As Byte)

    .... code avec tmr local

    Explore(parcours, tmr.Clone, i)   'rappel reccursif

    End sub

    dans cet état les fonctions array.sort(Tmr) ou Array.Exists(tmr, Function...) semblent fonctionnelles et propres aux multiples tmr locales clonées.

    Je vais tenir compte de vos observations et conseils pour observer mon application avec ce type d'array simple. 

    Dès que possible je lance un cas chargé au max et assez profond et voir le résultat, mais pour l'instant tout fonctionne et rien ne fume.

    encore merci de vos aides

    Bruno


    • Modifié Brunodu06 lundi 23 mai 2016 10:25 correction appel sub
    lundi 23 mai 2016 09:28
  • C'est pour ca que j'évite d'utiliser les manières "automatiques" de faire des clones : on sait pas ce qu'on fait exactement.

    Et c'est pour cela aussi que le .NET Framework n'utilise pas IClonable (bien que l'idée au début était sympa ;-))


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    lundi 23 mai 2016 09:32