C内存分配问题
因此,我有几个与我创建的 string
类型一起使用的函数。 其中之一创建动态分配的刺。 另一个获取所述字符串并扩展它。 最后一个释放字符串。 注意:函数名称已更改,但都是我自定义的。
string new = make("Hello, ");
adds(new, "everyone");
free(new);
上面的代码有效 - 它编译并运行良好。 下面的代码不起作用 - 它会编译、运行,然后
string new = make("Hello, ");
adds(new, "everyone!");
free(new);
代码之间的区别在于 adds()
函数添加了 1 个以上的字符(!
)。 它添加的字符没有区别——只是长度。 为了完整起见,以下代码不起作用:
string new = make("Hello, ");
adds(new, "everyone");
adds(new, "!");
free(new);
奇怪的是,以下代码使用不同的函数 addc()
(添加 1 个字符而不是字符串)起作用:
string new = make("Hello, ");
adds(new, "everyone");
addc(new, '!');
free(new);
以下代码也 起作用:做同样的事情,有效:
string new = make("Hello, everyone!");
free(new);
所有不起作用的错误都是这样的:(
test(526) malloc: *** error for object 0x100130: double free
*** set a breakpoint in malloc_error_break to debug
test
是我在其中使用的程序的极具描述性的名称。)
就函数而言在内部,我的 make() 是对 strlen() 的调用,两次调用 malloc() 以及对 memcpy( ),我的 adds()
是对 strlen()
的调用,对 realloc()
的调用,以及对memcpy()
,而我的 free()
是对标准库 free()
的两次调用。
那么有什么想法为什么我会得到这个,或者我需要分解并使用调试器吗? 我只能使用超过一定长度的 adds()
来获取它,而不是使用 addc()
来获取它。
分解并发布函数代码:
typedef struct _str {
int _len;
char *_str;
} *string;
string make(char *c)
{
string s = malloc(sizeof(string));
if(s == NULL) return NULL;
s->_len = strlen(c);
s->_str = malloc(s->_len + 1);
if(s->_str == NULL)
{
free(s);
return NULL;
}
memcpy(s->_str, c, s->_len);
return s;
}
int adds(string s, char *c)
{
int l = strlen(c);
char *tmp;
if(l <= 0) return -1;
tmp = realloc(s->_str, s->_len + l + 1);
if(!tmp) return 0;
memcpy(s->_str + s->_len, c, l);
s->_len += l;
s->_str[s->_len] = 0;
return s->_len;
}
void myfree(string s)
{
if(s->_str) free(s->_str);
free(s);
s = NULL;
return;
}
So I have a couple of functions that work with a string
type I have created. One of them creates a dynamically allocated sting. The other one takes said string, and extends it. And the last one frees the string. Note: The function names are changed, but all are custom-defined by me.
string new = make("Hello, ");
adds(new, "everyone");
free(new);
The code above works - it compiles and runs fine. The code below does not work - it compiles, runs, and then
string new = make("Hello, ");
adds(new, "everyone!");
free(new);
The difference between the code is that the adds()
function is adding 1 more character (a !
). The character it adds makes no difference - just the length. Just for completeness, the following code does not work:
string new = make("Hello, ");
adds(new, "everyone");
adds(new, "!");
free(new);
Oddly, the following code, which uses a different function, addc()
(which adds 1 character instead of a string) works:
string new = make("Hello, ");
adds(new, "everyone");
addc(new, '!');
free(new);
The following, which also does the same thing, works:
string new = make("Hello, everyone!");
free(new);
The error that all the ones that don't work give is this:
test(526) malloc: *** error for object 0x100130: double free
*** set a breakpoint in malloc_error_break to debug
(test
is the extremely descriptive name of the program I have this in.)
As far as the function internals, my make()
is a call to strlen()
and two calls to malloc()
and a call to memcpy()
, my adds()
is a call to strlen()
, a call to realloc()
, and a call to memcpy()
, and my free()
is two calls to the standard library free()
.
So are there any ideas why I'm getting this, or do I need to break down and use a debugger? I'm only getting it with adds()
es of over a certain length, and not with addc()
s.
Breaking down and posting code for the functions:
typedef struct _str {
int _len;
char *_str;
} *string;
string make(char *c)
{
string s = malloc(sizeof(string));
if(s == NULL) return NULL;
s->_len = strlen(c);
s->_str = malloc(s->_len + 1);
if(s->_str == NULL)
{
free(s);
return NULL;
}
memcpy(s->_str, c, s->_len);
return s;
}
int adds(string s, char *c)
{
int l = strlen(c);
char *tmp;
if(l <= 0) return -1;
tmp = realloc(s->_str, s->_len + l + 1);
if(!tmp) return 0;
memcpy(s->_str + s->_len, c, l);
s->_len += l;
s->_str[s->_len] = 0;
return s->_len;
}
void myfree(string s)
{
if(s->_str) free(s->_str);
free(s);
s = NULL;
return;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我要解决的一些潜在问题:
1/ 你的 make() 很危险,因为它没有跨字符串的空终止符进行复制。
2/ 在
myfree()
中将s
设置为NULL
也没什么意义,因为它是传递的参数,对实际没有影响 。3/ 我不知道为什么如果添加的字符串长度为 0 或更小,则从
adds()
返回 -1 首先,它不能是负数。 其次,您似乎可以添加一个空字符串,这应该会导致不更改字符串并返回当前字符串长度。 如果失败(即 realloc() 不起作用),我只会返回 -1 的长度,并确保在发生这种情况时保留旧字符串。4/ 即使
tmp
变量可以更改,您也不会将它存储到s->_str
中 - 如果您增加内存,它很少会就地重新分配内存大小,但如果增量足够小以适合malloc()
分配的任何额外空间,则这是可能的。 减小大小几乎肯定会就地重新分配,除非您的malloc()
实现对不同大小的内存块使用不同的缓冲池。 但这只是一个旁白,因为您永远不会使用此代码减少内存使用量。5/ 我认为您的特定问题是您仅为字符串分配空间,该字符串是指向结构的指针,而不是结构本身。 这意味着当您放入字符串时,您正在破坏内存区域。
这是我会编写的代码(包括更具描述性的变量名称,但这只是我的偏好)。
我已经更改:
adds()
的返回值可以更好地反映长度和错误条件。 现在,如果无法扩展(并且原始字符串未受影响),它仅返回 -1 - 任何其他返回值都是新的字符串长度。myfree()
的返回值(如果您确实想要将字符串设置为 NULL),如“s = myfree (s)
”。myfree()
中检查NULL
字符串,因为现在如果没有分配的string->strChars 就永远不可能拥有已分配的
。string
就是这样,根据您的需要使用(或不使用:-):
我能看到的唯一其他可能的改进是维护空间缓冲区和
strChars
的末尾以允许无需调用malloc()
的扩展级别。这将需要缓冲区长度和字符串长度,并更改代码以仅在字符串长度和新字符长度的组合大于缓冲区长度时分配更多空间。
这些都将被封装在函数中,因此 API 根本不会改变。 而且,如果您设法提供函数来减小字符串的大小,它们也不必重新分配内存,只需减少缓冲区的使用即可。 在这种情况下,您可能需要一个 compress() 函数来减少具有大缓冲区和小字符串的字符串。
A number of potential problems I would fix:
1/ Your
make()
is dangerous since it's not copying across the null-terminator for the string.2/ It also makes little sense to set
s
toNULL
inmyfree()
since it's a passed parameter and will have no effect on the actual parameter passed in.3/ I'm not sure why you return -1 from
adds()
if the added string length is 0 or less. First, it can't be negative. Second, it seems quite plausible that you could add an empty string, which should result in not changing the string and returning the current string length. I would only return a length of -1 if it failed (i.e.realloc()
didn't work) and make sure the old string is preserved if that happens.4/ You're not storing the
tmp
variable intos->_str
even though it can change - it rarely re-allocates memory in-place if you're increasing the size although it is possible if the increase is small enough to fit within any extra space allocated bymalloc()
. Reduction of size would almost certainly re-allocate in-place unless your implementation ofmalloc()
uses different buffer pools for different-sized memory blocks. But that's just an aside, since you're not ever reducing the memory usage with this code.5/ I think your specific problem here is that you're only allocating space for string which is a pointer to the structure, not the structure itself. This means when you put the string in, you're corrupting the memory arena.
This is the code I would have written (including more descriptive variable names, but that's just my preference).
I've changed:
adds()
to better reflect the length and error conditions. Now it only returns -1 if it couldn't expand (and the original string is untouched) - any other return value is the new string length.myfree()
if you want to really do want to set the string to NULL with something like "s = myfree (s)
".myfree()
forNULL
string since you can now never have an allocatedstring
without an allocatedstring->strChars
.Here it is, use (or don't :-) as you see fit:
The only other possible improvement I could see would be to maintain a buffer of space and the end of the
strChars
to allow a level of expansion without callingmalloc()
.That would require both a buffer length and a string length and changing the code to only allocate more space if the combined string length and new chars length is greater than the buffer length.
This would all be encapsulated in the function so the API wouldn't change at all. And, if you ever get around to providing functions to reduce the size of a string, they wouldn't have to re-allocate memory either, they'd just reduce their usage of the buffer. You'd probably need a
compress()
function in that case to reduce strings that have a large buffer and small string.make
中的第一个 malloc 应该是:否则,您只是为指向
struct _str
的指针分配了足够的空间。The first malloc in
make
should be:Otherwise you're only allocating enough space for a pointer to
struct _str
.realloc 可以返回指向所请求块的新指针。 您需要添加以下代码行:
在一种情况下它不会崩溃,但在添加一个字符后会崩溃的原因可能只是因为内存的分配方式。 可能存在最小分配增量(在本例中为 16)。 因此,当您为 hello 分配前 8 个字符时,它实际上分配了 16 个字符。当您添加每个人时,它不会超过 16 个字符,因此您会得到原始块。 但对于 17 个字符,realloc 返回一个新的内存缓冲区。
尝试更改添加如下
realloc can return a new pointer to the requested block. You need to add the following line of code:
The reason it doesn't crash in one case but does after adding one more character is probably just because of how memory is allocated. There's probably a minimum allocation delta (in this case of 16). So when you alloc the first 8 chars for the hello, it actually allocates 16. When you add the everyone it doesn't exceed 16 so you get the original block back. But for 17 chars, realloc returns a new memory buffer.
Try changing add as follows
在函数
adds
中,您假设realloc
不会更改需要重新分配的内存块的地址:虽然这对于小型重新分配可能是正确的(因为块的大小您获得的内存通常会四舍五入以优化分配),但通常情况并非如此。 当 realloc 返回一个新指针时,您的程序仍然使用旧指针,从而导致问题:
In function
adds
, you assume thatrealloc
does not change the address of the memory block that needs to be reallocated:While this may be true for small reallocations (because sizes of blocks of memory you get are usually rounded to optimize allocations), this is not true in general. When realloc returns you a new pointer, your program still uses the old one, causing the problem:
可能应该发布代码,但是双重释放意味着您在同一个指针上调用释放两次。
Probably should post the code, but the double free means you are calling free on the same pointer twice.
为什么“我的 free() 是对标准库 free() 的两次调用”。 为什么要打两次免费电话? 您应该只需要拨打一次。
请发布您的adds(); 和 free() 函数。
Why does "my free() is two calls to the standard library free()." Why are you calling free twice? You should only need to call once.
Please post your adds(); and free() functions.