如果我正确阅读了您的 parse 函数,它似乎正在遍历 ptr 指定的字符串列表。列表本身以 null 结尾,列表中的起始偏移量位于索引 q。
解析函数的目标似乎是生成一个输出字符串,它是所有输入字符串的串联,但在每个字符串之间插入了一个分隔符字符串str 和一个space。类似于以下内容:
result = ""
for each string s in ptr:
result += s
result += delimiter
result += " "
return result;
令人困惑的是parse 函数的一些输入参数实际上只是局部变量或根本没有使用。这包括e',i, andb1`。
因此,使您的问题变得困难的是将每个字符串连接在一起并尝试跟踪稍后释放每个临时分配的内存管理。你真正需要的是一个字符串类。但这是 C,而不是 C++。幸运的是,我们可以通过结构类型和一些有价值的辅助函数来克服这个问题。
我建议让我们从一个为连接优化的有价值的字符串类开始。让我们定义一个“SimpleString”如下:
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;
这里结构的str 是原始字符串指针。
现在让我们创建一个简单的“构造函数”来创建一个字符串:
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;
}
上述函数将“malloc”一个 SimpleString 实例并返回指向它的指针。 SimpleString 的内部成员str 本身被初始化为一个空字符串。
现在,当我们想连接到这个字符串时,我们可以使用我们的辅助函数,如下所示:
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;
}
随着字符串的增长,上述函数将负责重新分配额外的内存(并释放旧内存)。
现在终于有了一个释放字符串的辅助函数:
void release_string(SimpleString* s)
{
if (s)
{
free(s->str);
free(s);
}
}
现在我们可以大大简化你的解析函数如下:
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;
}
在上述函数中,我将您的 ptr 参数重命名为 list 并将您的 str 参数重命名为 delimiter。我单独留下了q 作为列表中的初始偏移量。
我怀疑您真的只想在除最后一次迭代之外的所有内容上连接尾随空格。如果是这样,我会把它留给你做练习。
在您的原始实现中,您使用参数j 来指示使用并作为输出参数返回的字符串计数。您可以轻松地将其添加回去。 (例如*j = count;)
示例用法:
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;
}