There are a number of ways to do this, and the way you approached it is a good one, but there are several areas where you seemed a bit confused. First, there is no need to allocated test. Simply using a pointer is fine. You could simply do char *test = "test"; in your example. No need to free it then either.
Next, when you are beginning to allocate memory dynamically, you need to always check the return to make sure your allocation succeeded. Otherwise, you can easily segfault if you attempt to write to a memory location when there has been no memory allocated.
In your substr, you should also validate the range of start and len you send to the function to insure you are not attempting to read past the end of the string.
When dealing with only positive numbers, it is better to use type size_t or unsigned. There will never be a negative start or len in your code, so size_t fits the purpose nicely.
Lastly, it is good practice to always check that a pointer to a memory block to be freed actually holds a valid address to prevent freeing a block of memory twice, etc... (e.g. if (sub) free (sub);)
Take a look at the following and let me know if you have questions. I changed the code to accept command line arguments from string, start and len, so the use is:
./progname the_string_to_get_sub_from start len
I hope the following helps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* substr (char* src, size_t start, size_t len)
{
/* validate indexes */
if (start + len > strlen (src)) {
fprintf (stderr, "%s() error: invalid substring index (start+len > length).\n", __func__);
return NULL;
}
char* sub = calloc (1, len + 1);
/* validate allocation */
if (!sub) {
fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
return NULL;
}
memcpy (sub, src + start, len);
// sub[len] = '\0'; /* by using calloc, sub is filled with 0 (null) */
return sub;
}
int main (int argc, char **argv) {
if (argc < 4 ) {
fprintf (stderr, "error: insufficient input, usage: %s string ss_start ss_length\n", argv[0]);
return 1;
}
char* test = argv[1]; /* no need to allocate test, a pointer is fine */
size_t ss_start = (size_t)atoi (argv[2]); /* convert start & length from */
size_t ss_lenght = (size_t)atoi (argv[3]); /* the command line arguments */
char* sub = substr (test, ss_start, ss_lenght);
if (sub) /* validate sub before use */
printf("\n sub: %s\n\n", sub);
if (sub) /* validate sub before free */
free(sub);
return 0;
}
Output
$ ./bin/str_substr test 1 2
sub: es
If you choose an invalid start / len combination:
$ ./bin/str_substr test 1 4
substr() error: invalid substring index (start+len > length).
Verify All Memory Freed
$ valgrind ./bin/str_substr test 1 2
==13515== Memcheck, a memory error detector
==13515== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==13515== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==13515== Command: ./bin/str_substr test 1 2
==13515==
sub: es
==13515==
==13515== HEAP SUMMARY:
==13515== in use at exit: 0 bytes in 0 blocks
==13515== total heap usage: 1 allocs, 1 frees, 4 bytes allocated
==13515==
==13515== All heap blocks were freed -- no leaks are possible
==13515==
==13515== For counts of detected and suppressed errors, rerun with: -v
==13515== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
\0at the end, and that's only appropriate if the substring takes all the length. I think it should be perfectly possible to have that kind of substring (const char* substr(const char* src, int start).), and this detail should be documented (because the initial string must not be changed anymore or the substring will just change too inexplicably, so to speak).memmove.valgrind. Simple to use. just run your program withvalgrind ./path/to/prog. Compile with-gandvalgrindwill identify lines with problems for you.memmoveand trymemmove(test, &test[1], 2); test = realloc(test, sizeof(char)*2); //to reduce the size to an appropriate length,esstgets printed. I assume this means that 5 bytes are still allocated for fortestinstead of 3 (the 2 chars and the null terminator).