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 :

Fonction et tableau de strings


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20
    Par défaut Fonction et tableau de strings
    Bonjour à tous,

    Une première pour moi dans ce forum - même si d'autres sujets sur le site m'ont déjà inspirés sur developpez.net : je débute en C et plus particulièrement sur Arduino !
    Oui, je sais, peut être aurait il fallu que j'écrive dans le forum Arduino, mais ma question relève plus du C que d'Arduino en lui même

    Mon problème est le suivant :

    J'ai une fonction "test" qui doit me renvoyer un chiffre puis plusieurs chaines de caractères vers la fonction main(). J'ai donc écrit ce morceau de code mais au final, je n'arrive pas à retrouver les valeurs quand je tente de les ressortir dans main().
    J'ai beau chercher un peu partout sur les moteurs de recherche, mais mes connaissances en C et encore plus sur les pointeurs & la mémoire système, sont très limités.
    Il me semblait avoir compris que pour retrouver la valeur dans un pointeur, il suffisait de mettre "&" devant le pointeur... Ici ça semble ne pas fonctionner

    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
     
    #include <stdio.h>
    #include <stdlib.h>
    int *test(){
        char *p;
        p = malloc(4*sizeof(char));
        p[0] = 3;
        p[1] = "Bonjour";
        p[2] = "moi";
        p[3] = "toi";
        return p;
    }
    int main(){
        char *tab;
        int i;
        tab = malloc(4*sizeof(char));
        tab = test();
        for(i=0;i<4;i++) {
            printf("%d\n",&tab[i]);
        }
        free(tab);
        return 0;
    }
    A noter que la première valeur est un int ("3" que j'ai inclus dans le tableau char... bof, bof...) puis les autres phrases sont bien des Strings.

    Une idée (je suppose que oui !) sur ce qui ne va pas sur mon code ??? Comment puis-je retrouver mes valeurs initiales ?

    Merci à tous,


    Thierry

  2. #2
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Une idée ? Oui.. plusieurs. Il y a des erreurs quasiment à chaque ligne. Dans l'ordre du flux d'exécution :

    • tu alloues une première fois ton buffer dans main, puis tu écrases l'adresse obtenue avec celle retournée par test : qui est responsable de la gestion mémoire ? L'appelé (test) ou l'appelant (main), mais pas les deux ;
    • test ne retourne pas le bon type de pointeur (ça peut se faire, mais ici c'est une erreur) ;
    • tu mélanges nativement des éléments de types différents au sein d'un même tableau ;
    • si tu interprêtes les éléments de p comme des char (un seul caractère), tu ne peux pas y stocker des chaînes de caractères ;
    • tu ne peux pas affecter / copier des chaînes dans ce contexte en utilisant l'opérateur = ;
    • le spécificateur de format passé à printf n'est pas le bon ;
    • tu confonds l'opérateur unaire d'indirection & et son inverse, l'opérateur unaire de déréférencement * ;
    • j'en ai peut-être oublié.


    Commente tout ton programme, puis réintègre chaque ligne une par une. Tu dois comprendre tout ce que tu fais. Si tu as un doute, nous t'aiderons.

    Active tous les warnings de ton compilateur (options -pedantic -Wall -Wextra pour GCC) puis traque-les tous. Ne t'arrête pas tant qu'il en reste : ce n'est pas parce que ça compile que l'exécutable obtenu a un comportement correct.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20
    Par défaut
    Merci pour la réponse...
    L’environnement Arduino n'étant pas TOP pour faire du debug, j'ai installé CodeBlock pour tester mes routines.

    J'ai repris début le début en refaisant un nouveau programme simple pour comprendre, mais j'ai quelques erreur et le résultat final n'est... tout à fait cela !
    Seule le 1er champ du tableau est correctement retrouvé dans main(); les autres affichent n'importe quoi... et je suppose qu'il doit falloir indiquer une taille quelque part, mais là, j'avoue que je pêche et les erreurs du "return" de la fonction test(), je ne comprend pas pourquoi il y a des warnings ???

    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int test(){
     
        char *variable[4];          // Déclaration du pointeur "variable" avec 4 champs possible
        variable[0] = "3";          // Définition des données "string" dans chaque ligne de la "variable"
        variable[1] = "Bonjour";
        variable[2] = "moi";
        variable[3] = "toi";
     
        return &variable;           // Je renvoie l'adresse du pointeur mais GCC renvoie "warning: function returns address of local variable [enabled by default]" et "warning: return makes integer from pointer without a cast [enabled by default]"
    }
     
    int main(){
     
        int *AdrTableau = test();   // on récpère l'adresse du pointeur renvoyé par la fonction test()
        int i;                       // Init de la variable temporaire et locale
        for(i=0; i<4; i++) {        // Boucle pour lister tous les champs
            // %d: affiche l'int "i"; %s: affiche le string char*
            printf("%d : %s\n", i, AdrTableau[i] );
        }
     
        return 0;
    }

    Que pensez vous de ce code ?

  4. #4
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 17
    Par défaut
    J'ai trois erreurs lorsque je compile avec les flags que Matt_Houston t'a conseillé :

    ligne 12 => error: incompatible pointer to integer conversion returning 'char *(*)[4]' from a function with result type 'int' [-Werror,-Wint-conversion]
    ligne 17 => error: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Werror,-Wint-conversion]

    ligne 21 => error: format specifies type 'char *' but the argument has type 'int' [-Werror,-Wformat]


    Les comprendre t'aidera vraiment à corriger tes erreurs.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20
    Par défaut
    Citation Envoyé par Personne.c Voir le message
    Les comprendre t'aidera vraiment à corriger tes erreurs.
    Le problème, c'est que je ne comprend pas pourquoi...
    Tout me semble "logique"... Mais j'ai du louper quelque chose !
    Avez vous une piste à me conseiller sur "chaque" problème ? Je pensais pourtant comprendre ces histoires de pointeur, mais visiblement...

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 818
    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 818
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par azimut2000 Voir le message
    J'ai repris début le début en refaisant un nouveau programme simple pour comprendre, mais j'ai quelques erreur et le résultat final n'est... tout à fait cela !
    Seule le 1er champ du tableau est correctement retrouvé dans main(); les autres affichent n'importe quoi... et je suppose qu'il doit falloir indiquer une taille quelque part, mais là, j'avoue que je pêche et les erreurs du "return" de la fonction test(), je ne comprend pas pourquoi il y a des warnings ???

    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
    #include <stdio.h>
    #include <stdlib.h>
     
    int test(){
     
        char *variable[4];          // Déclaration du pointeur "variable" avec 4 champs possible
        variable[0] = "3";          // Définition des données "string" dans chaque ligne de la "variable"
        variable[1] = "Bonjour";
        variable[2] = "moi";
        variable[3] = "toi";
     
        return &variable;           // Je renvoie l'adresse du pointeur mais GCC renvoie "warning: function returns address of local variable [enabled by default]" et "warning: return makes integer from pointer without a cast [enabled by default]"
    }
     
    int main(){
     
        int *AdrTableau = test();   // on récpère l'adresse du pointeur renvoyé par la fonction test()
        int i;                       // Init de la variable temporaire et locale
        for(i=0; i<4; i++) {        // Boucle pour lister tous les champs
            // %d: affiche l'int "i"; %s: affiche le string char*
            printf("%d : %s\n", i, AdrTableau[i] );
        }
     
        return 0;
    }
    Le problème, c'est que je ne comprend pas pourquoi...
    Tout me semble "logique"... Mais j'ai du louper quelque chose !
    Avez vous une piste à me conseiller sur "chaque" problème ? Je pensais pourtant comprendre ces histoires de pointeur, mais visiblement...
    Bonjour

    Le souci de ton code est que ta fonction "test()" renvoie l'adresse d'une variable locale, donc variable détruite quand on quitte la fonction. Et donc dans ton main() tu reçois une adresse ne correspondant à plus rien de concret.

    Si une fonction doit renvoyer une adresse, elle doit renvoyer une adresse persistante. Or il n'y a que 2 façons de créer une adresse persistante: en utilisant un type "static" ou l'allouer via malloc/calloc/realloc
    Le type static peut sembler pratique à priori mais a l'inconvénient de rendre ta fonction non réentrante (si la fonction est appelée deux fois, le second appel écrase le premier). Le malloc est plus sympa mais tu es alors responsable du pointeur que tu récupères et c'est donc à toi de le libérer. Et si tu appelles ta fonction deux fois ben, tu dois alors gérer deux retours.

    Autre détail: bien qu'une adresse soit un nombre entier, ce n'est pas un "int". Si ta fonction doit renvoyer une adresse, elle doit alors être du type "pointeur".
    Ce n'est pas un souci d'incompatibilité, c'est un souci "d'information". Quand tu écris int var=123; int *pt=&var tu informes le compilo que *pt (ce qu'il y a à l'adresse "pt") est un entier. Si ensuite tu demandes printf("%d", *pt) le compilo connaissant la nature de *pt saura le manipuler (récupérer 4 octets à partir de l'adresse pt (pas d'étoile puisque je parle ici du pointeur "pt") et convertir ces 4 octets en nombre).
    Si en revanche tu écris int var=123; int pt=&var, ce n'est pas faux en soi (au plus bas niveau tout est du nombre) mais ensuite quand tu demandes printf("%d", *pt) le compilo ne connaissant pas la nature *pt ne sait pas quoi faire de cette adresse.

    Tout ça pour dire que ta fonction ne peut pas être de type "int".

    Maintenant, pour corriger ton exemple, il suffit de réfléchir. Tu veux créer une fonction qui va stocker 4 strings. Une string étant manipulable par son pointeur de début, on a l'habitude de dire "string=pointeur". Ce n'est pas rigoureusement exact mais c'est une analogie qui peut aider à comprendre.
    Donc tu vas devoir créer un tableau permettant de stocker 4 char *. Un tableau de "<truc>" s'allouant dans un <truc> *, tu alloueras ces 4 char * dans un char **.

    Ce qui donne:
    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <stdio.h>
    #include <stdlib.h>
     
    char **test(){
    	char **variable;		// Déclaration d'un pointeur double
     
    	variable=malloc(4 * sizeof(char *));
    							// Allocation d'une zone permettant de stocker 4 pointeurs simples
     
    	// Remplissage des 4 pointeurs avec 4 adresses
    	variable[0] = "3";		
    	variable[1] = "Bonjour";
    	variable[2] = "moi";
    	variable[3] = "toi";
     
    	return variable;		// Renvoi du pointeur alloué
    }
     
    int main(){
     
    	char **AdrTableau = test();
    	int i;
    	for(i=0; i<4; i++) {
    		printf("%d : %s\n", i, AdrTableau[i] );
    	}
    	free(AdrTableau);
    	return 0;
    }

    Ne te méprends pas. Quand tu écris var="Bonjour" il ne s'agit pas d'une copie de chaine mais d'adresse. Tu ne fais que récupérer l'adresse de la chaine "Bonjour" (située en dur dans ton code) dans la variable var.

    Donc ce code récupère un tableau contenant 4 chaines statiques (non modifiables). Si tu veux changer le code pour récuperer des chaines "modifiable" il te faut alors les recopier depuis les chaines statiques en ayant pris soin auparavant de réserver l'espace pour ces chaines. Ce qui donnera

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char **test(){
    	char **variable;		// Déclaration d'un pointeur double
     
    	variable=malloc(4 * sizeof(char *));
    							// Allocation d'une zone permettant de stocker 4 pointeurs simples
     
    	// Remplissage des 4 pointeurs avec 4 chaines
    	variable[0] = malloc(strlen("3") + 1);	// Ne pas oublier d'allouer l'espace pour le '\0' => La chaine "3" a une taille de "1" mais contient 2 caractères
    	strcpy(variable[0], "3");
    	variable[1] = malloc(strlen("Bonjour") + 1);
    	strcpy(variable[1], "Bonjour");
    	variable[2] = malloc(strlen("moi") + 1);
    	strcpy(variable[2], "moi");
    	variable[3] = malloc(strlen("toi") + 1);
    	strcpy(variable[3], "toi");
     
    	return variable;		// Renvoi du pointeur alloué
    }
     
    int main(){
     
    	char **AdrTableau = test();
    	int i;
    	for(i=0; i<4; i++) {
    		printf("%d : %s\n", i, AdrTableau[i] );
    	}
    	for(i=0; i<4; i++)
    		free(AdrTableau[i]);
    	free(AdrTableau);
     
    	return 0;
    }

    Et tu ne dois pas oublier de libérer la mémoire allouée dans l'ordre inverse de son allocation...

    Citation Envoyé par azimut2000 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        tab = malloc(4*sizeof(char));
        tab = test();
    Sans avoir aucune connaissance ni en C, ni avec les pointeurs, ni même en programmation ; juste avec seulement un peu d'intuition on devrait tiquer sur ces deux lignes qui remplissent deux fois la même variable avec deux éléments différents. D'ailleurs de façon plus générale, on devrait tiquer chaque fois
    • qu'on remplit deux fois une même variable sans l'avoir traitée entre temps
    • qu'on traite une variable sans l'avoir remplie auparavant



    Citation Envoyé par azimut2000 Voir le message
    A noter que la première valeur est un int ("3" que j'ai inclus dans le tableau char... bof, bof...) puis les autres phrases sont bien des Strings.
    Parce tu penses qu'il y a une différence fondamentale entre "3" (une suite de "n" caractère ascii entre quotes) et "Bonjour" (une suite de "n" caractères ascii entre quotes) ? Ou que le C est assez intelligent pour "comprendre" que puisque l'ensemble de caractères représente un nombre il doit alors transformer cette suite en nombre ???
    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]

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 394
    Par défaut
    Le gros problème ici, c'est function returns address of local variable.
    Il ne faut pas oublier que les tableaux "statiques" sont passés et retournés par adresse et non pas par valeur (il en serait différemment si le tableau était dans une structure).
    Résultat, tu retournes l'adresse d'une variable qui n'existe plus une fois que la fonction retourne!

    Les seuls moyens que je connaisse pour retourner un nouveau tableau d'une fonction, sont l'allocation dynamique et le fait de mettre le tableau dans une structure.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20
    Par défaut
    Ahhhhh... yes !
    Merci à tous pour vos réponses ! et surtout à Sve@r qui m'a bien ouvert les yeux sur un truc que je n'avais pas (bien) compris au final ;-)

    Par contre le coup du pointeur de pointeur (pointeur double) sur la fonction test() et sur la variable "variable", j'en étais pas encore là et j'avoue que je n'y pensais pas :-(

    Autant faire un malloc sur chaque chaine et y copier le contenu souhaité, c'est OK pour moi, tout comme "variable=malloc(4 * sizeof(char *))" et définir correctement la fonction test() non par un "int" mais par un "char" , mais ce qui m'échappe c'est pourquoi on est obligé de faire un pointeur double sur la variable "variable" ??? C'est à cause du fait qu'il faut donner un pointeur qui indique l'adresse du pointeur de la variable "variable" ?

    Mais alors pourquoi mettre aussi un double pointeur sur la fonction test() ?







    (oui, je sais, je suis nul mais je commence de très loin ! et à mon age... les neurones ne fonctionnent plus aussi vite qu'il y a 40 ans )

  9. #9
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 394
    Par défaut
    Si ton tableau ne contient que des chaînes littérales que tu ne comptes pas modifier, alors plutôt que faire un malloc() de chaque chaîne, tu peux tout simplement le déclarer comme const char ** (tableau de chaînes constantes).

    Le pointeur est double parce que tu travailles ici sur un tableau de pointeurs; ou plus précisément, un pointeur sur le premier élément d'un tableau de pointeurs (eux-mêmes pointant chacun sur le premier caractère d'une chaîne).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Je rebondis sur un point : le fait que ton programme soit fait pour Arduino.

    1) Arduino te permet de faire du C++, donc je préfèrerais utiliser new et delete plutôt que malloc et free. De plus, je pense que des std::string du C++ serait bien comparées à des char* venus du C.
    2) On évite souvent autant que possible de faire de l'allocation dynamique sur MCU car on a un tas souvent très petit et on risque vite de le fragmenter et de ne plus réussir à allouer. Je ne dis pas de ne pas faire d'allocation dynamique, je dis d'être très vigilent à ce sujet.

    Que souhaites-tu faire de manière plus globale, au-delà de cette petite fonction de test ?

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 818
    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 818
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par azimut2000 Voir le message
    Autant faire un malloc sur chaque chaine et y copier le contenu souhaité
    Pas forcément. Ca se fait plutôt au cas par cas. Perso je pencherais plutôt sur le premier exemple (généralement quand on stocke des strings ce n'est pas pour les modifier ensuite).
    Surtout qu'en programmation opérationnelle tu dois aussi vérifier chaque malloc et prévoir un traitement de dérivation si un seul malloc échoue.

    Autre possibilité: tu peux aussi te dire "chaque chaine ne dépassera pas 200 caractères" et alors allouer un tableau de "n * char[200]" avant d'y mettre tes chaines. Ca peut-être aussi un bon compromis (pas de malloc à répétition à devoir gérer mais réservation d'un espace peut-être inutile).

    Citation Envoyé par azimut2000 Voir le message
    c'est OK pour moi, tout comme "variable=malloc(4 * sizeof(char *))" et définir correctement la fonction test() non par un "int" mais par un "char étoile" , mais ce qui m'échappe c'est pourquoi on est obligé de faire un pointeur double sur la variable "variable" ??? C'est à cause du fait qu'il faut donner un pointeur qui indique l'adresse du pointeur de la variable "variable" ?
    Exactement. Chaque fois que tu veux allouer de l'espace pour stocker des truc, tu récupèreras un pointeur de type truc étoile. Si tu alloues de l'espace pour des double tu récupèreras un pointeur double *. Si tu alloues de l'espace pour des long tu récupèreras un pointeur long *. Et si tu alloues de l'espace pour des strings (donc des char*) tu récupères de la même façon un pointeur de type char* *.

    Citation Envoyé par azimut2000 Voir le message
    Mais alors pourquoi mettre aussi un double pointeur sur la fonction test() ?
    Parce qu'une fonction doit toujours être du type de ce qu'elle renvoie. Elle renvoie un char étoile étoile elle est donc du type char étoile étoile ; là encore pour des questions de communication (l'appelant connait le type de la fonction donc par transitivité le type du truc qu'elle renvoie ; il sait donc comment l'utiliser).
    <disgression>Elle peut aussi être du type void étoile (pointeur universel). En effet, quand je dis "toujours du type" je m'arrête juste au type "pointeur". Un "char étoile étoile" c'est un pointeur, un "void étoile" c'est un pointeur aussi donc ça marche (et ça marche d'autant mieux que c'est justement un pointeur "fourre-tout" permettant d'unifier une fonction qui devrait renvoyer (selon le cas) plusieurs pointeurs de type différent). Mais après ça oblige à l'appelant à indiquer comment il se sert de ce qu'il a récupéré chaque fois qu'il veut l'utiliser. Ca se fait parfois dans des cas particuliers (comme par exemple les fonctions de socket qui sont adaptables à la fois aux sockets réseaux et à la fois aux sockets fichier) mais bon, pour ici ça reste inutile. </disgression>
    Donc mis à part cette disgression, une fonction est toujours du type de ce qu'elle renvoie.
    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]

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Que souhaites-tu faire de manière plus globale, au-delà de cette petite fonction de test ?
    En fait, j'ai un très long programme qui tourne dans la fonction setup() d'un de mes programmes et je voulais "découper" pour distinguer un peu plus les différentes étapes du programme... sauf que je me suis butté ce ce problème.

    Je sais qu'on peut faire du C++ sur Arduino, mais comme je suis en phase d'apprentissage, je voulais commencer par apprendre le C puis passer au C++... Bonne méthode ??? je ne sais pas...

  13. #13
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    J'en déduis que le programme fonctionne déjà donc ça va

    Bonne méthode je ne sais pas... Le C++ moderne peut-être très éloigné du C, surtout en terme de façon de penser le code. Ce que tu apprendras du C te servira en grande partie pour faire du C++ mais ce n'est pas nécessaire de faire du C d'abord. C'est simplement que les premiers chapitres d'un bouquin sur le C ressemblent souvent à ceux d'un bouquin sur le C++.

  14. #14
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Recommander le C++ à qui que ce soit, c'est déjà pas terrible. Recommander le C++ comme premier langage, ça me dépasse. Mais alors recommander le C++ à l'auteur des programmes listés dans ce thread, on franchit une frontière interdimensionnelle.

    À l'OP : avec un peu de rigueur la compréhension viendra vite, par la relecture des cours et de la doc et surtout de la pratique. Il faut juste que tu te focalises sur une étape à la fois : appel de fonction simple, puis gestion d'une zone mémoire dynamique, puis copie de chaîne, etc.. Chaque chose en son temps. Comme je l'ai écrit tu dois comprendre l'effet de chaque expression, chaque ligne de ton programme sur son comportement.

  15. #15
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 818
    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 818
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    Recommander le C++ à qui que ce soit, c'est déjà pas terrible. Recommander le C++ comme premier langage, ça me dépasse. Mais alors recommander le C++ à l'auteur des programmes listés dans ce thread, on franchit une frontière interdimensionnelle.
    Mouais. C'est un avis comme un autre mais personnellement je ne vois pas trop pourquoi. Le C++ est un langage comme un autre, il a le droit d'être appris comme les autres y compris en tant que "premier langage" ; et je n'ai rien vu chez le PO qui le disqualifierait pour y avoir droit (il lit, il cherche, il essaye, il tatonne et bien entendu il fait des erreurs mais c'est le cas de tout le monde pour tout apprentissage quel qu'il soit donc ce dernier point ne compte pas). "++" ne signifie pas "plus difficile à apprendre"...

    Citation Envoyé par Matt_Houston Voir le message
    À l'OP : avec un peu de rigueur la compréhension viendra vite, par la relecture des cours et de la doc et surtout de la pratique.
    Ben justement, ce conseil marche aussi dans le cadre de l'apprentissage du C++...
    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]

  16. #16
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    D'accord.

    Puisque t'as le temps de troller, explique à l'OP qui a du mal à copier trois strings et un int comment pécho à coup sûr aux conventions Arduino en écrivant son programme en C++ générique et memory safe à base de std::variant et rvalue references. N'oublie pas les decltype.

    Ah, par contre fais-le ailleurs que sur le forum C. Bisous !

Discussions similaires

  1. Réponses: 4
    Dernier message: 21/04/2007, 20h02
  2. [J2SE] tableau de string
    Par Jules82 dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 17/03/2005, 14h35
  3. Ranger un tableau de String dans ma HashMap
    Par jeyce dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 26/08/2004, 22h41
  4. [Collections] Conversion de Vector en tableau de String
    Par java_math dans le forum Collection et Stream
    Réponses: 5
    Dernier message: 06/06/2004, 12h55
  5. [Collections] Tableau de String
    Par gexti dans le forum Collection et Stream
    Réponses: 11
    Dernier message: 02/06/2004, 15h42

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