Les string en c, affectation, concaténation, split, ...

Soyez le premier à donner votre avis sur cette source.

Vue 7 904 fois - Téléchargée 680 fois

Description

Le concept de string manque dans le langage C. Présent en C++ grâce à la POO, l'objet string facilite la vie des développeurs dès lors que l'on souhaite manipuler des chaine de caractère.
Si l'on se penche sur la question, il est assez aisé d'imiter le type string en langage C, en faisant de la "pseudo POO".
Sans la surcharge de méthodes et d'opérateurs, voici une petite source permettant de créer des Variables type string (les MSTRING), de leur affecter simplement une valeur, de les concaténer et de les spliter entre elles, etc...

les fonctions sont :
affect => affecter une chaine de caractère à une MSTRING
concat => concatène deux MSTRING
deconcat => split de MSTRING selon une MSTRING, c'est à dire que le délimiteur n'est pas un caractère mais bien une chaine de caractère.
equal => compare deux MSTRING
destroyM => détruit une MSTRING
destroyP => détruit un tableau de MSTRING (les PSTRING)

Les allocations sont dynamiques, et permettent en théorie de donner dynamiquement une taille à une MSTRING.
Les fonctions prennent un dernier paramètre de type MSTRING permettant de ne pas modifier les deux premier.

ex: concat(string1, string2, string3) renvoie string3 (string3 = string1+string2) ainsi string1 et string2 ne sont pas modifiés.

ATTENTION, nous ne sommes pas en C++, donc pas de destructeur, il est donc nécessaire de détruire manuellement chaque chaine(MSTRING) "construite" avec destroyM() et chaque tableau de chaine(PMSTRING) avec destroyP().Eh oui! pas de miracle (vous croyiez quoi !!!).

J'ai testé le code sous valgrind (pour ceux qui connaissent), si les destruction de MSTRING se font correctement, il n'y a pas de fuite de mémoire.

Il doit certainement y avoir beaucoup d'améliorations à apporter, je peux juste dire qu'après avoir développé ces MSTRING, cela m'a beaucoup facilité la vie!!

Nul doute que les pros s'ennuieront devant cette source, puisqu'ils disposeront certainement des libs bien plus puissantes, mais j'ose espérer que certains débutants trouveront leur bonheur et que mes MSTRING dépanneront des codes sources =))

Développé sous CodeBlocks 8.02, Le code est portable et fonctionne donc sur tous les OS.

Source / Exemple :


#include "mstring.h"

MSTRING affect(const char *valeur ,MSTRING chaine)
{
    int taille = 0;
    int compteur = 0;

    while( valeur[taille] != '\0')
    {
        taille++;
    }

    chaine.taille = taille;
    chaine.text = malloc(taille*sizeof(char));

    for (compteur = 0; compteur < taille; compteur++)
    {
        chaine.text[compteur] = valeur[compteur];
    }
    chaine.text[chaine.taille] = '\0';

    return chaine;
}

void destroyM(MSTRING chaine)
{
    if( chaine.text != NULL)
    {
        free(chaine.text);
    }
    chaine.taille = 0;
}

void destroyP(PMSTRING Pchaine)
{
    int i = 0;

    for (i = 0; i < Pchaine.nbresschaine; i++)
    {
      destroyM(Pchaine.chaine[i]);
    }

    if (Pchaine.chaine != NULL)
    {
      free(Pchaine.chaine);
    }
    Pchaine.nbresschaine = 0;
}

MSTRING concat(MSTRING debut, MSTRING fin,MSTRING sortie)
{
    int compteur = 0;

    sortie.taille = debut.taille + fin.taille;
    sortie.text = malloc(sizeof(char) * sortie.taille);

    for(compteur = 0; compteur < debut.taille ; compteur++)
    {
        sortie.text[compteur] = debut.text[compteur];
    }
    for(compteur = debut.taille; compteur < sortie.taille; compteur++)
    {
        sortie.text[compteur] = fin.text[compteur - debut.taille];
    }

    sortie.text[sortie.taille] = '\0';

    return sortie;

}

PMSTRING deconcat(MSTRING entree, MSTRING delimiter, PMSTRING sortie)
{
    char *pointer = NULL;
    MSTRING temp;

    int occurence = 0;
    int index = 0;

    if ( entree.text != NULL && delimiter.text != NULL )
    {
            temp = affect(entree.text,temp);

        if(( pointer = strtok(temp.text,delimiter.text)) != NULL)
        {
            do
            {
                occurence++;
            }while((pointer = strtok(NULL,delimiter.text)) != NULL);

            sortie.nbresschaine = occurence;
            sortie.chaine = malloc(sizeof(MSTRING)*occurence);

            pointer = NULL;
            destroyM(temp);

            temp = affect(entree.text,temp);

            if(( pointer = strtok(temp.text,delimiter.text)) != NULL)
            {
                do
                {
                    sortie.chaine[index] = affect(pointer,sortie.chaine[index]);
                    index++;

                }while ((pointer = strtok(NULL,delimiter.text)) != NULL);
            }

        }
    }

    destroyM(temp);

    return sortie;
}

int equal(MSTRING string1, MSTRING string2)
{
    int count = 0;

    if ( string1.taille == string2.taille)
    {
        for ( count = 0; count < string1.taille; count++ )
        {
            if ( string1.text[count] != string2.text[count] )
            {
                return ERROR;
            }
        }
    }
    else
    {
        return ERROR;
    }

    return SUCCESS;
}

Conclusion :


Le C ça déchire quand même vachement finalement ...

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
1
Date d'inscription
samedi 6 mars 2010
Statut
Membre
Dernière intervention
1 mai 2011

salut tout le monde.
J'ai un petit projet en C qui permet la saisi d'une fonction qlcq
et le calcul de son aire par 3 méthodes différentes.Maintenant j'ai établi le programme qui fait le calcul de l'aire de n'importe quelle fonction. Mais je me suis bloquée au niveau de la saisi de la fonction par clavier?
SVP j'ai besoin d'un programme en C qui permet la saisi d'une telle fonction??
merci de me répondre!
je suis à l'attente de vos réponses!
Messages postés
51
Date d'inscription
lundi 8 septembre 2008
Statut
Membre
Dernière intervention
18 août 2009

OK NoMitsu, belle démonstration ! je pensais pas qu'il pouvait y avoir une telle différence. Et voila qui va permettre à Appranting de rendre ses fonctions plus performantes et plus robustes !
Messages postés
122
Date d'inscription
lundi 16 décembre 2002
Statut
Membre
Dernière intervention
15 février 2011

je n'ai rien contre l'allocation dynamique. c'est le reste de l'implem qui me dérange.
tien juste par curiosité j'ai fait un petit bench de 4 bouts de code.
Tous on pour objectif de copier une chaine de 10mo et de libérer la mémoire après copy.

implem "homemade" utilise le code donne par appranting:
void execute(void)
{
MSTRING tmp;

affect(_string, tmp);
destroyM(tmp);
}
moyen pour 100 test 66279ms.

implem "cstring" identique a homemade mais avec les functions string de la libc:
void execute(void)
{
size_t size = strlen(_string);
char* data = static_cast<char*>(malloc((size + 1) * sizeof(*_string)));
if (data == NULL)
throw "bad alloc";
strcpy(data, _string);
free(data);
}
moyen pour 100 test 11304ms.

implem "strdup" simplification du "cstring" avec strdup:
void execute(void)
{
char* data = strdup(_string);
if (data == NULL)
throw "bad alloc";
free(data);
}
moyen pour 100 test 9013ms.

implem "stl" utilise la class string de la stl:
void execute(void)
{
std::string data(_string);
}
moyen pour 100 test 9228ms.

récapitulatif

strdup 9013ms référence
homemade 66279ms 635%
stl 9228ms 2%
cstring 11304ms 25%
Messages postés
1
Date d'inscription
mercredi 5 mai 2010
Statut
Membre
Dernière intervention
7 mars 2011

C'est une blague ?

Rien que dans la fonction affect(), il y a buffer overflow ... J'ai pas été plus loin pour voir si le reste est de la même "qualité" ...
Un peu de rigueur SVP !
Messages postés
51
Date d'inscription
lundi 8 septembre 2008
Statut
Membre
Dernière intervention
18 août 2009

Même si je ne suis pas rentré dans le détail du code, moi je trouve que l'exercice est plutôt intéressant.

Pas d'accord avec NoMitsu sur la performance : tous les langages modernes qui permettent une gestion simple des chaines font de l'allocation dynamique donc à mon avis, les fonctions d'appranting sont compétitives en performance d'autant qu'elles restent simples.

Aucun problème non plus sur le passage des paramètres : certes ce ne sont pas des pointeurs mais des structures qui comportent un pointeur et un entier. Ce n'est pas très éloigné ! en tout cas, la chaîne en elle même (le tableau de char) n'est jamais passée en paramètre.

Là ou je suis d'accord avec NoMitsu par contre c'est sur le contrôle des malloc afin de s'assurer que l'allocation c'est bien passée.
Afficher les 6 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.