Forum Programmation.c Probleme de memoire, sprintf

Posté par  .
Étiquettes : aucune
0
12
août
2005
Bonjour,

J'ai écris un petit programme, mais en grandissant, et alors qu'il marché au départ, des erreurs de mémoire sont apparues à la compilation. Il me semble que j'utilise mal sprinf ou que j'ai un probleme de comprehension quelque part... En espérant que quelqu'un saura m'aider

Voici un code de test que j'ai fait pour isoler le probleme, il me renvoi une erreur de mémoire, pouquoi ?:


#include <stdio.h>
#include <string.h>

int main()
{
char * getipaddress(char *) ;
char * myip;
char * mystring;

myip = getipaddress("eth0");
sprintf(mystring,"mon adresse ip est :%s",myip);
//printf("ici mon string : %s",mystring);
return(1);
}
  • # allocation de chaine

    Posté par  . Évalué à 3.

    sprintf écrit des données dans un buffer qui doit déja etre alloué, ce qui n'est pas le cas dans ton code...

    au lien de char * mystring, utilise plutot char mystring[128];

    et au lien de sprintf(mystring,"mon adresse ip est :%s",myip)
    utilise snprintf(mystring,sizeof(mystring),"mon adresse ip est :%s",myip)
    qui fera un test pour etre sur de ne pas copier plus de données dans mystring que sa taille

    voila

    voir man sprintf/snprintf
    • [^] # Re: allocation de chaine

      Posté par  . Évalué à 2.

      Merci pour ta réponse, je vais essayer, dis-moi la taille du buffer est en nombre de caractères ?
      • [^] # Re: allocation de chaine

        Posté par  . Évalué à 3.

        dans ton cas oui: char mystring[128]; donc c'est un tableau de 128 caracteres

        pour des entiers; int montab[128]: tableau de 128 entiers (qui sont en général codés sur 4octets) soit en réalité 128*4 octets
        • [^] # Re: allocation de chaine

          Posté par  (site web personnel) . Évalué à 2.

          Les entiers sont codés sur sizeof(int) octets et c'est tout ce que tu dois savoir. Pareil pour les chars, c'est sizeof(char).

          Sinon comme dit plus bas, asprintf() est peut-être ton amie.

          pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

    • [^] # Re: allocation de chaine

      Posté par  (site web personnel) . Évalué à 3.

      sauf que snprintf ne garantit pas que la chaine soit bien NULL-terminated, ce qui en fait une fonction très peu pratique. asprintf de GNU est une meilleure alternative à sprintf.
      • [^] # Re: allocation de chaine

        Posté par  (site web personnel) . Évalué à 5.

        si on reprend ce qui est proposé plus haut :

        char *mystring[128]={0};
        snprintf(mystring, 127, "blach blah");

        t'assure un null-terminated dans tout les cas.

        (asprintf est pas disponible partout... hein)
      • [^] # Re: allocation de chaine

        Posté par  . Évalué à 4.

        snprintf termine toujours la chaine avec un 0. Tu dois confondre avec strncpy, qui elle ne la termine pas toujours (un vrai piège à débutant, d'ailleurs).
        • [^] # Re: allocation de chaine

          Posté par  (site web personnel) . Évalué à 2.

          mon dieu mais tu as raison ! :/

          on croit avoir des certitudes et tout s'écroule...

          int main() {
          int i;
          char foo[4];
          snprintf(foo, 4, "foobar");
          for (i = 0; i < 4; i++) {
          printf("char at %d is %d (%c)\n", i, foo[i], foo[i]);
          }
          }
        • [^] # Re: allocation de chaine

          Posté par  (site web personnel) . Évalué à 2.

          extrait de ma man page :
          Ces fonctions renvoient le nombre de caractères imprimés, sans compter
          le caractère nul `\0' final dans les chaînes. Les fonctions snprintf
          et vsnprintf n'écrivent pas plus de size octets (y compris le '\0'
          final). Si la sortie a été tronquée à cause de la limite, la valeur de
          retour est le nombre de caractères (sans le '\0' final) qui auraient
          été écrits dans la chaîne s'il y avait eu suffisament de place. Ainsi
          une valeur de retour size ou plus signifie que la sortie a été
          tronquée. (Voir aussi la section NOTES plus bas). Si une erreur de
          sortie s'est produite, une valeur négative est renvoyée.

          ce n'est pas très explicite : un \0 est _toujours_ ajouté en fin de chaîne.
  • # Tiens... tiens, j'ai dit tiens...

    Posté par  . Évalué à 4.


    sprintf(mystring,"mon adresse ip est :%s",myip);
    //printf("ici mon string : %s",mystring);
    return(1);


    Et donc, le problème est que tu perds ton string, c'est ça...?
  • # Strings et C

    Posté par  . Évalué à 5.

    J'ajouterais en premier lieu que déclarer une fonction dans le corps d'une autre (je parle de getipaddress), c'est peu courant ! Déplace ce truc au dessus du « int main() ».

    D'autre part, la solution que l'on t'a donné fonctionne, certes, mais ne met pas tellement en évidence ton erreur. J'ai l'impression que ton confonds les variables de type char * avec les objets Strings d'autres langages.

    Es-tu sûr d'avoir bien compris comment fonctionne un pointeur ?

    Si ce n'est pas le cas, sache que tous les ordinateurs fonctionnent comme cela en interne (au niveau du langage machine), que c'est relativement simple, contrairement à ce que pensent beaucoup d'étudiants en informatique, que cela correspond à quelque chose de très concret, et qu'en tout les cas ce n'est pas une bizarrerie du C inventée spécialement pour tourmenter les débutants. Quand tu auras maîtrisé ce truc, tu auras maîtrisé tout le reste.
  • # \_o<

    Posté par  (site web personnel) . Évalué à 2.

    si ca compile, mais execute mal:
    man valgrind
  • # Une solution

    Posté par  . Évalué à 1.

    Voilà, peut-être, une solution. Pas forcément très efficace en termes de temps, mais robuste.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    extern char* getipaddress(const char *) ;

    int main()~
    {
    char * myip;
    char * mystring;

    char cal_long[2]; // CHAINE BIDON POUR DETERMINER LA LONGUEUR A ECRIRE
    int longueur; // CONTIENT LA LONGUEUR DE LA CHAINE A ECRIRE

    myip = getipaddress("eth0");
    longueur = snprintf(mystring,sizeof(cal_long),"mon adresse ip est :%s",myip); // CALCUL DE LA LONGUEUR
    if ((mystring = malloc(longueur)) == NULL)
    {printf("ERREUR ALLOCATION MEMOIRE\n");
    exit(1);
    }
    sprintf(mystring,"mon adresse ip est :%s",myip);
    // printf("ici mon string : %s",mystring);
    free(mystring);
    return(1);
    }
    • [^] # Re: Une solution

      Posté par  . Évalué à 1.

      Boulette de ma part, il faut écrire:

      if ((mystring = malloc(longueur)+1) == NULL)

      pour tenir compte du /0 de fin de chaîne.
      • [^] # Re: Une solution

        Posté par  . Évalué à 1.

        ... et comme mystring n'est pas initialisée, lors de son utilisation dans le 1er snprintf, je le remplacerait par quelque chose commme :


        longueur = snprintf(NULL,0,"mon adresse ip est :%s",myip); // CALCUL DE LA LONGUEUR


        La variable cal_long ne sert à rien.
        • [^] # Re: Une solution

          Posté par  . Évalué à 1.

          La variable cal_long "devait" servir à quelque chose, puisque je devais écrire:
          longueur = snprintf(cal_long,sizeof(cal_long),"mon adresse ip est :%s",myip); // CALCUL DE LA LONGUEUR

          Mais qu'une inattention m'a fait écrire (ce qui est évidemment faux):
          longueur = snprintf(mystring,sizeof(cal_long),"mon adresse ip est :%s",myip); // CALCUL DE LA LONGUEUR


          Quand à la version:
          longueur = snprintf(NULL,0,"mon adresse ip est :%s",myip); // CALCUL DE LA LONGUEUR

          Elle serait élégante si elle était portable, malheureusement: non.

          Extrait de "man snprintf":

          CONFORMITÉ
          ...
          En ce qui concerne la valeur de retour de snprintf, SUSv2 et C99 sont en contradiction : lorsque snprintf est appelée avec un argument size=0 lors SUSv2 précise une valeur de retour indéterminée, autre que 1, alors que C99 autorise str à être NULL dans ce cas, et réclame en valeur de retour (comme toujours) le nombre de caractères qui auraient été écrits si la chaîne de sortie avait été assez grande.
          ...

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.