If I read your parse function correctly, it appears to be iterating over a list of strings specified by ptr
. The list itself is null terminated and the starting offset in the list is at index q
.
The parse function's goal appears to be to produce an output string that is the concatenation of all the input strings but with a delimiter string, str
and a space
inserted between each. Something like the following:
result = ""
for each string s in ptr:
result += s
result += delimiter
result += " "
return result;
What makes it confusing is that some of the input parameters to the parse
function are actually just local variables or not used at all. This includes e',
i, and
b1`.
So what makes your problem hard is the memory management of concatenating each string together and trying to keep track of freeing each temporary allocation later. What you really need is a string class. But this is C, not C++. Fortunately, we can overcome this with a struct type and some worthy helper functions.
I would suggest let's start with a worthy string class optimized for concatenation. Let's define a "SimpleString" as follows:
typedef struct _SimpleString
{
char* str; // the actual null terminated string
size_t length; // length of psz, not including null char
size_t allocated; // amount of memory malloc'd including room for null char
} SimpleString;
Where the str
of this struct is the raw string pointer.
Now let's create a simple "constructor" function to create a string:
SimpleString* create_string()
{
SimpleString* s = (SimpleString*)malloc(sizeof(SimpleString));
if (s == NULL)
{
return NULL; // out of memory
}
s->str = malloc(1);
if (s->str == NULL)
{
free(s);
return NULL;
}
s->str[0] = '\0';
s->length = 0;
s->allocated = 1;
return s;
}
The above function will "malloc" an instance of SimpleString and return the pointer to it. The inner member of SimpleString, str
, is initialized to an empty string itself.
Now whenever we want to concatenate into this string, we can use our helper function as follows:
int concat_string(SimpleString* s, const char* p)
{
size_t needed = 0;
size_t p_len = p ? strlen(p) : 0;
if (p == NULL)
{
return 0;
}
if (p_len == 0)
{
// nothing to do
return 1;
}
if (s->str)
{
needed += s->length;
}
needed += p_len;
needed += 1; // for null char
if (needed > s->allocated)
{
size_t newallocation = needed * 2; // allocate more than needed so that we don't have to reallocate and re-copy the buffer on each call to concat_string
char* newstring = malloc(newallocation);
if (newstring == NULL)
{
// out of memory
return 0;
}
newstring[0] = '\0';
s->allocated = newallocation;
if (s->str && (s->length > 0))
{
memcpy(newstring, s->str, s->length);
}
free(s->str);
s->str = newstring;
}
memcpy(s->str + s->length, p, p_len);
s->str[s->length + p_len] = '\0';
s->length += p_len;
return 1;
}
The above function will take care of reallocating additional memory (and freeing old memory) as the string grows.
Now finally a helper function to release the string:
void release_string(SimpleString* s)
{
if (s)
{
free(s->str);
free(s);
}
}
Now we can greatly simplify your parse function as follows:
SimpleString* parse(char **list, int q, const char *delimiter)
{
SimpleString* result = NULL;
char *current = list[q];
int count = 0;
while (current != NULL)
{
if (result == NULL)
{
result = create_string();
if (result == NULL)
{
// error! out of memory
break;
}
}
concat_string(result, current);
concat_string(result, delimiter);
concat_string(result, " ");
count++;
current = list[q + count];
}
return result;
}
In the above function, I renamed your ptr
parameter to be list
and your str
parameter to be delimiter
. I left q
alone as the initial offset into the list.
I suspect that you really wanted to only concatenate the trailing space on all but the last iteration. If that's the case, I'll leave that as an exercise for you.
And in your original implementation, you were using parameter j
to indicate the count of strings used and returned as an out parameter. You can easily add that back. (e.g. *j = count;
)
Sample usage:
int main()
{
char* list[] = { "Mecury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", NULL };
SimpleString* result = parse(list, 0, ",");
printf("%s\n", result->str);
release_string(result);
return 0;
}