# C allocation de memoire avec strcat



## tatouille (21 Mars 2006)

j'ai simplifié la structure, le probleme a chaque fois que j'essaye de toucher à
la mem de string_buffer je catch un SIGBUS


```
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


```
/* 
* 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;
}
```


----------



## Zeusviper (22 Mars 2006)

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 : 

```
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!)


```
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? ;-)

++


----------



## Didier Guillion (22 Mars 2006)

Attention le calloc mets la memoire a zero mais pas le malloc, donc, avant de faire le strcat, mettre un zero en debut de buffer.

Cordialement


----------



## tatouille (22 Mars 2006)

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


----------



## tatouille (22 Mars 2006)

```
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
```


----------



## tatouille (22 Mars 2006)

Didier Guillion a dit:
			
		

> Attention le calloc mets la memoire a zero mais pas le malloc, donc, avant de faire le strcat, mettre un zero en debut de buffer.
> 
> Cordialement



quand je met à zero j'ai un segfault !!!!!!


----------



## tatouille (22 Mars 2006)

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


----------



## Didier Guillion (22 Mars 2006)

tatouille a dit:
			
		

> test
> 
> char *buf = (char *)malloc(400);
> 
> ...




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


----------



## tatouille (23 Mars 2006)

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)


----------



## tatouille (28 Mars 2006)

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


----------



## yduc (4 Avril 2006)

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_


----------



## tatouille (6 Avril 2006)

yduc a dit:
			
		

> Juste une remarque, ne pas oublier le zéro final :
> 
> string_buffer=realloc( strl(string_buffer) + strl(elems_) *+ 1* )
> 
> ...


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

_


----------

