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

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2010
    Messages : 6
    Points : 7
    Points
    7
    Par défaut Y a t'il une fonction semblable à realloc, mais pour supprimer les premiers éléments d'une chaîne ?
    Bonjour

    Si j'alloue dynamiquement une chaîne de caractère, après si je veux supprimer les derniers caractères, je peux utiliser realloc pour supprimer ces caractères.
    Maintenant si je veux plutôt supprimer les premiers caractères est-ce qu'il existe une fonction un peu comme realloc qui pourrait le faire, plutôt qu'utiliser une boucle for ?

    J'avais aussi utiliser memcpy et realloc comme indiqué dans le code suivant :
    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
     
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
     
    int main() {
        #define ANCIENNE_TAILLE 16
        #define NOUVELLE_TAILLE ANCIENNE_TAILLE - 0xA + 1
        char * str_valeur = malloc(ANCIENNE_TAILLE * sizeof(char));
        strcpy(str_valeur, "0123456789ABCDEF");
     
        // Copie ABCDEF\0 dans le début de la chaîne et réalloue la chaîne
        memcpy(str_valeur, str_valeur + 0xA, NOUVELLE_TAILLE);
        str_valeur = realloc(str_valeur, NOUVELLE_TAILLE);
     
        // Affiche ABCDEF
        printf("%s\n", str_valeur);
    }
    J'avais fait à peu près la même chose dans mon programme et je l'ai compilé avec gcc et ça fonctionnait avec les optimisations -O0 et -O1, mais avec les autres optimisations, le programme se bloquait dans une boucle infinie. Par contre j'ai pas eu de problème avec l'exemple simple que j'ai montré.
    Je ne suis pas sûr si j'ai le droit d'appeler memcpy comme j'ai fait, parce que dans mon cas le 2e pointeur passé à memcpy pointe sur une partie du contenu du premier pointeur et apparemment ça fonctionne pas avec trop d'optimisation.

    Merci pour votre aide
    Jonas

  2. #2
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2010
    Messages : 6
    Points : 7
    Points
    7
    Par défaut
    En fait, je viens de voir que le problème qui venait avec les optimisations venait d'ailleurs.

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Je ne comprends pas pourquoi tu veux allouer à nouveau de la mémoire pour faire cela.Tu te compliques la tâche. Une simple boucle, qui tient en une ligne ou deux, fait parfaitement l'affaire. Une chaîne de caractères se termine toujours par un '\0'. Si la zone de mémoire allouée est plus grande, ce n'est pas un problème.
    Par exemple, si tu alloues 10 char et que tu y écrives les caractères suivants :
    'a','b','c','d','\0','f','g','h','i','j'
    alors ta chaîne de caractères sera en réalité :
    'a','b','c','d','\0'
    , ce qui n'empêche pas qu'il y a toujours 10 chars alloués. La condition est simplement que la chaîne de caractères tienne dans cette zone de mémoire, elle ne doit absolument pas déborder sinon il faut redouter le crash.

    1) Fais attention à la fonction memcpy. Les deux chaînes ne doivent pas se chevaucher. Ce n'est pas le cas dans ton exemple, mais par exemple si tu supprimais qu'un seul caractère, tu te retrouverais alors avec les deux chaînes qui se chevauchent.
    Explications :
    La fonction memcpy() copie n octets depuis la zone mémoire src vers la zone mémoire dest. Les deux zones ne doivent pas se chevaucher. Si c'est le cas, utilisez plutôt memmove(3) .
    2) Cette ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strcpy(str_valeur, "0123456789ABCDEF");
    est susceptible de provoquer un crash. Ce n'est pas 16 mais 17 chars qui sont copiées : 16 char + '\0' final.

    La fonction strcpy() copie la chaîne pointée par src (y compris le caractère `\0' final) dans la chaîne pointée par dest. Les deux chaînes ne doivent pas se chevaucher. La chaîne dest doit être assez grande pour accueillir la copie.
    3) Il faut toujours vérifier le retour de malloc. Si la fonction retourne NULL et que tu accèdes à cette adresse, c'est le crash assuré.

    4) Au sujet de realloc :
    Si realloc() échoue, le bloc mémoire original reste intact, il n'est ni libéré ni déplacé.
    Résultat : il y a fuite de mémoire si tu écrases le pointeur, ce qui est le cas dans ton exemple.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2010
    Messages : 6
    Points : 7
    Points
    7
    Par défaut
    Bonjour

    Merci d'avoir pris le temps de me répondre. Désolé d'avoir autant attendu avant de répondre.

    J'ai oublié quelques précisions :
    Je travaillait à l'époque sur un système embarqué avec seulement 256 ko de mémoire RAM et avec un micro kernel multitâche sans mémoire virtuelle qui tournait dessus.
    Ce bout de code devait se trouver dans une fonction qui retournait str_valeur et le processus qui l'appelle devra se charger de libérer le pointeur une fois qu'il avait fini de travailler avec.
    Cette fonction pouvait être appelée simultanément par plusieurs processus.
    Le coût d'une copie de quelques caractères par une boucle est négligeable, mais par curiosité, je voulais savoir si on pouvait éviter cette copie qui me semble pouvoir être théoriquement évitable. Il suffirait juste de désallouer le début de la chaîne de caractère. Bien sûr, on peut toujours vivre avec cette copie, mais c'était juste pour savoir.

    Je ne comprends pas pourquoi tu veux allouer à nouveau de la mémoire pour faire cela.Tu te compliques la tâche.
    C'est vrai, je n'en avait pas besoin dans mon cas (tant dans l'exemple que dans la réalité) parce que le gain de place faite à la réallocation était toujours inférieur à 16 caractères et que j'avais un nombre réduit de processus qui tournaient.
    Par contre ce ne serait plus forcément vrai si le gain de caractères serait bien plus important (genre 1ko) et si la fonction serait appelée simultanément par un nombre plus important de processus, sachant que je n'avais que 256ko de RAM disponible.

    2) Cette ligne
    Code :

    strcpy(str_valeur, "0123456789ABCDEF");

    est susceptible de provoquer un crash. Ce n'est pas 16 mais 17 chars qui sont copiées : 16 char + '\0' final.
    C'est juste, merci.

    Il faut toujours vérifier le retour de malloc. Si la fonction retourne NULL et que tu accèdes à cette adresse, c'est le crash assuré.
    Dans mon cas ce serait plus exactement une exception qui va faire crasher tout le système parce qu'un processus a tenté d'écrire quelque chose dans une ROM . Donc oui, ça voudrait la peine dans mon cas.

    Mais dans le cas où un système d'exploitation plus évolué est utilisé et qu'un processus fait appel à malloc, mais que malloc retourne NULL parce qu'il n'y a plus de mémoire allouable, de toute façon c'est déjà la fin assurée du processus, non ? Il ne pourra pas travailler correctement s'il ne peut pas allouer la mémoire qu'il a besoin et devra quitter, peut être plus proprement qu'un crash, mais le résultat final est le même, car si j'ai bien compris, le système d'exploitation tient une table par processus avec tous les pointeurs qu'il utilise et il va alors pouvoir tuer le processus qui a crashé et libérer la mémoire qu'il utilisait.
    Et si on aimerait traiter le cas en envoyant un message d'erreur, peut-être que l'envoi du message d'erreur entraîne un appel supplémentaire à malloc. Pendant ce temps, d'autres processus ainsi que le système d'exploitation peuvent aussi faire appel à malloc et rencontrer le même problème.
    Sinon, on pourrait envisager pour un processus important d'attendre que de la mémoire se libère grâce à un processus moins important qui va rencontrer le même problème et décider de se terminer.

    4) Au sujet de realloc :
    Citation:
    Si realloc() échoue, le bloc mémoire original reste intact, il n'est ni libéré ni déplacé.
    Résultat : il y a fuite de mémoire si tu écrases le pointeur, ce qui est le cas dans ton exemple.
    C'est vrai.

    Jonas

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 720
    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 720
    Points : 31 037
    Points
    31 037
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jeroman Voir le message
    1) Fais attention à la fonction memcpy. Les deux chaînes ne doivent pas se chevaucher. Ce n'est pas le cas dans ton exemple, mais par exemple si tu supprimais qu'un seul caractère, tu te retrouverais alors avec les deux chaînes qui se chevauchent.
    Bonjour

    Il me semblait avoir vu quelque part, il y a très longtemps (arf, désolé de ne pas pouvoir dire mieux) que si les zones se croisaient, alors memcpy() savait gérer.
    Exemple: si la zone destinatrice commence au milieu de la zone source, alors la copie part de la fin pour ne pas écraser la source.
    Et ça, je suis sûr que je l'ai vu à propos d'un mem quelconque (est-ce réellement memcpy ?) mais je n'arrive pas à retrouver le détail exact...

  6. #6
    Membre actif Avatar de quetzacoatl
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 168
    Points : 223
    Points
    223
    Par défaut
    La fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     void *memmove(void *dest, const void *src, size_t n);
    (dans <string.h>)
    gère les chevauchements de zones mémoires, mais elle est sans doute plus longue car elle effectue une copie de la zone à copier dans un tableau temporaire

  7. #7
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    memmove() , signalée déjà par jeroman plus haut.
    Dans une situation de chevauchement des zones mémoires, le comportement de memcpy() est indéfini.

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Citation Envoyé par quetzacoatl Voir le message
    La fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     void *memmove(void *dest, const void *src, size_t n);
    (dans <string.h>)
    gère les chevauchements de zones mémoires, mais elle est sans doute plus longue car elle effectue une copie de la zone à copier dans un tableau temporaire
    En fait, pas tout à fait. Pour être plus précis, elle se comporte "comme si" elle utilisait un tableau temporaire. Cela veut dire que, dans la pratique, un tableau temporaire n'est pas forcément utilisé, ce qui serait d'ailleurs peu économique. Le plus simple et le plus rapide, c'est que la fonction vérifie si dest>src ou si dest<src, afin qu'elle utilise la bonne méthode de copie. On peut d'ailleurs trouver de nombreuses implémentations memmove sur Google.

    Voilà ce que dit la norme C99 (la C90 dit pareil) :

    The memmove function copies n characters from the object pointed to by s2 into the
    object pointed to by s1. Copying takes place as if the n characters from the object
    pointed to by s2 are first copied into a temporary array of n characters that does not
    overlap the objects pointed to by s1 and s2, and then the n characters from the
    temporary array are copied into the object pointed to by s1.
    Traduction rapide :
    La fonction memmove copie "n" caractères de l'objet pointé par s2 vers l'objet pointé par s1.
    La copie se déroule comme si les "n" caractères de l'objet pointé par s2 étaient d'abord copiés vers un tableau temporaire ne chevauchant ni les objets pointés par s1 ni ceux pointés par s2, puis qu'ensuite les "n" caractères du tableau temporaire étaient copiés vers l'objet pointé par s1.

  9. #9
    Membre actif Avatar de quetzacoatl
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 168
    Points : 223
    Points
    223
    Par défaut
    J'avoue que le comme si m'avait échappé dans le man, merci @jeroman pour ces précisions.
    Désolé d'avoir créer ce doublon.

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 720
    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 720
    Points : 31 037
    Points
    31 037
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par diogene Voir le message
    memmove() , signalée déjà par jeroman plus haut.
    Dans une situation de chevauchement des zones mémoires, le comportement de memcpy() est indéfini.
    Euh, désolé si ma question semble con... mais à quoi sert memcpy() si memmove() fait pareil mais en mieux ?
    N'allons pas faire croire que faire un test initial pour détecter la position relative des deux zones afin de choisir si on commence par le début ou par la fin est super top gourmand en ressources quoi...

  11. #11
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Euh, désolé si ma question semble con... mais à quoi sert memcpy() si memmove() fait pareil mais en mieux ?
    N'allons pas faire croire que faire un test initial pour détecter la position relative des deux zones afin de choisir si on commence par le début ou par la fin est super top gourmand en ressources quoi...
    La différence entre les deux va potentiellement plus loin que ce simple test. memcpy() n'a pas à se préoccuper de ce recouvrement et peut donc être implémenter avec différentes optimisations (copie par bloc de n octets, appel d'instructions spécifiques, etc.) qui ne sont pas utilisables par memmove() (ou tout du moins pas utilisables dans tous les cas).

    Il est fréquent que l'implémentation de memmove() reste très simple et ne propose aucune optimisation particulière même lorsqu'elles pourraient être utilisées alors que memcpy() est optimisé

Discussions similaires

  1. Une fonction implémentée en Java pour afficher les nombres premiers
    Par autran dans le forum Codes sources à télécharger
    Réponses: 2
    Dernier message: 01/05/2015, 16h45
  2. Supprimer les premiers caractères d'une chaine
    Par Balbuzard dans le forum Débuter
    Réponses: 16
    Dernier message: 16/12/2010, 10h42
  3. Supprimer les premiers caractères d'une chaîne
    Par supers dans le forum Word
    Réponses: 4
    Dernier message: 21/08/2009, 10h04
  4. Supprimer les premiers 0 dans une chaîne
    Par supersmoos dans le forum Langage
    Réponses: 2
    Dernier message: 11/01/2007, 11h28
  5. [VB6]Une fonction comme Trim(), mais pour les "-"
    Par Jihnn dans le forum VB 6 et antérieur
    Réponses: 13
    Dernier message: 13/04/2006, 19h43

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