IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Renvoi de pointeur depuis une fonction


Sujet :

C

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 198
    Points : 37
    Points
    37
    Par défaut Renvoi de pointeur depuis une fonction
    Bonjour ,
    Dans ce code , il a certaines choses que je ne comprends pas .

    1 er ) Je pensais que l'ecriture du prototype de la fonction devait etre rigoureusement le meme que celui de la fonction apres le main . Ici nous avons dabord : char *strinverser(char *input);
    puis la fonction elle meme : char *strinverser(char *entrante)

    2 eme) puts(strinverser(machaine)); Pour moi ici , on a l'appel de la fonction qui envoie le tableau "ma chaine " et apres inversion de la chaine , le retour de la fonction se fait dans la fonction puts . C'est ca ?

    3eme) Pourquoi apres la 1ere ligne de la 1 ere boucle while , il y a un " ; " ?

    Derniere question : L'utilisation des pointeurs n'est pas encore super clair pour moi . Que nous apporte de plus l'utilisation de pointeur dans cet exemple ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include <stdio.h>
    char *strinverser(char *imput);
     
    int main()
    {
     char machaine[64];
     
     printf("Saisissez du texte :");
     fgets(machaine,62,stdin);
     puts(strinverser(machaine));
     return 0;
    }
    char *strinverser(char *entrante)
    {
     static char sortante[64];
     char *i,*o;
     i=entrante; o=sortante;
     
     while(*i++ != '\n')
       ;
     i--;
     
     while(i>=entrante)
      *o++=*i--;
     *o='\0';
     return(sortante);
    }

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par chris7522 Voir le message
    1 er ) Je pensais que l'ecriture du prototype de la fonction devait etre rigoureusement le meme que celui de la fonction apres le main . Ici nous avons dabord : char *strinverser(char *input);
    puis la fonction elle meme : char *strinverser(char *entrante)
    La signature doit être la même. Et la signature c'est juste le type de la fonction et le type de ses paramètres. Donc le nom des paramètres n'a pas d'importance. Il n'en a tellement pas que généralement on ne les met même pas dans le prototype => char *strinverser(char*);
    Citation Envoyé par chris7522 Voir le message
    2 eme) puts(strinverser(machaine)); Pour moi ici , on a l'appel de la fonction qui envoie le tableau "ma chaine " et apres inversion de la chaine , le retour de la fonction se fait dans la fonction puts . C'est ca ?
    Exact. C'est le principe général de la notion "d'expression" en C qui est la base de l'analyse lexicale d'un compilateur et qui peut-être
    • une constante => 5
    • une opération utilisant des expressions => 5 + 6 (tu remarqueras la présence de la notion d'expression qui permet ainsi au truc de se retrouver inclus dans lui-même)
    • une fonction utilisant des expressions => f(5); g(5+6); h(f(5) + g(5+6) * 2) / 3.0

    Donc ici tu affiches à l'écran le résultat de inverse().
    C'est exactement comme en math quand tu écris y=f(g(x)) => calcul de g(x) et résultat utilisé comme paramètre de f().

    Un détail à retenir toutefois: si une fonction attend 2 (ou plus) paramètres, (ex void fct(int, int);) tu as parfaitement le droit de lui passer 2 fonctions en entrée si ces fonctions sont du bon type (ex fct(carre(5), cube(6)) en admettant que "carre()" et "cube()" soient int) mais tu ne peux absolument pas prédire laquelle sera appelée avant laquelle. C'est un effet de l'empilement des paramètres qui n'est pas réglementé. Donc si "carre()" et "cube()" sont indépendantes pas de souci mais si l'une dépend du travail de l'autre (ex "cube()" va utiliser un truc calculé par "carre()") alors tu dois assurer l'ordre des appels toi-même (en utilisant donc des variables qui récupèrent les résultats puis tu envoies ces variables à "fct()").
    Et surtout ne parlons pas du résultat absolument catastrophique de ce genre d'appel: fct(i++, i++)...

    Citation Envoyé par chris7522 Voir le message
    3eme) Pourquoi apres la 1ere ligne de la 1 ere boucle while , il y a un " ; " ?
    Ca c'est plus élémentaire et tu ne devrais pas poser la question. Le while se suffit à lui-même pour faire le travail (positionner "i" sur le caractère valant '\n' ) donc la boucle n'invoque aucune instruction. Mais pour l'analyseur syntaxique il faut une instruction obligatoire. Donc on y met une instruction vide. Il est même d'ailleurs assez courant d'écrire plus simplement while(...);.

    Citation Envoyé par chris7522 Voir le message
    Derniere question : L'utilisation des pointeurs n'est pas encore super clair pour moi . Que nous apporte de plus l'utilisation de pointeur dans cet exemple ?
    Déjà à te familiariser avec la notion de pointeur permettant de te positionner à divers endroit d'une zone mémoire. Mais c'est vrai que lire *o++=*i--; n'est pas chose aisée (et le pire c'est que cette habitude vient des premiers temps du C où on pensait qu'écrire en super condensé ferait aller le truc super vite alors qu'en réalité, le compilateur traduit la même chose qu'on écrive ça en une instruction ou en 3 (*o=*i; o++; i--).

    Toutefois un pointeur placé à la bonne position évite au compilo de recalculer cette position, ce qui se produit chaque fois que tu utilises un indice (ce que j'ai détaillé ici).

    Accessoirement c'est bien d'avoir pensé à protéger l'espace utile avec fgets() (passer 62 pour une taille possible de 64). Toutefois le trop est l'ennemi du bien (il faut juste un espace pour stocker le '\0' donc 63 aurait suffit). Et si tu avais lu la doc de fgets(), tu aurais vu qu'elle se charge elle-même de réserver un espace pour le '\0' (tu lui passes N elle stockes N-1) donc char machaine[64]; fgets(machaine, 64, stdin);.

    Sinon petit test amusant qui te fera prendre conscience du danger des variables statiques: remplace puts(strinverser(machaine)); par puts(strinverser(strinverser(machaine)));...

    [edit]
    Pour en revenir au code lui-même (je présume que tu le tires d'un exemple de tuto) perso je le trouve assez catastrophique (en dehors du static mentionné plus haut qui reste en réalité un souci mineur).
    En effet, pour positionner le "i" à la bonne place il part du principe que la chaine contient un '\n'. Or ce n'est pas garanti (si la saisie dépasse 64, fgets() tronque et donc il n'y a pas de '\n' dans la chaine stockée).
    Ensuite une fonction doit se voir comme indépendante de l'extérieur. Une fonction qui va inverser une chaine ne doit se préoccuper que de la chaine et pas de la façon dont elle a été créée. Autrement dit, la fonction strinverse() ne doit pas utiliser le '\n' pour se caler parce qu'en faisant ainsi, tu la limites dans son utilisation (par exemple tu ne peux pas appeler puts(strinverse("Hello"))).

    Voici un exemple de ce qui aurait pu être écrit à la place...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    char *strinverser(char *entrante) {
    	static char sortante[64];
    	char *i,*o;
    	i=entrante; o=sortante;
     
    	while (*i) i++;
    	i--;
     
    	while (i>=entrante) {
    		*o=*i;
    		o++;
    		i--;
    	}
    	*o='\0';
    	return(sortante);
    }
    Ca produit le même résultat mais là, tu peux appeler en plus puts(strinverse("Hello"))...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 198
    Points : 37
    Points
    37
    Par défaut
    Merci beaucoup pour toutes ces explications , je n'ai pas encore le niveau pour comprendre parfaitement tout ce qui a été dit ,mais j'ai compris l'essentiel . Ca viendra en temps voulu , pas de précipitation . Ce code est tiré du livre que j'étudie en ce moment " Apprendre a programmer en C pour les nuls "(2014). J'ai téléchargé vos cours ( C) sur votre site , il me tarde de commencer la lecture .

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Ces 2 codes sont équivalents :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while (truc)
        ;
     
    // et 
    while (truc) {
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 19/12/2014, 17h03
  2. Utilité d'un pointeur vers une fonction ?
    Par Nasky dans le forum C
    Réponses: 10
    Dernier message: 20/03/2010, 19h54
  3. Ecrire dans un tableau html depuis une fonction js ?
    Par botanica dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 05/10/2005, 12h48
  4. Probleme de pointeur sur une fonction
    Par nicky78 dans le forum C
    Réponses: 2
    Dernier message: 23/05/2004, 20h26
  5. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo