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:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TAM 15
char* concat(char* answer, char* src, unsigned int* limit, unsigned int* total)
{
unsigned int length = strlen(src);
if((*limit - *total) > 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; //<------
unsigned int total = 0; //<------
char* mem_block = calloc(LIMIT, sizeof(char));
unsigned int i;
for(i = 0; i<5; ++i)
mem_block = concat(mem_block, strings[i], &LIMIT, &total); //<------
printf("RES : %s -- %d\n", mem_block, strlen(mem_block));
free(mem_block);
return 0;
}
This example runs well and valgrind reports all fine:
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)
But there are a couple of things I don’t like. I don’t like to have to pass this variables //<—- 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:
==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)
I’m a bit confused with this because I thought this was not necessary because the function directly modifies the pointers.
Any comments on how to improve this function will be welcome.
Thanks a lot, and sorry for the long post.
When you modify answer in your function you only modify it in the scope of the function, the calling function will still see the old value (which is invalid since you called realloc).
When you return the new pointer and start using it in the calling function everything works, as it should.
The easiest way to fix this is to make your concat function look like:
and call it like:
However, you should abstract out your strings into their own type instead of manually passing their lengths together. Something like:
should be a good starting point, then you can start to implement dynamic functions using this struct instead.