Portée de variable

zakak
Portée de variable

Bonjour !

Je dois écrire une fonction ne retournant rien et prenant en paramètre une chaine de caractères pour la modifier. Le problème, c'est qu'à l'intérieur de la fonction, la variable est bien modifiée, mais pas à l'extérieur. C'est tout à fait normal d'après le code vu que je ne retourne rien. Mais comment puis-je faire pour retourner la nouvelle chaine sans faire de char * fonction(char * chaine) ???

#include <stdio.h>
#include <stdlib.h>

void fonction(char * chaine)
{
  chaine = "azerty";
  printf("%s\n", chaine); // ca ecrit azerty
}

int main()
{
char * chaine="qwerty";

fonction(chaine);

printf("%s\n", chaine); // ca ecrit qwerty
return 0;
}

Merci d'avance !

labofonic

Dans quel langage codes-tu stp? (on dirait du C)
Je ne pratiques pas le C, mais je peux déjà te répondre du point de vue strictement algorithmique.

Ton raisonnement me semble erroné : si tu veux modifier ta chaine de caractère, quel que soit le langage ( C, PHP, javascript...), tu dois utiliser une fonction qui recevra en argument la chaîne à modifier et qui retournera en sortie la chaîne modifiée.

Ta variable "chaine" a une portée limitée à la fonction dans laquelle elle a été déclarée : main.
Lorsque main passe l'argument chaine à fonction, fonction la copie en mémoire et c'est seulement cette copie qui est modifiée.

Tu as donc passé l'argument par valeur, et non pas par référence.
Ce qui est d'ailleurs une bonne manière de procéder.

Pour que fonction modifie chaine directement, il faudrait que tu passes l'argument par référence. Au lieu de travailler sur une copie, fonction disposerait alors d'un pointeur sur l'adresse mémoire de chaine, ce qui lui permettrait de modifier directement le contenu de chaine.

Ce mécanisme serait assez dangereux : il s'apparente à l'utilisation abusive de variables globales.
Ce genre de mauvaises pratiques rend le déboggage et la maintenance malaisés : il devient difficile de suivre les traitements subis par une variable.

Les technologies objet ont généralisé l'usage de l'encapsulation : la fonction appelée travaille seulement sur une copie de la variable, et renvoie la valeur modifiée.
On trace ainsi facilement les modifications de la valeur de la variable.

Tu dois donc modifier fonction pour qu'elle renvoie la chaine modifiée.

PS : à l'avenir stp :
- précise quel langage tu utilises : ça permet de rédiger directement une correction
- utilise des noms de variables et de fonctions explicites : ici tu aurais pu utiliser maChaine et maFonction -noms génériques acceptables pour un exemple aussi simple-, ou mieux : maSaisie et ChangerSaisie
(on utilise généralement des verbes d'action pour les procédures et les fonctions).

zakak

OK merci beaucoup pour cette réponse rapide !

Il s'agit en effet du C.

Je teste pour voir...

Merci encore !

jrebillat

Toutes les remarques de labofonic sont parfaitement justifiées. Laisser les fonctions modifier les éléments fournis en entrée est à éviter, surtout pour ceux qui, comme les chaines de caractères en C/C++ sont des tableaux alloués.

Toutefois, ce qui arrive ici est plus vicieux que ce qui est expliqué par labofonic.
En effet le paramètre chaine est un pointeur sur une chaine de caractère. Donc ce qui est passé par valeur, c'est le pointeur, pas la chaine !
Ce qui veut dire que tu peux changer le contenu de la chaine (par un accès direct avec chaine[i] ou des fonctions comme strcpy(). Avec une limitation de taille (jeu de mot) : attention à la longueur de la chaine à recopier, qui doit être inférieure ou alors à celle d'entrée !

Toi, tu as changé l'adresse pointée par le pointeur en le dirigeant vers une constante chaine locale à la fonction. Heureusement, le changement était uniquement local (pas dans la variable chaine du main) car sinon la zone pointée par le pointeur retourné pourrait (ça dépendra du compilateur) ne pas être valide.

Tu es tombé sur une potentialité du C à créer des bugs difficiles à résoudre. C'est pourquoi les conseils de labofonic sont à suivre.

fredericmazue

Quote:
Toutefois, ce qui arrive ici est plus vicieux que ce qui est

expliqué par labofonic.
En effet le paramètre chaine est un pointeur sur une chaine de caractère.

Donc ce qui est passé par valeur, c'est le pointeur, pas la chaine !
Ce qui veut dire que tu peux changer le contenu de la chaine (par un
accès direct avec chaine[i] ou des fonctions comme strcpy(). Avec une limitation de taille (jeu de mot) : attention à la longueur de la chaine à recopier, qui doit être inférieure ou alors à celle d'entrée !

Tout à fait !
Et même plus que cela... on NE PEUT PAS en C écrire une fonction qui
retourne une chaine car

- le type chaine n'existe pas
- char * n'est pas une chaine. L'erreur ultra classique est alors

char *buggy(char *param)
{
  char chaine[256];
  strcpy(chaine, param);
  return chaine; //BANG
}

parce que la prétendue chaine (mais le vrai tableau) est sur la pile et sera détruite à la sortie de la fonction.

Quote:
Toi, tu as changé l'adresse pointée par le pointeur en le dirigeant vers une constante chaine locale à la fonction. Heureusement, le changement était uniquement local (pas dans la variable chaine du main) car sinon la zone pointée par le pointeur retourné pourrait (ça dépendra du compilateur) ne pas être valide.

En plus...
Et comme on ne peut pas compter sur le comportement d'un compilateur le code est pas bon du tout du tout.

Il est important de bien avoir en tête qu'en C le type chaine n'existe pas. donc on ne peut pas le copier, l'affecter, le retourner. Ce qu'on fait quand on travaille avec des "chaine" en C c'est travailler
avec des tableau de char. Comme, jrebillat te l'as dit: "accès direct
avec chaine[i]". Et sa recommandation "attention à la longueur de la
chaine à recopier, qui doit être inférieure ou alors à celle d'entrée !" ne sera sans doute doute jamais trop répétée. Et j'ajoute attention au zéro final de la "chaine" :)

char tableau[2];
strcpy(tableau, "ab"); // BUG!!!!!!!

car on met trois éléments dans un tableau qui ne peut en contenir que 2.
3 avec le zéro final.....