This is just wrong:
// So far so good...
filename = (char *)calloc(length, sizeof(char));
// No!!! You just leaked the previously allocated memory block!
// The `\0` at the end is also wrong.
filename = "Hello World\0";
// This is OK
key = filename + 6;
// You are writing into memory of a string literal, that's undefined behavior
*(filename + 5) = 0;
// You are freeing a string literal, that's undefined behavior too
free(filename);
As for no segfault part, undefined behavior may not manifest itself right away: for example, when you free a wrong region, the freeing itself may work, but a subsequent allocation could fail.
If you would like to shorten the string, make a copy, and free the original:
char *filename = malloc(length); // no cast
strcpy(filename, "Hello, world"); // no \0
char *trimmed = strdup(filename+6); // Make a copy
free(filename); // Free the original
filename = trimmed; // You are done!
In general, you can free only what you have allocated. The main reason for this is that malloc
/calloc
/realloc
store "bookkeeping" information in the memory associated with the address returned to you, often in a block immediately prior to the allocated address. You can try faking it, but even if it works, the solution would be fragile and non-portable.