Comment connaitre le nombre d'élément d'un tableau [Résolu]

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Kwai chang caine a écrit :Bonjour DENY

Merci de ta réponse 8) , mais apparement le code que tu m'a donné renvois le dimensionnement du tableau.

Ce que j'aurais aimé avoir c'est le dernier element inscrit dans le tableau.

Par exemple si un tableau est dimensionné a 100.

Code : Tout sélectionner

Dim Tableau(100)
Et que je lui dit juste que :

Code : Tout sélectionner

Tableau(1) = "premier"
Tableau(2) = "second"
Je voudrais savoir si il y a un autre moyen simple d'obtenir le nombre du dernier enregistrement c'est a dire "2" dans ce cas.
Cela evite de rechercher encore des elements dans un tableau alors que on en a jamais écris autant.
Comme ça on gagne du temps dans les boucles qui vident les tableaux dans une listview par exemple.

Code : Tout sélectionner

Dim Tableau.s(100)
Tableau(1) = "premier"
Tableau(2) = "second"

For i = 1 To 100
  
 If Trim(Tableau(i)) = ""
  i - 1
  Break
 EndIf  

Next 

Debug Str(i) + " est le dernier element du tableau"
Oui, il y a moyen :D

Code : Tout sélectionner

Declare.L LastString(*Index)
Declare KillString(Tmp.S(1), n.L)

Dim Tartare.S(70)

Tartare(0) = "Aie"
Tartare(1) = "Aioli"
Tartare(2) = "Fines herbes"

Debug "On a le tableau suivant :"
For i = 0 To 3
Debug Str(i) + "= " + Tartare(i)
Next
Debug " "


*Adr = LastString(@Tartare() )
Debug "n° de la dernière chaîne créée : " + Str(*Adr) + " (" + Tartare(*Adr) + ")"

Debug "On défonce " + Tartare(2) + " avec KillString() pas avec Tartare(x) = " + Chr(34) + Chr(34)
KillString(Tartare(), 2)

*Adr = LastString(@Tartare() )
Debug "n° de la dernière chaîne créée : " + Str(*Adr) + " (" + Tartare(*Adr) + ")"

Procedure.L LastString(*Index) ;(Ollivier spéciale dédicace à Kcc)
! xor   eax,   eax             
! mov   edi,  dword [p.p_Index]
! mov   ebx,  edi             
! mov   ecx,  0xFFFFFFFF
! cld                        
! REPNE  SCASD ; >>> Une seule instruction ASM pour For: If PeekL() = 0: ExitFor: EndIf: Next
! mov   eax,  edi
! sub   eax,  ebx
! shr   eax,  2
! sub   eax,  2
ProcedureReturn
EndProcedure

Procedure KillString(Tmp.S(1), n.L)
  Tmp(n) = ""                  ; Fred gère la mémoire
  *ptr = @Tmp()                ; on récupère l'adresse du tableau
! xor   eax,  eax              ; on va écrire un LONG (=DWORD) = 0
! mov   ebx,  dword [p.v_n]    ; on récupère le n de la chaîne
! shl   ebx,  2                ; on le multiplie par 4 (car SizeOf(Long) = 4)
! mov   edi,  dword [p.p_ptr]  ; on pointe le tableau
! add   edi,  ebx              ; on se précise sur le pointeur à killer
! stosd                        ; on le kille
EndProcedure
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Attention pour la commande KillString() /!\
J'ignore si elle est fiable à 100%. Je pressents que le fonctionnement des tableaux soit plus complexe que je ne l'imagine. Donc, si tu veux du fiable, utilise uniquement la procedure LastString(). C'est déjà pas mal comme système.
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

Tout d'abord merci à tous de votre interet 8)

@NICO
C'est vrai qu'en partant de la fin cela peut etre plus rapide.
Et encore sans compter avec votre gaufrette préférée en ma personne qui a tendance a surdimensionner les tableaux pour etre sur de ne pas avoir un jour un "Array index out of bounds" :D

Il faut dire que j'ai induit GNOZAL en erreur car c'est moi par mon code du debut de POST qui comptait du début.

Quoi qu'il en soit merci de ton code, il me sera aussi tres utile.

Encore une question car notre ami GNOZAL n'a pas répondu.
J'aime bien faire des procedures intrinseques, comme ça on est sur de ne pas oublier une declaration ou une autre procedure qui lui est necessaire lors du prochain copier/coller.

Est ce que si je fourre tout dans la procedure cela ne pose pas de problemes :

Code : Tout sélectionner

Procedure.l DernierElementTablo(*Array) 

 Structure StringArray 
  s.s[0] 
 EndStructure 
  
 Protected i.l, DernierElement.l, *TempArray.StringArray 
 *TempArray = *Array 
 
 For i = PeekL(*Array - 8) To 0 Step -1 
  If *TempArray\s[i] <> "" 
   DernierElement = i 
   Break 
  EndIf 
 Next 
 
 ProcedureReturn DernierElement 

EndProcedure 

Dim Tablo.s(10) 

Tablo(0) = "0" 
Tablo(1) = "1" 
Tablo(2) = "2" 
Tablo(3) = "" 
Tablo(4) = "4" 
Tablo(5) = "" 
Tablo(6) = "" 
Tablo(7) = "" 
Debug DernierElementTablo(Tablo())
@FLYPE
Bonjour mon merlin préféré
Je vois que t'essaie toujours de caser tes macros ....est-ce qu'il sont frais au moins :lol:
Tu as raison, c'est surement mieux pour le code, mais y'a rien à faire les macros en PURE j'ai du mal a m'y faire, comme mon estomac dans la vie d'ailleurs :lol:
Mais tu fait bien de forcer la vente :wink:

@Ollivier
Cool, une nouvelle fonction pour pure en ASM.
J'aime l'ASM, j'y comprend couic, mais c'est toujours aussi beau.
J'ai compris que pour un tableau PURE, il y a une difference entre VIDE et NUL, comme pour VB d'ailleurs :? ça me gonfle, car c'est souvent la cause de pas mal de bug tant qu'on a pas compris la difference.
T'aurais pas la meme fonction avec la detection de VIDE pour avoir l'équivalent du code de GNOZAL et NICO ????

En tout cas grand merci de ton joli code avec noir de hieroglyphe dedans :D
T'etais peut etre egyptien dans une autre vie :lol:

@LA FAMILLE
Encore merci, de vos aides.
Je vous aime
Que les dieux vous apportent joie et santé à vous et votre famille, pendant les deux millenaires qui nous survivrons. :D
gnozal
Messages : 832
Inscription : mar. 07/déc./2004 17:35
Localisation : France
Contact :

Message par gnozal »

nico a écrit :La méthode employée par Gnozal liste tous les éléments du tableau, ce qui n'est pas nécessaire, la logique voudrait qu'on parte de la fin et que l'on s'arrête au premier élément non vide trouvé.
J'ai simplement utilisé le code de Kwai chang caine sans le modifier. La question n'était pas de l'optimiser mais de pouvoir utiliser un tableau comme argument de procédure.
Kwai chang caine a écrit :Est ce que si je fourre tout dans la procedure cela ne pose pas de problemes :
No problem, sir !
Kwai chang caine a écrit :J'ai compris que pour un tableau PURE, il y a une difference entre VIDE et NUL, comme pour VB d'ailleurs ça me gonfle, car c'est souvent la cause de pas mal de bug tant qu'on a pas compris la difference.
Si on parle de tableau de chaînes par exemple :
VIDE = la chaîne existe [pointeur valide] mais il n'y a pas de caractères dedans, le pointeur pointe vers un 0 [fin de chaîne]
NUL = la chaîne n'existe pas [pointeur nul = pas de mémoire allouée], et on s'expose à une erreur de type 'illegal memory access' ou 'specified address is null'.
C'est pourquoi dans mon premier exemple [Peek/Poke] je vérifie que *AddresseChaine n'est pas nul.

Avec Peek / Poke

Code : Tout sélectionner

Procedure.l UBound(*Array)
  ProcedureReturn PeekL(*Array - 8) - 1
EndProcedure

Procedure.l DernierElementTablo(*Array)
  Protected i.l, DernierElement.l, *AddresseChaine
  For i = 0 To UBound(*Array)
    *AddresseChaine = PeekL(*Array + i * 4)
    If *AddresseChaine
      If PeekS(*AddresseChaine) <> ""
        DernierElement = i
      EndIf
    EndIf
  Next
  ProcedureReturn DernierElement
EndProcedure


Dim Tablo.s(10)

Tablo(0) = "0"
Tablo(1) = "1"
Tablo(2) = "2"
Tablo(3) = ""
Tablo(4) = "4"
Tablo(5) = ""
Tablo(6) = ""
Tablo(7) = ""

Debug DernierElementTablo(Tablo())
Avec astuce de pointeurs

Code : Tout sélectionner

Procedure.l UBound(*Array)
  ProcedureReturn PeekL(*Array - 8) - 1
EndProcedure

Structure StringArray
  s.s[0]
EndStructure

Procedure.l DernierElementTablo(*Array)
  Protected i.l, DernierElement.l, *TempArray.StringArray
  *TempArray = *Array
  For i = 0 To UBound(*Array)
    If *TempArray\s[i] <> ""
      DernierElement = i
    EndIf
  Next
  ProcedureReturn DernierElement
EndProcedure

Dim Tablo.s(10)

Tablo(0) = "0"
Tablo(1) = "1"
Tablo(2) = "2"
Tablo(3) = ""
Tablo(4) = "4"
Tablo(5) = ""
Tablo(6) = ""
Tablo(7) = ""

Debug DernierElementTablo(Tablo())
brossden
Messages : 833
Inscription : lun. 26/janv./2004 14:37

Message par brossden »

@ Polux

Je suis désolé de dire cela mais je pense que tu es à coté de la plaque !
Tu fais une grosse brasse entre les procedures, les fonctions, les branchement conditionnel ou non !

Les procedures sont des fonctions et "Lycée de Versailles" avec ou sans retour. Ce sont deux terminologies pour la même chose. L'une est issue du français l'autre de l'anglais.

Les branchements eux sont tout à fait autre chose, les Gosub peuvent effectivement être utilisés par de programmateurs débutant ou de mauvais dévelpppeur comme des fonctions ou procedures, mais il étaient utilisés les anciens languages qui ne pocedaient pas de fonction. Pour ce qui est des Goto, leurs véritables raison d'être est un saut ou un branchement pour sauter tout une partie de code. Par exemple si des conditions de départ ne sont pas réalisées aller directement au processus de fin de programme sans se taper une condition depuis le début du programme.

exemple

If SaisieMotDePasse() <> "MDP"
Goto Fin
Endif

Reste du programme
..........
..........
..........

Fin:
End

au lieux de :

If SaisieMotDePasse() = "MDP"

Reste du programme
..........
..........
..........

Endif
End

Pour ce qui est du travail en équipe, il existe en général une charte que tout un chacun se doit de respecter... et je vois mal qui d'autre que le chef de projet aller relire les lignes pissées par ses développeurs ! lors se faire jeter par le reste de l'équipe ???????????
Et si certains utilisent des gosub ils doivent avoir 80 ans non ? :lol:
Denis

Bonne Jounée à tous
ATHOW
Messages : 226
Inscription : mer. 29/déc./2004 16:54

Message par ATHOW »

En ce qui concerne les fonctions/procédures, en fait, tout dépend du langage... en Java, on n'utilisera ni l'un ni l'autre mais des "méthodes".

On fait la distinction "procédure" = "fonction ne renvoyant pas de résultat" dans certains langages mais la syntaxe des deux reste souvent la même (par exemple en C, public int truc() est une fonction renvoyant un entier, et public void machin() est une fonction ne renvoyant rien, c'est à dire une procédure...).

En PureBasic, cette distinction est inutile (comme dans la plupart des langages), et comme Fred a prévu uniquement les mots clé "Procedure", "ProcedureReturn" et "EndProcedure", autant ne parler que de procedures !

Pour les GoSub, je trouve ça moche (comme les Goto etc) même si je les ai utilisés il fut un temps.
Pour le travail en équipe, en effet, le mieux est d'utiliser un code découpé en de nombreuses procédures/fonctions/méthodes, bien documentées. C'est plus lisible et plus facile à débugger.
La plupart du temps, en fait, avant de commencer un projet en équipe (ou en solo) on commence par un cahier des charges. Pour un projet "sérieux" (entreprise), on élabore ensuite des diagrammes UML, des design patterns... qui laissent finalement peu de place à l'inventivité du développeur (il n'aura qu'à lire les diagrammes et coder les procédures comme si il remplissait un texte à trou).

Voila les éclaircissements que je peux apporter.
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

@GNOZAL
gnozal a écrit :
nico a écrit :La méthode employée par Gnozal liste tous les éléments du tableau, ce qui n'est pas nécessaire, la logique voudrait qu'on parte de la fin et que l'on s'arrête au premier élément non vide trouvé.
J'ai simplement utilisé le code de Kwai chang caine sans le modifier. La question n'était pas de l'optimiser mais de pouvoir utiliser un tableau comme argument de procédure.
Je t'avais déjà défendu, il faut reconnaitre qu'avec un associé comme moi ... :roll:
Il faut dire que j'ai induit GNOZAL en erreur car c'est moi par mon code du debut de POST qui comptait du début.
Je te remercie de l'explication en détail, c'est vrai ces VIDES et NULS, c'est NUL :lol:
Quand on est debutant on ne voit pas trop l'interet et la subtilité.
Ce qui serait bien, c'est que les NUL n'existent pas (Comme dans la vie d'ailleur :lol:) comme ça on aurait pas d'erreur quand on essaye de les lire.
Avatar de l’utilisateur
cederavic
Messages : 1338
Inscription : lun. 09/févr./2004 23:38
Localisation : Bordeaux

Message par cederavic »

Hello,
J'ai trouvé ce poste très interessant! J'apporte donc ma pierre a l'édifice avec une procédure (ouaip je marche qu'a coups de procedure moi :p) qui recherche le "dernier element inserré" en partant du millieu du tableau et en le parcourant dans les deux sans.
Le plus de ce code c'est que le tableau peut avoir une structure "personnalisée". Il suffit juste de donne la taille de cette structure!
Les moins : tableau à une dimension et ça fonctionne pas avec le type String seul (par exemple Dim Test.s(200)). Je me suis pas encor penché sur ce problème, mais je le ferais!
En attendant, voila le code :

Code : Tout sélectionner


Procedure LastInsert(*Array, sSize.l)
  ; *Array  : Pointeur vers le tableau
  ; sSize   : SizeOf() du tableau (taille en memoire d'un element)
  ; dSize   : Nombre d'elements dans le tableau
  ; tSize   : Taille totale en memoire du tableau
  ; *Empty  : Allocation d'un element "vide"
  ; *Copy   : Allocation d'un element "copié" pour comparaison
  
  dSize = PeekL(*Array - 8)
  tSize = sSize * dSize
  
  *Empty = AllocateMemory(sSize)
  *Copy = AllocateMemory(sSize)
  
  ; On commence par le millieu du tableau et on va le parcourir de MinS1 (0 a la premiere passe) à Millieu et de Milleu a dSize
  S1 = dSize / 2
  S2 = S1 + 1
  
  MinS1 = 0
  If S2 > dSize : S2 = dSize : EndIf
  
  Repeat
    
    If S1 >= MinS1
      ; Copy et comparaison entre l'élément S1 et l'élément "vide"
      CopyMemory(*Array + sSize * S1, *Copy, sSize)
      If CompareMemory(*Empty, *Copy, sSize) = 1 ; L'élément S1 est "vide", on continu
        S1 - 1
      Else ; L'élément S1 n'est pas vide, ça sert a rien d'aller plus bas, on sauvegarde la position
        D1 = S1
        S1 = - 1
      EndIf
    EndIf
    
    If S2 <= dSize
      ; Copy et comparaison entre l'élément S2 et l'élément "vide"
      CopyMemory(*Array + sSize * S2, *Copy, sSize)
      If CompareMemory(*Empty, *Copy, sSize) = 1 ; L'élément S2 est "vide", on continu 
        S2 + 1
      Else ; L'élément S2 n'est pas vide, on sauvegarde la position et on prend le millieu entre S2 et dSize
        D2 = S2
        MinS1 = S2
        S1 = S2 + ((dSize - S2) / 2)
        S2 = S1 + 1
      EndIf
    Else ; On a atteint la fin du tableau -> Verdicte
      Eod = #True
    EndIf
  
  Until Eod = #True
  
  If D1 > D2 ; Rien de compliqué, on retourne l'élément le plus grand
    ProcedureReturn D1
  Else
    ProcedureReturn D2
  EndIf

EndProcedure

Structure tStruct ; Structure de test
  a.b
  b.l
  c.q
  d.s
EndStructure

Dim Test.tStruct(200)

For t = 0 To 4 ; on insère 4 éléments au hazard
  id.l = Random(200)
  a.d = Random(255) - 128
  b.l = Random(255) - 128
  c.q = Random(255) - 128
  d.s = Chr(Random(255))
  Test(id)\a = a
  Test(id)\b = b
  Test(id)\c = c
  Test(id)\d = d
  
  If id > lastid : lastid = id : EndIf
  
Next

Debug "Dernier élément : " + Str(lastid)
Debug "==="

Debug "Dernier trouvé : " + Str(LastInsert(@Test(0), SizeOf(tStruct)))
PS : sur un tableau de 10000 éléments avec 1000 insertion, il me le trouve en 0 ms! (timer = gettickcount_() avant LastInsert(), et debug gettickcount_() - timer apres LasteInsert())
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

Bonjour CEDERAVIC
cederavic a écrit : J'ai trouvé ce poste très interessant!
Je te remercie............., Kcc y pose noire (Beaucoup, pour DOBRO :wink: ) de questions avec son QI de moule, et donne pas des brouettes de soluces, mais il est content que ça puisse servir à quelque chose.

Bah dis donc, cette fois c'est de la haute voltige 8)
On reconnais bien la ton talent.

0 ms !!! Bientot tu va nous faire un code qui donnera le résultat avant de lancer l'appli :D

Merci de ta pierre qui est la tres bienvenue sur l'edifice de ma méconnaissance :wink:
Avatar de l’utilisateur
cederavic
Messages : 1338
Inscription : lun. 09/févr./2004 23:38
Localisation : Bordeaux

Message par cederavic »

Bouerf, j'suis sur que tu sais faire plein de choses extras ;)
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

C'est sympa 8) .
Tu as raison, je sais pas mal de choses comme vous tous, mais étalées sur pas mal de domaines....
Ce qui fait que je sais pas beaucoup dans chaque domaine.

Alors je suis en admiration devant les personnes qui ont su faire le bon choix du début et ne pas s'éparpiller tout au long de leur vie.

Car en principe, on a pas assez d'une vie entiere pour creuser 70 % d'un domaine quand on s'y attelle vraiment, alors je t'explique pas quand tu brasse sur une dizaine, voir plus.

Moi maintenant j'aimerais oublier les milliers de choses qui sont dans ma tete pour ne laisser place qu'a la prog.
Car quand j'apprend quelque chose, si je le note pas .....
C'est peut etre alzeimher qui me guette :cry:

Le bleme c'est que j'arrive pas a trouver la pile de mon BIOS, pour mon RAZ, j'ai du etre construit par "packard bell" ou "ACER" :D

Déjà c'est au départ de ma vie.
Je crois que j'ai merdé
Quand j'etait petit, j'aurais du choisir l'option "Informatique" en maternelle, au lieu de ça j'ai pris "Légo"....
Aaaah la boulette, mais la boulette..... :D
Avatar de l’utilisateur
Crystal Noir
Messages : 892
Inscription : mar. 27/janv./2004 10:07

Message par Crystal Noir »

Bah tu peux te rattraper en prenant l'opion MindStorm :D Comme ca option lego spécialité MindStorm hop tu allies les deux :D


Pour ceux qui connaissent pas : MindStorm ce sont des logos programmables via PC :)
Avatar de l’utilisateur
cederavic
Messages : 1338
Inscription : lun. 09/févr./2004 23:38
Localisation : Bordeaux

Message par cederavic »

Personnelement je pense qu'il vaut mieu etre un minimum compétent dans plusieur domaines et etre polyvalent plutot qu'etre a fond sur un sujet et etre à la ramasse quand on parle d'autre chose.
Disons que toucher un peut à tout en prog c'est comme la culture générale.
Je suis pas spécialisé dans un domaine, le code du dessus c'est seulement des connaissance d'un peut partout, mais assemblé ça donne quelquechose :)
Bref, il n'est jamais trop tard ;)
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

Merci de tes encouragements.

Le probleme, c'est que ce n'est pas qu'en programmation que j'ai pratiqué l'eclectisme à outrance. :cry:
En fait quand je parle de domaines, ce n'est pas qu'en informatique (Malheureusement), mais dans d'autres activités qui n'ont rien à voir les unes avec les autres.

Et la je peux te dire que j'ai tendance à me mélanger les pingoinces.
Mais c'est pas grave, je rame, je rame, j'ai bientot attaqué la falaise, heureusement que y'a des personnes comprehensives comme vous tous, sans quoi ..... :cry:
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

@Kcc

Regarde! Je reprends ma fonction de l'espace-temps

Code : Tout sélectionner

Procedure.L LastString(*Index) ;(Ollivier spéciale dédicace à Kcc) 
! xor   eax,   eax                         ; eax = 0
! mov   edi,  dword [p.p_Index]    ; edi = pointeur index
! mov   ebx,  edi                         ; ebx = pointeur index
! mov   ecx,  0xFFFFFFFF              ; ecx = 4Go
! cld                                           ; cld = recherche de bas en haut
! REPNE  SCASD ; >>> Une seule instruction ASM pour For: If PeekL() = 0: ExitFor: EndIf: Next 
! mov   eax,  edi                         ; eax = adresse trouvée
! sub   eax,  ebx                         ; eax = adresse trouvé - adresse tableau
! shr   eax,  2                             ; eax / 4
! sub   eax,  2                            ; eax - 2
ProcedureReturn 
EndProcedure 

Je change le tout dernier chiffre de la dernière ligne ASM (le 2 devient 1) et je mets un nouveau le nom

Code : Tout sélectionner

Procedure.L NextNullString(*Index) ;(Ollivier spéciale dédicace à Kcc) 
! xor   eax,   eax                         ; eax = 0
! mov   edi,  dword [p.p_Index]    ; edi = pointeur index
! mov   ebx,  edi                         ; ebx = pointeur index
! mov   ecx,  0xFFFFFFFF              ; ecx = 4Go
! cld                                           ; cld = recherche de bas en haut
! REPNE  SCASD ; >>> Une seule instruction ASM pour For: If PeekL() = 0: ExitFor: EndIf: Next 
! mov   eax,  edi                         ; eax = adresse trouvée
! sub   eax,  ebx                         ; eax = adresse trouvé - adresse tableau
! shr   eax,  2                             ; eax / 4
! sub   eax,  1                            ; eax - 1
ProcedureReturn 
EndProcedure 

PS:
* NextNullString() ne convient pas au tableau de moins de 1 pointeur déjà alloué
Dernière modification par Ollivier le mer. 08/août/2007 16:49, modifié 2 fois.
Répondre