Gestion des chaines (variable, pointeur, fonction, ...)

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Oncle Karl
Messages : 10
Inscription : mer. 22/juin/2005 6:23

Gestion des chaines (variable, pointeur, fonction, ...)

Message par Oncle Karl »

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

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
La concaténation de chaine : signe '+'

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
Ajout de caractère

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)
Les pointeurs

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)
Affichage du premier caractère de la chaine avec le BON type de pointeur

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
Affichage du premier caractère de la chaine avec le MAUVAIS type de pointeur

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
MAUVAISES méthodes pour se positionner sur un caractère

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
BONNE méthode pour se positionner sur un caractère

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
Tableau de 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
Tableau de pointeur de 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
Tableau de pointeur de caractère de 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
Parcours de 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
Modification d'un caractère d'une chaine

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"
Fonction qui retourne une constante de chaine

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
Fonction qui retourne une variable 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
Fonction qui retourne une adresse de 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 
Une fonction ne peut retourner un pointeur de caractère de chaine, car le type STRUCTURE n'est pas admis en retour de procedure

Code : Tout sélectionner

;Procedure.BYTE Test()   ;Erreur de compilation
;EndProcedure
Chaine en retour de fonction CallFunctionFast

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)