Gestion des chaines (variable, pointeur, fonction, ...)
Publié : dim. 26/juin/2005 11:23
Post édité ce même jour pour clarification de mise en page
Ce post ne contient pas de question
Voici ce que j'aurais aimé trouver à mes débuts sur la gestion des chaines, et en espérant que ça puisse aider les suivants.
Commentaires, remarques et corrections d'erreur sont les bienvenus.
Les variables
La concaténation de chaine : signe '+'
Ajout de caractère
Les pointeurs
Affichage du premier caractère de la chaine avec le BON type de pointeur
Affichage du premier caractère de la chaine avec le MAUVAIS type de pointeur
MAUVAISES méthodes pour se positionner sur un caractère
BONNE méthode pour se positionner sur un caractère
Tableau de chaine
Tableau de pointeur de chaine
Tableau de pointeur de caractère de chaine
Parcours de chaine
Modification d'un caractère d'une chaine
Fonction qui retourne une constante de chaine
Fonction qui retourne une variable chaine
Fonction qui retourne une adresse de chaine
Une fonction ne peut retourner un pointeur de caractère de chaine, car le type STRUCTURE n'est pas admis en retour de procedure
Chaine en retour de fonction CallFunctionFast
Ce post ne contient pas de question
Voici ce que j'aurais aimé trouver à mes débuts sur la gestion des chaines, et en espérant que ça puisse aider les suivants.
Commentaires, remarques et corrections d'erreur sont les bienvenus.
Les variables
Code : Tout sélectionner
#ChaineCourte = "AZBY" ;Définition d'une constante de type chaine
Chaine.s = #ChaineCourte ;Initialisation de la variable de type chaine par une constante. Notez le type .s
Chaine_2.s = "CXDW" ;Initialisation de la variable de type chaine avec une chaine de caractère
Debug Chaine ;Affichage de la chaine
Code : Tout sélectionner
Chaine.s = "AZBY"
Chaine_2.s = Chaine + Chaine_2
Debug Chaine_2 ;Affichage de la chaine
Chaine_2 = Chaine + "-----" + Chaine
Debug Chaine_2 ;Affichage de la chaine
Code : Tout sélectionner
Chaine.s = "AZBY"
Chaine_2.s = Chaine + Chr(32) + "A" + Chr(13) + "Deuxième ligne" ;Ajout des caractères ' '(espace), 'A', et retour à la ligne
;l'affichage de Debug ne traite pas les caractères 'spéciaux' => rendu par MessageRequester
MessageRequester("AVEC retour à la ligne", Chaine_2)
Chaine_2 = Chaine + Chr(32) + "A" + "Deuxième ligne" ;Ajout des caractères ' '(espace), 'A',
MessageRequester("SANS retour à la ligne", Chaine_2)
Code : Tout sélectionner
;ATTENTION : L'adresse d'une chaine est l'adresse de son premier caractère
;Mais pour accéder au caractère d'une chaine, il faut utiliser le bon type de pointeur
*PtrGood.BYTE ;Il faut passer par un type .BYTE (de format structure)
*PtrBad.b ;et non un type .b
Chaine.s = "AZBY"
*PtrGood = @Chaine
*PtrBad = @Chaine
;- Affichage de l'adresse de la chaine
Debug @Chaine ;Affichage de l'adresse de la chaine
Debug *PtrGood ;Affichage de la valeur du pointeur (normalement égal à la valeur de @Chaine)
Debug *PtrBad ;Affichage de la valeur du pointeur (normalement égal à la valeur de @Chaine)
Code : Tout sélectionner
Chaine.s = "AZBY"
*PtrGood.BYTE = @Chaine
Debug Chr(*PtrGood) ;Affiche le LSB de l'adresse de la chaine
Debug Chr(*PtrGood\b) ;Affiche A, premier caractère de la chaine
Code : Tout sélectionner
Chaine.s = "AZBY"
*PtrBad.b = @Chaine
Debug Chr(*PtrBad) ;Affiche le LSB de l'adresse de la chaine
;Debug Chr(*PtrBad\b) ;Génère une erreur de compilation car le type .b n'est pas une structure
Code : Tout sélectionner
Chaine.s = "AZBY"
*PtrGood.BYTE = @Chaine
Debug Chr(*PtrGood\b + 1) ;Affiche B, caractère suivant A dans la table ASCII (i.e. A(64) + 1 = B(65 dans la table ASCII)
;Debug Chr((*PtrGood + 1)\b) ;Génère une erreur de compilation : nombre de paramètre incorrect
Code : Tout sélectionner
Chaine.s = "AZBY"
*PtrGood.BYTE = @Chaine
*PtrGood+1 ;Correspond à *PtrGood = *PtrGood + 1
Debug Chr(*PtrGood\b) ;Affiche Z, caractère suivant A dans la chaine
;Autre méthode
*PtrGood = @Chaine + 3 ;On pointe l'adresse de départ plus un décalage (ici 3)
Debug Chr(*PtrGood\b) ;Affiche Y, sans besoin de parcourir toute la chaine
Code : Tout sélectionner
Chaine.s = "AZBY"
Dim PtrProcS.s(2) ;Le tableau contient des valeurs de type chaine
PtrProcS(0) = Chaine ;Affectation d'une valeur chaine au tableau
Debug PtrProcS(0) ;Affiche la chaine
Code : Tout sélectionner
Chaine.s = "AZBY"
Dim PtrProcL.l(2) ;Le tableau contient des adresses, donc des valeurs numériques
PtrProcL(0) = @Chaine ;Affectation d'une valeur d'adresse de chaine au tableau
Debug PtrProcL(0) ;Affiche l'adresse de la chaine
Debug PeekS(PtrProcL(0)) ;Récupère la chaine à partir de son adresse et affiche la chaine
Code : Tout sélectionner
Chaine.s = "AZBY"
Dim *PtrProcB.BYTE(2) ;Le tableau contient des adresses, donc des valeurs numériques
*PtrProcB(0) = @Chaine ;Affectation d'une valeur d'adresse de chaine au tableau
Debug *PtrProcB(0) ;Affiche l'adresse de la chaine
Debug Chr(*PtrProcB(0)\b) ;Affiche A, premier caractère de la chaine
Code : Tout sélectionner
;Une chaine est par nature terminée par un caractère NULL (valeur hexadecimal 0)
Chaine.s = "AZBY"
Dim *PtrProcB.BYTE(2) ;Le tableau contient des adresses, donc des valeurs numériques
*PtrProcB(0) = @Chaine ;Affectation d'une valeur d'adresse de chaine au tableau
While *PtrProcB(0)\b ;Tant que le caractère NULL n'est pas atteint
Debug Chr(*PtrProcB(0)\b) ;Affiche le caractère suivant de la chaine
*PtrProcB(0) + 1 ;Incrementation de la valeur du pointeur => on pointe le caractère suivant
Wend
Code : Tout sélectionner
;ATTENTION : Si un caractère NULL est inséré dans la chaine, celui-ci marquera la nouvelle fin de cette chaine
Chaine.s = "AZBY"
Dim *PtrProcB.BYTE(2) ;Le tableau contient des adresses, donc des valeurs numériques
*PtrProcB(0) = @Chaine + 2 ;On pointe le caractère B
*PtrProcB(0)\b = 0 ;On remplace B par le caractère NULL
*PtrProcB(0) = @Chaine ;On repositionne le pointeur au début de la chaine
*PtrGood = *PtrProcB(0) ;On copie la variable de type pointeur de caractère de chaine dans une variable de type pointeur de chaine
Debug PeekS(*PtrGood) ;La chaine n'est plus que "AZ"
Code : Tout sélectionner
#ChaineCourte = "AZBY" ;Définition d'une constante de type chaine
Procedure.s RetourneChaine() ;Le type de la fonction est .s
ProcedureReturn #ChaineCourte
EndProcedure
Debug RetourneChaine() ;Affichage de la chaine
Code : Tout sélectionner
;Attention :
; - Si une variable n'est pas déclarée globalement, elle sera déclarée automatiquement en tant que variable locale
Global Chaine.s
Chaine = "AZBY"
Procedure.s RetourneChaine_2();Le type de la fonction est .s
ProcedureReturn Chaine ;Si Chaine n'est pas déclarée en Global, Chaine est ici une variable numeric
EndProcedure ;ce qui génère une erreur de compilation : "expect string"
Debug RetourneChaine_2() ;Affichage de la chaine
Code : Tout sélectionner
;Attention :
; - Il ne faut pas retourner l'adresse d'une variable locale, car après le EndProcedure,
; les variables locales n'existent plus
; - Pour retourner une adresse, il faut déclarer une variable globale et locale portant le même nom
; et retourner l'adresse de la variable globale
Global Res.s ;Variable Global servant pour le passage de la valeur de retour
Chaine.s = "AZBY"
Procedure.l RetourneAdChaine();Le type de la fonction est un NUMERIC : .l
Res.s = Chaine ;Si Chaine n'est pas déclaré en Global, cette ecriture génère
ProcedureReturn @Res ;une erreur de compilation : numeric to string
EndProcedure
Debug "Passage par variable Global"
Debug PeekS(RetourneAdChaine());Récupère la chaine à partir de son adresse
;Autre solution passage par une variable en paramètre : ici, Chaine n'aurait pas besoin d'être déclarée en Global
Procedure.l RetourneAdChaine_2(ChaineTmp.s)
Res.s = ChaineTmp
ProcedureReturn @Res
EndProcedure
Chaine.s = "AZBY"
Debug "Passage par une variable en paramètre de fonction"
Debug PeekS(RetourneAdChaine_2(Chaine));Récupère la chaine à partir de son adresse
;Autre solution passage par un pointeur en paramètre : ici, Chaine n'aurait pas besoin d'être déclarée en Global
Global *Res.l
Procedure.l RetourneAdChaine_3(*ChaineTmp.l)
*Res.l = *ChaineTmp
ProcedureReturn *Res
EndProcedure
Chaine.s = "AZBY"
Debug "Passage par un pointeur en paramètre de fonction"
Debug PeekS(RetourneAdChaine_3(@Chaine));Récupère la chaine à partir de son adresse
Code : Tout sélectionner
;Procedure.BYTE Test() ;Erreur de compilation
;EndProcedure
Code : Tout sélectionner
;Resultat = CallFunctionFast(*PointeurFonction [,Parametre1 [, Parametre2...]])
;CallFunctionFast permet d'appeler une fonction en passant par l'adresse de cette fonction : *PointeurFonction
;Le nombre de paramètres autorisés est quelconque mais doit correspondre exactement aux besoins de la fonction
;Resultat contient le résultat de la fonction appelée.
;ATTENTION :
;CallFunctionFast ne retourne que UNE VALEUR NUMERIC, que l'on peut traiter en tant qu'adresse, ou valeur.
;CallFunctionFast ne retourne pas de chaine
;Ceci implique qu'il faut faire attention lorsque l'on code des fonctions que l'on souhaite être appelées par un CallFunctionFast.
;Ces fonctions ne doivent pas retourner de chaine, mais un pointeur de chaine.
Global Res.s ;Variable Global servant pour le passage de la valeur de retour
Chaine.s = "AZBY"
Procedure.l RetourneAdChaine_2(ChaineTmp.s)
Res.s = ChaineTmp
ProcedureReturn @Res
EndProcedure
*PtrProc.l = @RetourneAdChaine_2() ;Stockage de l'adresse de la fonction RetourneAdChaine_2
Resultat.l = CallFunctionFast(*PtrProc, Chaine)
Debug PeekS(Resultat)