C allocation de memoire avec strcat

tatouille

Membre expert
1 Juin 2004
5 174
493
Stanford CA
j'ai simplifié la structure, le probleme a chaque fois que j'essaye de toucher à
la mem de string_buffer je catch un SIGBUS

Bloc de code:
char *string_buffer=(char *)calloc(1,2000);

/* j'ajoute une premiere chaine */
strcat(string_buffer,add_string);

/* puis je lis un Array */

for (i=0;i<elems;i++)
{
   /* ->string_buffer=realloc -> strl(string_buffer) + strl(elems[i]) ) */
   /* ici je voudrais réallouer de la mémoire à string_buffer */ 
   strcat(string_buffer,elems[i]);
}
Voila j'ai essayé plusieurs solutions mais je n'arrive pas réallouer de la mem
avec strcat , peut-être faut 'il faire un mem copy mais meme probleme

voila donc si quelqu'un a une solu plus sexy
(au lieu de créer un gros buffer en esperant qu'il sera suffisant sachant que elems est variant ...)

je pourrais bien sur faire une premiere boucle pour obtenir la len de chaque elems
mais c'est stupide (l e cpp pour ce genre de manipulation c'est plus souple )

ici le cas complet

Bloc de code:
/* 
* PyApp.h
* Tries to load this from the Info.plist file
*/
extern char *pyApp_plistPyRoot;
extern char *pyApp_plistPyMainClass;
extern char *pyApp_plistPyClassPath;
extern char *pyApp_ClassPathMask;
extern char *pyApp_plistDebug;

int PyApp_getPlistDict(char *filename)
{
    CFDataRef PlistData = PyApp_loadPlist(filename);
    CFStringRef WorkingDirectory;
    CFStringRef MainClass;
    CFNumberRef PrintDebug;
    CFArrayRef ClassPathArrayRef;
    CFIndex numClassPath = 0;
    char *classPathBuffer=(char *)calloc(1,2000);
    
    if (PlistData != NULL)
    {
        /* Creates root dict */
        CFPropertyListRef infoPlist = CFPropertyListCreateFromXMLData(
                                            NULL,PlistData,
                                            kCFPropertyListImmutable,
                                            NULL
                        );
          
          /* Gets  Python Dict */
        CFDictionaryRef PythonDict = CFDictionaryGetValue(infoPlist,CFSTR("Python"));
        
        if(WorkingDirectory = CFDictionaryGetValue(PythonDict,CFSTR("WorkingDirectory")))
        {
            /* extern */
            pyApp_plistPyRoot = PyApp_CFString2Char(WorkingDirectory);
          }

          if(MainClass = CFDictionaryGetValue(PythonDict,CFSTR("MainClass")))
          {
              /* extern */
              pyApp_plistPyMainClass = PyApp_CFString2Char(MainClass);
          }
          
          if(PrintDebug = CFDictionaryGetValue(PythonDict,CFSTR("PrintDebug")))
        {    
            SInt32 _debug = 0;
            CFNumberGetValue(PrintDebug,kCFNumberSInt32Type,&_debug);
            
            /* extern */
            if(_debug == 1)
                pyApp_plistDebug = "True";
            else
                pyApp_plistDebug = "False";
        }
        
        if(ClassPathArrayRef = (CFArrayRef) CFDictionaryGetValue(PythonDict,CFSTR("ClassPath")))
        {
             numClassPath = CFArrayGetCount(ClassPathArrayRef);
         }
        
        char *read_path = pyApp_plistPyRoot;
        char *py_path=(char *)calloc(1,strlen(read_path));
        sprintf(py_path,pyApp_ClassPathMask,read_path);
        strcat(classPathBuffer,py_path);
        
        if(numClassPath > 0)
        {
            int i = 0;
            
            for (i=0;i<numClassPath;i++)
            {        
                char *read_path = PyApp_CFString2Char(CFArrayGetValueAtIndex(ClassPathArrayRef,i));
                char *py_path=(char *)calloc(1,strlen(read_path));
                sprintf(py_path,pyApp_ClassPathMask,read_path);
                strcat(classPathBuffer,py_path);
            }
        }
        
        pyApp_plistPyClassPath = classPathBuffer;
        
          CFRelease(PlistData);
          CFRelease(infoPlist);
        
        return 1;
        
    }else
        return 0;
}
 
Euh d'abord une remarque : pourquoi utiliser un calloc? surtout si tu n'attribues qu'un élément?? :mouais:

Sinon, strcat ne touche pas du tout à la mémoire. Il faut donc que ton string_buffer soit pret a recevoir la chaine supplémentaire avant son appel.
Et donc tu ne peux échapper à la boucle de calcul des tailles ou bien une taille fixe!

Un code que j'avais trouvé quelquepart quand le problème s'était posé à moi :
Bloc de code:
Strcat, concatenate strings, alloc mem

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

char *mkconcat(char **, int);

int main(void) {
 char *strings[] = { "jasmin", "is", "a", "nutcracker" };
 char *result = NULL;

 result = mkconcat(strings, (sizeof(strings) / sizeof(strings[0])));
 if(result == NULL) {
  fprintf(stderr, "Error - mkconcat == NULL\n");
  return 1;
 } else {
  printf("%s\n", result);
  free(result);
 }

 return 0;
}

char *mkconcat(char **list, int max) {
 char *result = NULL;
 int i = 0, len = 0;

 /* calc. total size needed ... */
 for(i = 0; i < max; i++)
  len += (strlen(list[i]) + 1);

 /* alloc sufficient mem ... */
 result = malloc(len * sizeof(char) + 1);
 if(result == NULL) {
  fprintf(stderr, "Error - mkconcat -> malloc()\n");
  return NULL;
 }

 /* concatenate strings */
 for(i = 0; i < max; i++) {
  if(strcat(result, list[i]) == NULL) {
   fprintf(stderr, "Error - strcat()\n");
   return NULL;
  }

  if(i < (max - 1)) { /* space only inbetween tokens */
   if(strcat(result, " ") == NULL) {
    fprintf(stderr, "Error - strcat()\n");
    return NULL;
   }
  }
 }

 return result;
}


toutefois en voyant ca et par rapport à ce que tu souhaites : je pense qu'on pourrait simplement transformer le calloc en malloc, pui sun realloc avant chaque strcat. (mais je ne suis pas sur qu'en terme de performance ce soit trés bon!)

Bloc de code:
char *string_buffer=(char *)malloc(2000);

/* j'ajoute une premiere chaine */
strcat(string_buffer,add_string);

/* puis je lis un Array */

for (i=0;i<elems;i++)
{

   string_buffer=(char *)realloc(string_buffer, 2000+strlen(elems[i]));
   if ( string_buffer == NULL ) {
      printf("Erreur d'allocation mémoire !!!");
      exit(2);
   }
   /* ->string_buffer=realloc -> strl(string_buffer) + strl(elems[i]) ) */
   /* ici je voudrais réallouer de la mémoire à string_buffer */ 
   strcat(string_buffer,elems[i]);
}

et encore une tite remarque : pourquoi la première allocation à 2000?
et j'ai pas vu de free dans ton code? ;-)

++
 
merci des reponses j'utilise un c alloc parce qu'il n'y a pas tout

mais bon j'ai essayé aussi avec un malloc realloc
que ce soit sur le string buffer ou le pointeur de strcat
puis j'ai observé ce qui se passe nothing

j'ai fait un petit strcat_2 avec le code de strcat (freeBSD)
pour observer tout ce qui ce passe
un malloc realloc marche bien sous le linux
alors que sous darwin c'est comme 'p - ss -- r' dans un violon

didier
ok j'avais zappé ce point merci

mais bon le malloc ne m'arrange pas du tout du tout
merci je vais continuer à creuser
 
Bloc de code:
for (i=0;i<elems;i++)
{

   string_buffer=(char *)realloc(string_buffer, 2000+strlen(elems[i]));
   if ( string_buffer == NULL ) {
      printf("Erreur d'allocation mémoire !!!");
      exit(2);
   }
   /* ->string_buffer=realloc -> strl(string_buffer) + strl(elems[i]) ) */
   /* ici je voudrais réallouer de la mémoire à string_buffer */ 
   strcat(string_buffer,elems[i]);
}

j'obtient  toujours
 printf("Erreur d'allocation mémoire !!!"); 
sinon la bouble boucle c'est pas beau mais ca a le mérite
de ne pas crasher si les data sont supérieurs à la taille du Buffer
 
test

char *buf = (char *)malloc(400);

strcat( rempli la memoire)

for ...
{
buf=(char *)realloc(buf,2000); !!!!

strcat( char de 30 )
}

Segmentation fault

il realloc mon bip "ul"

j'ai essayé avec le pointeur de strcat aussi la même ?
suis je fou ?

strcat fait une copie
mais en utilisant son pointeur ca devrait fonctionner et bah non
 
tatouille a dit:
test

char *buf = (char *)malloc(400);

strcat( rempli la memoire)

for ...
{
buf=(char *)realloc(buf,2000); !!!!

strcat( char de 30 )
}

Segmentation fault

il realloc mon bip "ul"

j'ai essayé avec le pointeur de strcat aussi la même ?
suis je fou ?

strcat fait une copie
mais en utilisant son pointeur ca devrait fonctionner et bah non


Tu teste bien que ton realloc a fonctionné et n'a pas retourné NULL ?
Tu nettoie bien ton buffer par buff[0]=0; ou strcpy(buff,"");

Cordialement
 
Didier Guillion a dit:
Tu teste bien que ton realloc a fonctionné et n'a pas retourné NULL ?
Tu nettoie bien ton buffer par buff[0]=0; ou strcpy(buff,"");

Cordialement
oui je le nettoie mais j'ai identifié le problème qui pourtant ne devrait pas

j'appele cette method dans une method ou je fais un calloc
ca ne devrait pas merder mais
sous darwin ca à l'air de le gener

je calloc j'appel la method et hop j'ai un beau melange
c'est rigolo :) bon je vais remettre tout ca a plat et ca devrait fonctionner
pour l'instant je laisse un gros buffer et je limite la taille du tableau
qui ne devrait jamais depasser 10 membres (dans le context cela serait stupide)
 
Zeusviper a dit:
Euh d'abord une remarque : pourquoi utiliser un calloc? surtout si tu n'attribues qu'un élément?? :mouais:
...
j'ai tout remalloqué y'a pas de free parce que le buffer est assigné à une extern (de le suite dans le mallox)

mais ce n'est plus le cas
:zen:
 
Juste une remarque, ne pas oublier le zéro final :

string_buffer=realloc( strl(string_buffer) + strl(elems) + 1 )

(Ok dans l'exemple de Zeusviper (#2).)

Avec la mémoire qu'on a maintenant, une bonne solution consiste à travailler dans un tampon super grand, 1 Mo par exemple (voir large !), et à le retailler à la fin.

Yves
 
yduc a dit:
Juste une remarque, ne pas oublier le zéro final :

string_buffer=realloc( strl(string_buffer) + strl(elems) + 1 )

(Ok dans l'exemple de Zeusviper (#2).)

Avec la mémoire qu'on a maintenant, une bonne solution consiste à travailler dans un tampon super grand, 1 Mo par exemple (voir large !), et à le retailler à la fin.

Yves

oui mais dans mon cas faire un Tampon de 1 Mo ce serait tuer une mouche avec un fusil :)

:zen: