title: dynamic string concatenation in C
body: <p>I know this is a very common question, but I would like to know your thoughts about the following function. The idea is that this function can concatenate strings without worrying of the result size:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdlib.h&gt;
  
  #define TAM 15 
  
  char* concat(char* answer, char* src, unsigned int* limit, unsigned int* total)
  {
   unsigned int length = strlen(src);
  
   if((*limit - *total) &gt; length)
    strcat(answer, src); 
   else
   {
    *limit *= 2;
    answer = realloc(answer, sizeof(char)*(*limit));
    printf("RESIZING...\n");
    if(answer == NULL)
    {  
     printf("RESIZING ERROR...\n"); 
     return NULL;
    }
  
    strcat(answer, src); 
   }
  
   *total += length;
  
   return answer;
  }
  
  int main(void)
  {
   char* strings[] = { "ONE", "TWO", "THREE", "FOUR", "FIVE" };
  
   unsigned int LIMIT = TAM;   //&lt;------
   unsigned int total = 0;     //&lt;------
  
   char* mem_block = calloc(LIMIT, sizeof(char));
  
   unsigned int i;
   for(i = 0; i&lt;5; ++i)
    mem_block = concat(mem_block, strings[i], &amp;LIMIT, &amp;total);  //&lt;------
  
   printf("RES : %s -- %d\n", mem_block, strlen(mem_block));
  
   free(mem_block);
  
   return 0;  
  }
  </code></pre>
  
  <p>This example runs well and valgrind reports all fine:</p>
  
  <pre><code>elias@elias-VirtualBox ~/Desktop $ valgrind ./reSize2
  ==2939== Memcheck, a memory error detector
  ==2939== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
  ==2939== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
  ==2939== Command: ./reSize2
  ==2939== 
  RESIZING...
  RES : ONETWOTHREEFOURFIVE -- 19
  ==2939== 
  ==2939== HEAP SUMMARY:
  ==2939==     in use at exit: 0 bytes in 0 blocks
  ==2939==   total heap usage: 2 allocs, 2 frees, 45 bytes allocated
  ==2939== 
  ==2939== All heap blocks were freed -- no leaks are possible
  ==2939== 
  ==2939== For counts of detected and suppressed errors, rerun with: -v
  ==2939== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
  </code></pre>
  
  <p>But there are a couple of things I don't like. I don't like to have to pass this variables //&lt;---- to the function. Is there a better way to do it? And also if I don't receive back the return pointer "mem_block", valgrind outputs the following:</p>
  
  <pre><code>==2923== Memcheck, a memory error detector
  ==2923== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
  ==2923== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
  ==2923== Command: ./reSize2
  ==2923== 
  RESIZING...
  ==2923== Invalid read of size 1
  ==2923==    at 0x4028D51: strcat (mc_replace_strmem.c:176)
  ==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x4028D59: strcat (mc_replace_strmem.c:176)
  ==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca029 is 1 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid write of size 1
  ==2923==    at 0x4028D6F: strcat (mc_replace_strmem.c:176)
  ==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca033 is 11 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid write of size 1
  ==2923==    at 0x4028D7C: strcat (mc_replace_strmem.c:176)
  ==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca035 is 13 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid write of size 1
  ==2923==    at 0x4028D81: strcat (mc_replace_strmem.c:176)
  ==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca037 is 0 bytes after a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x804864A: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x408A75C: vfprintf (vfprintf.c:1629)
  ==2923==    by 0x4092C9E: printf (printf.c:35)
  ==2923==    by 0x405F112: (below main) (libc-start.c:226)
  ==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x40B374B: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1317)
  ==2923==    by 0x4092C9E: printf (printf.c:35)
  ==2923==    by 0x405F112: (below main) (libc-start.c:226)
  ==2923==  Address 0x41ca036 is 14 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x40B375F: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1317)
  ==2923==    by 0x408A734: vfprintf (vfprintf.c:1629)
  ==2923==    by 0x4092C9E: printf (printf.c:35)
  ==2923==    by 0x405F112: (below main) (libc-start.c:226)
  ==2923==  Address 0x41ca035 is 13 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x40B36E8: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1349)
  ==2923==    by 0x408A734: vfprintf (vfprintf.c:1629)
  ==2923==    by 0x4092C9E: printf (printf.c:35)
  ==2923==    by 0x405F112: (below main) (libc-start.c:226)
  ==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== Invalid read of size 1
  ==2923==    at 0x40B36F4: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1348)
  ==2923==    by 0x408A734: vfprintf (vfprintf.c:1629)
  ==2923==    by 0x4092C9E: printf (printf.c:35)
  ==2923==    by 0x405F112: (below main) (libc-start.c:226)
  ==2923==  Address 0x41ca02a is 2 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  RES : ONETWOTHREEFIVE -- 15
  ==2923== Invalid free() / delete / delete[]
  ==2923==    at 0x4027C02: free (vg_replace_malloc.c:366)
  ==2923==    by 0x8048677: main (in /home/elias/Desktop/reSize2)
  ==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
  ==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
  ==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
  ==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
  ==2923== 
  ==2923== 
  ==2923== HEAP SUMMARY:
  ==2923==     in use at exit: 30 bytes in 1 blocks
  ==2923==   total heap usage: 2 allocs, 2 frees, 45 bytes allocated
  ==2923== 
  ==2923== LEAK SUMMARY:
  ==2923==    definitely lost: 30 bytes in 1 blocks
  ==2923==    indirectly lost: 0 bytes in 0 blocks
  ==2923==      possibly lost: 0 bytes in 0 blocks
  ==2923==    still reachable: 0 bytes in 0 blocks
  ==2923==         suppressed: 0 bytes in 0 blocks
  ==2923== Rerun with --leak-check=full to see details of leaked memory
  ==2923== 
  ==2923== For counts of detected and suppressed errors, rerun with: -v
  ==2923== ERROR SUMMARY: 80 errors from 12 contexts (suppressed: 11 from 6)
  </code></pre>
  
  <p>I'm a bit confused with this because I thought this was not necessary because  the function directly modifies the pointers.</p>
  
  <p>Any comments on how to improve this function will be welcome.</p>
  
  <p>Thanks a lot, and sorry for the long post.</p>