Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 2006
-
17 août 2005 à 22:52
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 2006
-
26 mars 2012 à 21:01
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 20062 26 mars 2012 à 20:26
du code d'il y a 7 ans ? en C ? j'étais un aventurier.
Non testé ? je ne pense pas. Peut être pas tous les cas mais bon.
Quelles sont les données en entrées qui font planter ?
trigertrouper31
Messages postés5Date d'inscriptionmercredi 18 juillet 2007StatutMembreDernière intervention 9 mars 2012 9 mars 2012 à 15:48
Bonjour,
Alors quand on met du code source on balance pas du code sans l'avoir testé avant "Hylvenir" >:-(
Au final ton code marche pas des segfault à la volé j'ai pas envie de debuguer
Le mec a peux être fait du code pas propre à cause de la dé-allocation abusive mais sa marche!
cs_goth
Messages postés82Date d'inscriptionlundi 23 décembre 2002StatutMembreDernière intervention23 août 2005 18 sept. 2006 à 23:27
lol,ca t'a dit quelque les fonction pour manipuler les chaines en C?
Essaie man 3 strcmp dans google
oliver7
Messages postés102Date d'inscriptiondimanche 3 octobre 2004StatutMembreDernière intervention 8 septembre 2006 16 sept. 2006 à 19:49
slt
J'essay d'utiliser ton code mais j'ai un petit souci.
Mon code :
char** tableau;
tableau = split("TESTE;rien",";",0);
if (tableau[0] == "TESTE")
{
printf("%s",tableau[0]);
} else {
printf("1er tableau n'est pas teste0");
}
Mon probleme est qu'il fait toujours le else, pourquoi ?
kazoumoulox
Messages postés14Date d'inscriptionmercredi 5 avril 2006StatutMembreDernière intervention 5 juin 2006 10 avril 2006 à 10:10
re re salut..bon en fait g capté le pb!! trop nul moi en C...en fait j'affichais pas le bon truc,... un %c au lieu d'un %s dans le printf, du coup me fesait envoyer paitre...alors dsl pour toutes ces questions inutiles...
mais je rajoute que l'explode marche nikel!!! merci les coupains!
kazoumoulox
Messages postés14Date d'inscriptionmercredi 5 avril 2006StatutMembreDernière intervention 5 juin 2006 10 avril 2006 à 09:33
suite du message précédent : apparemment ya un ptit probleme, en fait je ne peux pas accéder a tab[i], au i eme element de la chaine créée, est ce que ca vient de mon strcpy que je fais pour copier le buffer dans la chaine ou autre chose???
kazoumoulox
Messages postés14Date d'inscriptionmercredi 5 avril 2006StatutMembreDernière intervention 5 juin 2006 10 avril 2006 à 09:04
salut... j'avais besoin d'une fonction explode en C, similaire a celle du php. En fait je récupère le contenu affiché dans la console d'un batch (de ftp) que je lance dans mon prog. Je récupère donc ce contenu dans un fichier, puis je l'ouvre et je fait un fgets sur chaque ligne... et donc je peux récuperer la liste des fichiers que j'obtiens en faisant un ls quand je suis connecté... je mets dans un buffer la sortie de ce fgets(), et je fais un explode(grace a cette fonction au dessus), pour avoir l'extension des fichiers (je ne veux que les txt)... mais la j'ai un pb... il me sort que le nom de fichier est, a chaque fois, "2292832"...et que l'extension est bien "TXT". comment ca se fait, pour le nom de fichier??? si kkun a une idée?? je sèche...
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 20062 22 août 2005 à 18:43
Mon code étant buggué, je le corrige.
J'ai supprimé le realloc qui peut être pénalisant pour les perfs.
// Compte le nombre séparateur, le nombre de champs vide
// et le séparateur par des '\0'
while( pos = strstr( pos, separator ) ) {
memset( pos, '\0', sizeSeparator );
if ( pos == str || ( pos != str && !*(pos-1) ) )
++nbEmptyField;
meech
Messages postés209Date d'inscriptionvendredi 11 avril 2003StatutMembreDernière intervention14 août 2007 19 août 2005 à 10:54
Goth > conernant la désallocation, tu as raison, je n'avais pas vu les choses comme cela. Pas mal du tout, ton code.
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 20062 19 août 2005 à 10:05
C'est jamais important que ça marche, c'est le minimum que ça marche.
A quoi peut bien servir du code qui ne marche pas ?
L'important c'est que ça soit utilisable, lisible, maintenable, souple,...
ça c'est important et toute la difficulté à mon sens.
Le fait d'utiliser la chaîne passée en entrée permet justement
d'éviter d'avoir la responsabilibité de l'allocation et la boucle
pour libérer la mémoire.
PS : les 2 lignes : if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
se remplacent par : if ( !vide && ( !*currentSplit[ current-1 ] ) )
PPS: J'ai omis le test sur les retours d'allocation car non présent dans le code original.
cs_goth
Messages postés82Date d'inscriptionlundi 23 décembre 2002StatutMembreDernière intervention23 août 2005 19 août 2005 à 09:29
pour la refonte en c++, la je developpe en C, c le pourquoi du comment.
Puis ta fonction marche bien, mais, à mon avis le pb,si c'en est un, c que tu réutilise la même chaine str (d'ou l'économie de malloc)
Mais bon, ca marche c l'important non?
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 20062 19 août 2005 à 00:16
Au fait, voici la correction pour
le cas du séparateur bar ;)
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 20062 19 août 2005 à 00:12
goth > l'idéal pour refaire la fonction PHP, c'est d'utiliser le C++ avec std::string et std::vector comme ça le principal problème d'allocation/réallocation est résolu.
Meech, la désallocation en boucle est désagréable pour un utilisateur surtout si la boucle d'affichage et la boucle de désallocation sont séparées.
Voici une autre version, un peu plus courte,
qui n'impose pas la boucle de free en modifiant la chaîne entrée en param. le param vide est traité même si pas très utile à mon sens en pratique.
A vous de voir.
// La chaine à splitter qui sera modifée
char** split( char* str, const char* c, int vide )
{
int currentSplitSize = 8;
char** currentSplit = malloc( currentSplitSize * sizeof(char*) );
int sizeSeparateur = strlen( c );
int current = 0;
currentSplit[current++] = str;
// Si on ne veut pas des chaines vide, et si la chaine
// précédente est vide alors, on recule pour l'effacer
if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
--current;
// On pointe vers le nouveau début
currentSplit[ current++ ] = str;
// On agrandit le tableau si trop petit en le doublant
if ( current > currentSplitSize - 1 )
{
currentSplitSize <<=2;
currentSplit = realloc( currentSplit,
currentSplitSize * sizeof(char*) );
}
}
// La dernière chaine peut etre vide, on recule pour la supprimer
if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
--current;
// On termine le tableau
currentSplit[ current ] = 0;
return currentSplit;
}
int main(){
int i;
char str[]="foo|bar||baz|bar|";
meech
Messages postés209Date d'inscriptionvendredi 11 avril 2003StatutMembreDernière intervention14 août 2007 18 août 2005 à 15:44
Salut,
1. Pour la question de la différence entre "const char*" et "char*", je cite :
"Une variable dont le type est qualifié par const ne peut pas être modifiée. Ce qualificateur est utilisé pour se protéger d'une erreur de programmation. On l'emploie principalement pour qualifier le type des paramètres d'une fonction afin d'éviter de les modifier involontairement."
2. Je ne comprends pas bien le problème de la boucle "free". Comment faire autrement, mis à part automatiser la désallocation dans une fonction ?
3. Un bon code très utile.
cs_goth
Messages postés82Date d'inscriptionlundi 23 décembre 2002StatutMembreDernière intervention23 août 2005 18 août 2005 à 09:48
en fait j'ai réessayer de fai re le fonction explode comme on la trouve en php, donc a l'origine en gardant les mots vides (comme tu l'a dit ca peu etre utile pour un csv ou fichier de config qqconque.
>Tu aurais sûrement pu faire une fonction unique pour le realloc si besoin.
tu entends quoi par la?
> si on rajoute const au param shaine, il faut que largestring soit aussi en const sinon il y a un warning.
Mais question....ca change quoi de mettre en const char *.
>en ca qui conscerne la taille du séparateur tu peux tres bien avoir une chaine comme séparateur. Essaie de mettre bar comme séparateur (dans l'exempel ca va de soit) et tu aura comme sortie :
Chaine
0 : fo
1 : ||
2 : |
pour finir avec le problème du free en boucle, je voulais que la fonction soit dynamique au possible...j'aurais pu allouer par plus gros bloc puis désallouer le surplus en fin, mais bon...
Puis pour les free...ben fau bien liberer la memoire allouer...sinon comment tu veux faire?
goth
Hylvenir
Messages postés364Date d'inscriptionmercredi 11 février 2004StatutMembreDernière intervention 5 octobre 20062 17 août 2005 à 22:52
Tu aurais sûrement pu faire une fonction unique pour le realloc si besoin.
Dans ton test, tu ne profites pas de la possiblité d'avoir un séparateur de plusieurs caractères. Domamge.
Par contre, bien le main qui lance la fonction, ça aurait été parfait,
avec un test automatique vérifiant les résultats mais je chipote ;)
L'idée du vide est original (par exemple strtok n'accepte pas) mais est-ce utile ? J'imagine un fichier csv pour lequel on sauterait les
colonnes vide ( ;; ). pas top ? Mais c'est peut être bien d'avoir le choix.
La signature de tes fonction devrait probablement être const char*, const char*, int. Il semble qu'il manque un const.
Les multiples realloc font que c'est assez pénible à utiliser au retour (avec des free en boucle)? il n'y a pas mieux ?
26 mars 2012 à 21:01
while( *pos++ );
pos += sizeSeparator - 1;
}
currentSplit[sizeSplit] = 0; // Affectation manquante
return currentSplit;
}
26 mars 2012 à 20:26
Non testé ? je ne pense pas. Peut être pas tous les cas mais bon.
Quelles sont les données en entrées qui font planter ?
9 mars 2012 à 15:48
Alors quand on met du code source on balance pas du code sans l'avoir testé avant "Hylvenir" >:-(
Au final ton code marche pas des segfault à la volé j'ai pas envie de debuguer
Le mec a peux être fait du code pas propre à cause de la dé-allocation abusive mais sa marche!
18 sept. 2006 à 23:27
Essaie man 3 strcmp dans google
16 sept. 2006 à 19:49
J'essay d'utiliser ton code mais j'ai un petit souci.
Mon code :
char** tableau;
tableau = split("TESTE;rien",";",0);
if (tableau[0] == "TESTE")
{
printf("%s",tableau[0]);
} else {
printf("1er tableau n'est pas teste0");
}
Mon probleme est qu'il fait toujours le else, pourquoi ?
10 avril 2006 à 10:10
mais je rajoute que l'explode marche nikel!!! merci les coupains!
10 avril 2006 à 09:33
10 avril 2006 à 09:04
22 août 2005 à 18:43
J'ai supprimé le realloc qui peut être pénalisant pour les perfs.
// ---------------------------------------------------------------------
char** split( char* str, const char* separator, int removeEmptyField )
{
size_t sizeSeparator = strlen( separator );
char** currentSplit = 0;
size_t nbSep 0, nbEmptyField 0, sizeSplit = 0, currentSep = 0;
char* pos str, *currentPos str;
// Compte le nombre séparateur, le nombre de champs vide
// et le séparateur par des '\0'
while( pos = strstr( pos, separator ) ) {
memset( pos, '\0', sizeSeparator );
if ( pos == str || ( pos != str && !*(pos-1) ) )
++nbEmptyField;
++nbSep;
currentPos = (pos += sizeSeparator);
}
if ( currentPos == str || ( currentPos != str && !*currentPos ) )
++nbEmptyField;
// Calcul la taille du tableau final
sizeSplit = nbSep+1 - (removeEmptyField?nbEmptyField:0);
if ( !sizeSplit ) return 0;
// Alloue le tableau des pointeurs
currentSplit = malloc( (sizeSplit+1) * sizeof(char*) );
if ( !currentSplit ) return 0;
// Affecte les entrées du tableau
pos = str;
while( currentSep < sizeSplit ) {
if ( !( removeEmptyField && !*pos ) )
currentSplit[currentSep++] = pos;
while( *pos++ );
pos += sizeSeparator - 1;
}
return currentSplit;
}
19 août 2005 à 10:54
19 août 2005 à 10:05
A quoi peut bien servir du code qui ne marche pas ?
L'important c'est que ça soit utilisable, lisible, maintenable, souple,...
ça c'est important et toute la difficulté à mon sens.
Le fait d'utiliser la chaîne passée en entrée permet justement
d'éviter d'avoir la responsabilibité de l'allocation et la boucle
pour libérer la mémoire.
PS : les 2 lignes : if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
se remplacent par : if ( !vide && ( !*currentSplit[ current-1 ] ) )
PPS: J'ai omis le test sur les retours d'allocation car non présent dans le code original.
19 août 2005 à 09:29
Puis ta fonction marche bien, mais, à mon avis le pb,si c'en est un, c que tu réutilise la même chaine str (d'ou l'économie de malloc)
Mais bon, ca marche c l'important non?
19 août 2005 à 00:16
le cas du séparateur bar ;)
Chaine initiale : foo|bar||baz|bar|
0 : foo|
1 : ||baz|
2 : |
19 août 2005 à 00:12
Meech, la désallocation en boucle est désagréable pour un utilisateur surtout si la boucle d'affichage et la boucle de désallocation sont séparées.
Voici une autre version, un peu plus courte,
qui n'impose pas la boucle de free en modifiant la chaîne entrée en param. le param vide est traité même si pas très utile à mon sens en pratique.
A vous de voir.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// La chaine à splitter qui sera modifée
char** split( char* str, const char* c, int vide )
{
int currentSplitSize = 8;
char** currentSplit = malloc( currentSplitSize * sizeof(char*) );
int sizeSeparateur = strlen( c );
int current = 0;
currentSplit[current++] = str;
while( str = strstr( str, c ) )
{
*str = '\0';
str += sizeSeparateur;
// Si on ne veut pas des chaines vide, et si la chaine
// précédente est vide alors, on recule pour l'effacer
if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
--current;
// On pointe vers le nouveau début
currentSplit[ current++ ] = str;
// On agrandit le tableau si trop petit en le doublant
if ( current > currentSplitSize - 1 )
{
currentSplitSize <<=2;
currentSplit = realloc( currentSplit,
currentSplitSize * sizeof(char*) );
}
}
// La dernière chaine peut etre vide, on recule pour la supprimer
if ( !vide && ( !strlen(currentSplit[ current-1 ] ) ) )
--current;
// On termine le tableau
currentSplit[ current ] = 0;
return currentSplit;
}
int main(){
int i;
char str[]="foo|bar||baz|bar|";
printf("Chaine initiale : %s \n",str);
char** tab = split( str, "|", 0 );
for(i=0;tab[i];i++) {
printf("%d : %s\n",i,tab[i]);
}
free(tab);
printf("\n");
char str2[]="foo|bar||baz|bar|";
tab=split(str2,"|",1);
for(i=0;tab[i];i++) {
printf("%d : %s\n",i,tab[i]);
}
free(tab);
}
18 août 2005 à 15:44
1. Pour la question de la différence entre "const char*" et "char*", je cite :
"Une variable dont le type est qualifié par const ne peut pas être modifiée. Ce qualificateur est utilisé pour se protéger d'une erreur de programmation. On l'emploie principalement pour qualifier le type des paramètres d'une fonction afin d'éviter de les modifier involontairement."
2. Je ne comprends pas bien le problème de la boucle "free". Comment faire autrement, mis à part automatiser la désallocation dans une fonction ?
3. Un bon code très utile.
18 août 2005 à 09:48
>Tu aurais sûrement pu faire une fonction unique pour le realloc si besoin.
tu entends quoi par la?
> si on rajoute const au param shaine, il faut que largestring soit aussi en const sinon il y a un warning.
Mais question....ca change quoi de mettre en const char *.
>en ca qui conscerne la taille du séparateur tu peux tres bien avoir une chaine comme séparateur. Essaie de mettre bar comme séparateur (dans l'exempel ca va de soit) et tu aura comme sortie :
Chaine
0 : fo
1 : ||
2 : |
pour finir avec le problème du free en boucle, je voulais que la fonction soit dynamique au possible...j'aurais pu allouer par plus gros bloc puis désallouer le surplus en fin, mais bon...
Puis pour les free...ben fau bien liberer la memoire allouer...sinon comment tu veux faire?
goth
17 août 2005 à 22:52
c'est un peu compliqué pour juste la suppression du static
de l'exemple http://cppfrance.com/code.aspx?id=28947
Tu aurais sûrement pu faire une fonction unique pour le realloc si besoin.
Dans ton test, tu ne profites pas de la possiblité d'avoir un séparateur de plusieurs caractères. Domamge.
Par contre, bien le main qui lance la fonction, ça aurait été parfait,
avec un test automatique vérifiant les résultats mais je chipote ;)
L'idée du vide est original (par exemple strtok n'accepte pas) mais est-ce utile ? J'imagine un fichier csv pour lequel on sauterait les
colonnes vide ( ;; ). pas top ? Mais c'est peut être bien d'avoir le choix.
La signature de tes fonction devrait probablement être const char*, const char*, int. Il semble qu'il manque un const.
Les multiples realloc font que c'est assez pénible à utiliser au retour (avec des free en boucle)? il n'y a pas mieux ?
Cordialement.