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
Avatar de l’utilisateur
Polux
Messages : 440
Inscription : mer. 21/janv./2004 11:17
Localisation : france
Contact :

Message par Polux »

oulala une procédure n'est pas une fonction! Une procédure permet d'effectuer une action répétitive en lui passant des paramêtres, la fonction elle a pour différence de retourner un résultat.
Il est conseillé d'eviter d'utiliser les gosub et les return, ainsi que les goto mais dans une moindre mesure, uniquement pour une question de lisibilité du code ( quand vous bossez en équipe par exemple ).
Avatar de l’utilisateur
Flype
Messages : 2431
Inscription : jeu. 29/janv./2004 0:26
Localisation : Nantes

Message par Flype »

Code : Tout sélectionner

Procedure.l UBound(*Array)
  ProcedureReturn PeekL(*Array - 8)
EndProcedure
puisqu'on parle de 'procédure vs fonction', il y a aussi le traditionnel 'fonction vs macro'.

typiquement, ce genre de truc est à mettre dans une macro qui sera beaucoup plus rapide à l'exécution du programme.

Code : Tout sélectionner

Macro UBound(AddressOfArray)
  PeekL(AddressOfArray - 8)
EndMacro
Image
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

Polux a écrit :oulala une procédure n'est pas une fonction! Une procédure permet d'effectuer une action répétitive en lui passant des paramêtres, la fonction elle a pour différence de retourner un résultat.
ben je suis désolé mais une procedure en PureBasic EST une Fonction
en effet dans la conception de la procedure purebasic
tu a un mot clef qui s'appelle PROCEDURE RETURN !! qui sert a retourner une valeur !!
ce qui est bien le propre d'une Fonction !!
que tu n'utilise ou pas cette disponibilité, ne change pas ce fait !


Il est conseillé d'eviter d'utiliser les gosub et les return, ainsi que les goto mais dans une moindre mesure, uniquement pour une question de lisibilité du code ( quand vous bossez en équipe par exemple ).
je sais pas qui t'as conseiller ça ? :D

au contraire je le repete, l'utilisation de Sous Programme (gosub return)
est plutot conseillé puisque plus rapide qu'une Fonction (Procédure en pure basic) (pas de sauvegarde de la pile !!)

je sais que la mode consiste a utiliser des procédures (c'est a dire des Fonctions) a tout bout de champs , mais c'est surement pas une raison pour en plus chercher a en faire une règle d'or !

chacun fais bien comme il veut !
j'ai fait des programme (tres grand) sans utilisation de procedure
ni même de structure !

tout ces petit plus (procédure, structure ect..) ne sont pas indispensable a la programmation, ils ne sont que des principe de confort rien de plus !

on peut tres bien programmer un jeu sans structures, procédures
(ormis les fonctions propre du langage, bien sur :D)
et ceux même dans un projet a plusieurs , car le secret d'une bonne organisation a plusieurs, ne réside pas dans l'utilisation ou non des procédure a l'encontre des sous-programme
mais simplement d'une entente au niveau du system employé !
bref de parler le même langage ! :D
Avatar de l’utilisateur
Polux
Messages : 440
Inscription : mer. 21/janv./2004 11:17
Localisation : france
Contact :

Message par Polux »

Dans pure c'est une chose ( une proc. est une fonction ) mais en programmation générale, se sont deux choses bien différentes.
Pour ce qui est des gosub, je ne dit pas qu'ils sont moins rapides à l'execution ( au contraire ), par contre si tu bosse dans une équipe de 20 programmeurs par exemple, tu vas vite te faire insulter si tu utilise des gosub :D Moi même quand je dois taper dans du code remplit de gosub et que je dois faire des aller et venue sans arrêt pour comprendre, ça me gave très vite ( et je parle par experience ). Dans le milieu professionnel, il y a des règles, et malheureusement on y coupe pas.
Et puis quand tu code un moteur par exemple, c'est quand même plus cool d'utiliser des procédures afin de passer des paramêtres et de faire un truc plus structuré. moi ça me permet de réccupérer des procédures de mes précédents jeux et de les améliorer tranquilou. J'arrive a optimiser bien mieux les choses comme ça ( cf, tous mes jeux sont codés comme ça ).
Mais comme tu dit, personne n'a LA bonne méthode, juste celle qui lui convient :wink:
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
Répondre