字符串修剪会导致内存泄漏吗?
我很好奇修剪字符串以确保不会发生内存泄漏的正确方法是什么。我想这可能确实是一个基于 free() 工作原理的问题。我已经包含了 trim() 函数的代码。见下文。
int main()
{
char* testStr1 = strdup("some string");
char* testStr2 = strdup(" some string");
char* testStr3 = strdup("some string ");
trim(&testStr1);
trim(&testStr2);
trim(&testStr3);
free(testStr1); // no memory leak
free(testStr2); // possible memory leak?
free(testStr3); // possible memory leak?
return 0;
}
int trim(char** pStr)
{
if(pStr == NULL || *pStr == NULL)
return FAILURE;
char* str = *pStr;
while(isspace(*str)) {
(*pStr)++;
str++;
}
if(*str == 0) {
*pStr = str;
return SUCCESS;
}
char *end = str + strlen(str) - 1;
while(end > str && isspace(*end))
end--;
*(end+1) = 0;
*pStr = str;
return SUCCESS;
}
I'm curious what the proper way to trim a string is to ensure that no memory leak occurs. I guess this may really be a question based on exactly how free() works. I've included the code for my trim() function. See below.
int main()
{
char* testStr1 = strdup("some string");
char* testStr2 = strdup(" some string");
char* testStr3 = strdup("some string ");
trim(&testStr1);
trim(&testStr2);
trim(&testStr3);
free(testStr1); // no memory leak
free(testStr2); // possible memory leak?
free(testStr3); // possible memory leak?
return 0;
}
int trim(char** pStr)
{
if(pStr == NULL || *pStr == NULL)
return FAILURE;
char* str = *pStr;
while(isspace(*str)) {
(*pStr)++;
str++;
}
if(*str == 0) {
*pStr = str;
return SUCCESS;
}
char *end = str + strlen(str) - 1;
while(end > str && isspace(*end))
end--;
*(end+1) = 0;
*pStr = str;
return SUCCESS;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这实际上并不是免费工作原理的答案,但我会按照以下方式做一些事情:
char * trim_realloc(char * str) {
字符 * p = str;
字符 * e;
字符*ne; // 新的结束
字符 * r;
size_t 长度;
您
应该注意我对
realloc
行的评论,因为无论如何我都将尾随空间归零(并且因为许多 realloc 实现只担心“它是否足够大”,而不是“是否有太多额外空间” )你可以让你的字符串所在的缓冲区在最后占用太多空间。它仍然是 \0 在正确的位置终止(除非我未经测试的代码中可能存在错误)。您可以做的其他事情是将字符串移动到缓冲区的开头,然后修剪尾部,以便:
完成以下步骤:
“c cat ”
“ca猫”
“猫猫”
“猫在”
“猫”
“猫”
在开始修剪尾巴之前
。现在,回到 free 的工作原理——free 需要传递 NULL 或堆分配函数之一传递给您的值。实现了一些堆分配库,以便当 malloc 分配数据时,该数据块的大小存储在 malloc 返回的地址之前的字节中,并且当您调用 free 时,该指针前面的字节用于确定要执行的操作。该内存块的实际大小是。如果您传递了 malloc(或 calloc、realloc 或类似的)未返回的内容,则 free 可能会查找错误的位置并使用它在那里找到的任何内容作为您要释放的块的大小 - 并且不会有任何好处的这个。
This isn't really an answer to how free works, but I would do something along these lines:
char * trim_realloc(char * str) {
char * p = str;
char * e;
char * ne; // new end
char * r;
size_t len;
}
You should note my comment on the line with
realloc
Since I zeroed out trailing space anyway (and since many realloc implementations only worry about "is it big enough", not "is there too much extra space") you could have just let the buffer that your string lived in take up too much space at the end. It's still \0 terminated at the correct spot (unless there's bugs in my untested code, which there could be).Other things you could do would be to just move the string to the beginning of the buffer and then trim the tail, so that:
went through the steps:
"c cat "
"ca cat "
"catcat "
"cat at "
"cat t "
"cat "
before you started trimming the tail.
Now, back to how free works -- free needs to be passed either NULL or a value that one of the heap allocation functions passed to you. Some heap allocation libraries are implemented so that when malloc allocates data the size of that data chunk is stored in the bytes just before the address that malloc returns, and when you call free the bytes just in front of that pointer are used to determine what the size of that memory chunk actually is. If you pass the something that was not returned by malloc (or calloc, or realloc, or similar) then free may look in the wrong place and use whatever it finds there as the size of the chunk you are freeing -- and nothing good comes of this.
您不需要额外的 malloc/realloc/... 进行修剪,例如:
不快但安全,对于您的示例, free 永远不会失败,因为 s 没有改变。只有内容可以更改。
You don't need an extra malloc/realloc/... in trim, like:
Not fast but safe, free fails never for your examples, because s not changed. Only the s content can change.
是的,这会导致内存泄漏,但更糟糕的是,它会导致未定义的行为。由于
trim
修改了指针变量,因此main
将指针传递给free
,而malloc
未返回该指针。这是未定义的行为,在许多实现中它会损坏堆。至少有三种正确的方法来处理这个问题。
1. 让修剪分配并返回一个新字符串,并让调用者负责释放新字符串以及旧字符串(如果需要):
2. 让调用者分配一个相同长度的新字符串(以保守一点),并将两个指针传入。
3. 将字符串修剪到位,向左移动:
Yes, this will cause a memory leak, but worse, it causes undefined behavior. Since
trim
modifies the pointer variables,main
passes a pointer tofree
that was not returned bymalloc
. This is undefined behavior, and it will corrupt the heap on many implementations.There are at least three correct ways to handle this.
1. Have trim allocate and return a new string, and make the caller responsible for freeing the new one, as well as the old (if needed):
2. Let the caller allocate a new string the same length (to be conservative), and pass both pointers in.
3. Trim the string in place, shifting it left:
您传递给
free
的指针需要完全与您从malloc
(或calloc
或< code>realloc),而不仅仅是指向malloc
返回的内存区域的指针。因此,您的第二根字符串是导致问题的原因。您的第一个和第三个都很好,因为您传递给free
的指针与您从malloc
收到的指针(通过strdup
)相匹配。然而,在这种情况下,你得到的并不是真正的内存泄漏——而是未定义的行为。
The pointer you pass to
free
needs to be exactly the same pointer you received frommalloc
(orcalloc
orrealloc
), not just a pointer into the region of memory thatmalloc
returned. As such, your second string is the one that causes a problem. Your first and third are fine because the pointer you pass tofree
matches the one you received frommalloc
(viastrdup
).What you're getting in that case, however, isn't really a memory leak -- it's undefined behavior.