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 :

demande aide création fonction split


Sujet :

C

  1. #1
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 257
    Par défaut demande aide création fonction split
    Bonjour,

    Je cherche à créer une fonction split.

    Voici mon code actuel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    temp=strtok(chaine,":");
    while (temp!=NULL)
    {
     coupure=strdup(temp);
     temp=strtok(NULL,":");
    }
    Je souhaite ensuite stocker les adresses de coupure dans un tableau comme ceci :

    [tableau 0]=1ère adresse coupure
    [tableau 1]=2éme adresse coupure
    etc ..
    la dernière entrée de tableau devant être NULL.

    c'est là que je bloque.

    Mes essais n'ont pas été fructueux.

    Je dois pas être loin de la solution.

    Merci pour votre aide.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  2. #2
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    la fonction strtok() renvoit NULL s'il n'y a plus d'occurence du délimiteur ou qu'elle rencontre le terminateur de chaine, ça a tendance à nous arranger ici
    d'autre part on va troquer la boucle while(){...} pour une boucle do {...} while().

    on aurait alors quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    do {
       p = strtok(chaine, ":");
       tableau[i++] = p;
    } while (p != NULL)

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Attention à strtok() car elle utilise un pointeur statique pour mémoriser ses étapes (pour pouvoir repartir du même point lors de l'appel suivant). Ca marche jusqu'au moment où on veut l'appeler dans des boucles imbriquées comme par exemple exploiter un PATH avec ses ":" puis exploiter chaque chemin trouvé avec ses dossiers séparé par "/". Et là le truc s'envoie joyeusement en l'air.

    Il vaut mieux lui privilégier strtok_r() à laquelle on passe en 3° paramètre l'adresse d'un pointeur dédié à la sauvegarde de l'état en cours. On peut alors, dans le cas d'appels imbriqués, utiliser différents pointeurs de travail...
    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]

  4. #4
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 257
    Par défaut
    Merci pour vos réponses.
    @sven : dans mon cas pas de prob. strtok ou strtok_r répond à mon besoin.

    Je n'ai pas de soucis avec strtok, je récupère bien toutes les occurrences dans temp et recopiés via dtrdup dans mon pointeur nommé coupure.

    @bufferbob : je vais tester ton bout de code, à vu d'oeil, ça me parait bon.

    je vous tiens au courant.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    Je n'ai pas de soucis avec strtok
    Oui parce que là tu ne l'appeles qu'une seule fois et ta fonction traite toute la boucle strtok() avant de sortir.

    Appelles-là dans cette configuration
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    chemin=strtok(path, ":")
    while (chemin != NULL)
    {
        dossier=strtok(chemin, "/")
        while (dossier != NULL)
        {
            ...
           dossier=strtok(NULL, "/")
        }
        chemin=strtok(NULL, ":")
    }

    Et tu verras comment ton truc partira dans le décors...

    Citation Envoyé par chrtophe Voir le message
    ...et recopiés via strdup dans mon pointeur nommé coupure.
    Pourquoi dupliquer les chaines ? La solution de bufferBob est plus sympa (il stocke les pointeurs de la chaine d'origine et non de nouvelles chaines recopiées).
    Ceci dit, si vraiment c'est utile (modif ultérieure etc) il te faudra bien penser à les libérer en fin de travail...
    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]

  6. #6
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 257
    Par défaut
    oui Sve@r,

    ce que je voulais dire, c'est que je ne suis pas dans cette config, je peux donc utiliser soit l'un soit l'autre. Mais sur le principe tu as raison, il suffit que je change mon code on faisant des imbrications et je devrais remplacer strtok par strtok_r.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  7. #7
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 257
    Par défaut
    Voici le retour de mon essai :

    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
     
    void *split(char *a_spliter,char *spliter)
    {	
    	void *tableau[32];
    	printf("adr tableau : %p\n",tableau);
    	char *p=strtok(a_spliter,spliter);
    	int increment=0;
    	while (p!=NULL)
    	{
    		printf("p : %p %s\n",p,p);
    		char *temp=strdup(p);
    		tableau[increment++]=temp;
    		p=strtok(NULL,spliter);
    	}
    	tableau[increment] = NULL;
    	increment=0;
    	printf("vérification\n");
    	do
    	{
    		printf("%p %s\n",tableau[increment],tableau[increment]);	
    		increment++;		
    	} while (tableau[increment]!=NULL);
    	return *tableau;
    }
    J'ai fixé arbitrairement la taille de tableau à 32.
    la partie en dessous de printf("vérification\n"); est effaçable (mis à part la ligne return)

    Il me reste à gérer la libération de la mémoire (free sur les 32 pointeurs de tableau jusqu'au 1er égal à NULL, libération de l'adresse retourné par l'appelant hors de la fonction).

    Si je veux réserver la taille exacte nécessaire à tableau je pourrais faire un 1er parcours strtok pour compter le nombre de chaines et faire un malloc genre sizeof(void*)*compteur.

    J'ai une dernière question. Je n'arrive pas à exploiter correctement mon pointeur void hors de la fonction, de façon à récuperer les pointeurs contenant les chaines les un derrière les autres (comme dans la partie verif) à partir de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void *adr=split(chaine,":");
    . Je retourne un void, c'est peut-être pas le mieux, j'ai fait cela en prévision d'une éventuelle taille variable de tableau non connue par l'appelant (pas besoin de connaitre la taille du tableau, juste récuperer les pointeurs les uns derrière les autres jusqu'à NULL, un peut comme le contenu de argv ou argp).
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    J'ai une dernière question. Je n'arrive pas à exploiter correctement mon pointeur void hors de la fonction, de façon à récuperer les pointeurs contenant les chaines les un derrière les autres (comme dans la partie verif) à partir de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void *adr=split(chaine,":");
    . Je retourne un void, c'est peut-être pas le mieux, j'ai fait cela en prévision d'une éventuelle taille variable de tableau non connue par l'appelant (pas besoin de connaitre la taille du tableau, juste récuperer les pointeurs les uns derrière les autres jusqu'à NULL, un peut comme le contenu de argv ou argp).
    Ce ne sera pas la dernière question je le crains car ton code ne peut pas fonctionner. En effet, tu renvoies un tableau local donc perdu quand la fonction se termine.
    Tu ne peux renvoyer que l'adresse d'un truc soit déjà existant (arrivé depuis l'appelant), soit d'un truc alloué (via malloc) mais en aucun cas l'adresse d'un truc local à la fonction.

    Sinon pourquoi tu stockes tes différents pointeurs (des pointeurs sur des caractères donc des "char*") dans des "void*" ??? Le fait d'utiliser "void*" n'est pas là pour gérer des tableaux de taille variable mais pour gérer des tableaux d'objets non connus à l'avance. Ce n'est pas tout à fait la même chose !!!

    Donc tu dois stocker différents char* dans un tableau donc un char *tab[]. Mais comme ton tableau doit-être alloué dynamiquement, cela devient alors un char **tab.

    Voici ta fonction corrigée (et testée)

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char **split(char *a_spliter,char *spliter)
    {
    	char **tableau;
    	tableau=malloc(32 * sizeof(char*));
    	int increment=0;
    	char *p=strtok(a_spliter,spliter);
    	while (p!=NULL && increment < 32)
    	{
    		tableau[increment++]=strdup(p);
    		p=strtok(NULL,spliter);
    	}
    	tableau[increment]=NULL;
    	return tableau;
    } 
     
    int main()
    {
    	char **pt;
    	char **res;
    	res=split(getenv("PATH"), ":");
    	for (pt=res; *pt != NULL; pt++)
    	{
    		printf("pt=%s\n", *pt);
    		free(*pt);
    	}
    	free(res);
    }

    Ensuite, pour supprimer cet arbitraire "32", tu pourras soit
    • compter combien t'as besoin d'éléments puis de nouveau traiter et exploiter ta chaine
    • utiliser un malloc initial puis faire du realloc pour agrandir ton tableau chaque fois que celui-ci atteint sa limite allouée

    ...
    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]

  9. #9
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 257
    Par défaut
    Merci Sve@r,

    c'est les ** qui me manquaient.

    Sinon pourquoi tu stockes tes différents pointeurs (des pointeurs sur des caractères donc des "char*") dans des "void*" ???
    L'utilisation de void est simplement venu de tentatives infructueuses.

    JE ne suis pas programmeur de métier, je me débrouille (plus ou moins bien). J'ai intégré correctement la notion de pointeur, mais les doubles pointeurs (même pas sûr du nom), c'est autre chose.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  10. #10
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    JE ne suis pas programmeur de métier, je me débrouille (plus ou moins bien). J'ai intégré correctement la notion de pointeur, mais les doubles pointeurs (même pas sûr du nom), c'est autre chose.
    Pour faire simple: un pointeur sur "truc" signifie qu'à cette adresse, tu auras un "truc" et s'écrit truc *. Et le contenu de "truc" peut être de n'importe quel type y compris un pointeur (donc contenant lui-même une étoile dans sa définition).

    Donc avec un char *pt, cela veut dire qu'à l'adresse placée dans "pt" tu as un char. Peut-être toutefois qu'à l'adresse située juste après, tu as aussi un char. Et encore à l'adresse située encore après. Si vraiment c'est le cas parce que c'est toi qui a fait en sorte que ce soit comme cela, alors ça veut dire que "pt" est le point de départ d'un tableau et que dans ce cas, t'as le droit de l'utiliser comme un tableau (d'où l'amalgame comme quoi pointeur=tableau).

    De la même façon, avec un char **pt, cela veut dire qu'à l'adresse placée dans "pt" tu as un char* (donc une adresse). La signification de cette adresse peut-être multiple et peut-même correspondre elle-même au point de départ d'un tableau. Et comme "pt" peut lui-aussi être le point de départ d'un tableau, voilà comment on obtient un tableau de tableaux autrement dit une matrice (ou un tableau 2D).

    Et de même on peut monter le nombre d'étoiles augmentant d'autant la dimension des tableaux gérés (mais j'ai jamais vu au delà de 3).

    Dans mon/ton cas, on se contente juste de mémoriser différentes adresses, chacune étant donnée par strdup(). Comme ce sont des adresses sur des char (donc des char*), on doit alors les mémoriser dans un char **.
    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]

  11. #11
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 257
    Par défaut
    Très bonne explication,

    Je pense que c'est clair maintenant.

    la notion de 3 étoiles je savais pas que ça existait. Je présume que c'est un peu comme un ajout de dimension à un tableau.

    Merci encore.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

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

Discussions similaires

  1. Aide création fonction avec sqsh
    Par skull75 dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 19/07/2012, 10h21
  2. Demande aide (debutant) => Fonctions
    Par Invité dans le forum C
    Réponses: 5
    Dernier message: 15/11/2009, 20h12
  3. besoin d'aide pour fonction split
    Par remitbo dans le forum Langage SQL
    Réponses: 1
    Dernier message: 05/06/2009, 12h45
  4. [JS] Aide création Fonction
    Par Pahcixam dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 20/02/2007, 18h40

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