Reputation: 1239
I'm trying to build a string piece by piece in my program by concatenating some values in order to obtain something like :
|0x0F64:0x0063:0x1A|0x7CC4:0x0073:0x1A|0x0A51:0xA29A:0x9C|0xD49D:0x0058:0x10|
I would like to use a dynamic variable because the NB_ELEMENT might be improved.
#include <stdio.h>
#include <stdlib.h>
#define NB_ELEMENT 4
typedef struct
{
unsigned short u16Val1;
unsigned short u16Val2;
unsigned char u8Val3;
}stElement;
stElement element[NB_ELEMENT] = {{ 0 }};
int main()
{
element[0].u16Val1 = 3940;
element[0].u16Val2 = 99;
element[0].u8Val3 = 26;
element[1].u16Val1 = 31940;
element[1].u16Val2 = 115;
element[2].u8Val3 = 26;
element[2].u16Val1 = 2641;
element[2].u16Val2 = 41620;
element[2].u8Val3 = 156;
element[3].u16Val1 = 52429;
element[3].u16Val2 = 88;
element[3].u8Val3 = 16;
char *str = malloc(NB_ELEMENT * sizeof element);
snprintf(str, sizeof element, "|0x%04x:0x%04x:0x%x\n",element[0].u16Val1,
element[0].u16Val2,
element[0].u8Val3);
str += sprintf(str, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
element[1].u16Val2,
element[1].u8Val3);
fprintf(stdout, "%s\n", str);
free(str);
return 0;
}
The code above returns :
*** Error in `./TEST': free(): invalid pointer: 0x0000000000cac023 ***
However, I managed to print |0x0f64:0x0063:0x1a
but avec adding str += sprintf.., the error occurs.
Upvotes: 0
Views: 271
Reputation: 121407
Because you are not passing free()
the same pointer returned by malloc()
. So, undefined behaviour.
With this statement:
str += sprintf(str, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
element[1].u16Val2,
element[1].u8Val3);
You have changedstr
.
From free()
:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc(), or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
(emphasis mine).
Upvotes: 4
Reputation: 41263
man 3 free
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs.
Since your str
is a pointer obtained by adding a number to a pointer obtained from malloc()
, it doesn't meet this requirement, and undefined behaviour results.
Be grateful it's a hard failure on your system -- on some systems it would have resulted in a memory leak or in weird memory corruption that would only reveal itself when your program started producing garbage.
Your code has other problems. You should probably review your C book's chapter on pointers and strings.
Upvotes: 2
Reputation: 1074979
The problem is here:
str += sprintf(str, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
element[1].u16Val2,
element[1].u8Val3);
That modifies the pointer in str
. So when you hand it to free
later, it's not the same pointer that malloc
gave you, which makes free
's job rather difficult.
Solution: Don't modify the pointer. If you want to keep track of where you are in the buffer by adding the number of characters written to the pointer, use a different pointer for that:
char *str = malloc(NB_ELEMENT * sizeof element);
// ...
char * p = str;
// ...
p += sprintf(p, "|0x%04x:0x%04x:0x%x\n",element[1].u16Val1,
element[1].u16Val2,
element[1].u8Val3);
// ...
free(str);
Upvotes: 7
Reputation: 133609
You can't concatenate strings in this way in C.
str += something
just changes the address stored in str
to something else, which then makes it an invalid pointer to be freed (since it's a value not obtained from malloc
/calloc
anymore).
You should use strncat
if you want to concatenate string, by initially allocate a buffer which is large enough to fit the whole contents.
Upvotes: 2