下面的代码偶尔会在buffer = (char*) realloc(buffer, allocated * sizeof(char));
调用(下面标记为)时失败,我用它为char*
动态分配空间,最初分配1个字符,每次加倍分配的数量我已经拥有的内存不足以存储字符串。
我的项目的许多其他部分都有非常相似的代码,具有相同的内存分配策略和调用(仅更改void*
我传递给realloc
的类型)。
我正在使用VS2010来调试问题,当我在调试模式下启动程序时,该函数总是成功完成。
但是,从命令行调用程序时,很可能在一段时间内出现“访问冲突读取位置”错误后,其中一次realloc调用将失败 - 尽管它不会一直发生,只有在多次调用下面的函数后才会发生,并且已经进行了许多重新分配。
更奇怪的是,如果指针位置发生了变化,我会在realloc调用之前和之后放置一些打印断言,当我这样做并运行程序时,对realloc的调用会随机失败。
我做错了什么?
TOKEN
next_token_file(FILE* file,
STATE_MACHINE* sm,
STATE_MACHINE* wsssm)
{
char* buffer = (char*) malloc(sizeof(char));
size_t allocated = 1;
size_t i = 0;
while(1)
{
/*
... code that increments i by one and messes with sm a bit. Does nothing to the buffer.
*/
// XXX: This fails when using realloc. Why?
if(i + 1 >= allocated)
{
allocated = allocated << 1;
buffer = (char*) realloc(buffer, allocated * sizeof(char));
}
buffer[i] = sm->current_state->state;
/*
... more code that doesn't concern the buffer
*/
}
// Null-terminate string.
buffer[++i] = 0;
TOKEN t = {ret, buffer};
return t;
}
答案 0 :(得分:3)
由于这些行
char* buffer = (char*) malloc(16 * sizeof(char));
size_t allocated = 1;
程序缩减buffer
前4次重新分配。所以程序从i=16
开始写入未分配的内存,这是未定义的行为,所以任何事情都可能发生。此外,这很可能会破坏内存管理,从而导致realloc()
失败。
您可能希望将这两行更改为:
size_t allocated = 16; /* or = 1 if the 16 was a typo. */
char * buffer = malloc(allocated);
其他说明:
sizeof(char)
始终为1
。malloc/calloc/realloc
的结果,因为不需要也不建议:https://stackoverflow.com/a/605858/694576。参考最后一个注释,应该应用以下修改
char * buffer = malloc(allocated);
可能会成为:
char * buffer = malloc(allocated);
if (NULL == buffer)
{
/* Error handling goes here. */
}
和
buffer = (char*) realloc(buffer, allocated * sizeof(char));
可能会成为:
{
char * pctmp = realloc(buffer, allocated);
if (NULL == pctmp)
{
/* Error handling goes here. */
}
else
{
buffer = pctmp;
}
}
答案 1 :(得分:1)
更多的评论而不是答案,但我没有50分可以评论。
此:
char* buffer = (char*) malloc(16 * sizeof(char));
应该是
char* buffer = (char*) malloc(1 * sizeof(char));
或
allocated = 16.
答案 2 :(得分:0)
我不知道,当你增加或减少我。 但我敢打赌,根据这个片段,你的问题是:你的无限重新分配,并且你没有检查realloc是否返回NULL,这将使你的程序崩溃;)
正如已经说过的那样,即使是运行不好的pritf也符合它,你的内存也会受到侵犯。这将通过重新分配已被覆盖范围之外的内存地址来实现(除了其UB之外)
或者如果你尝试工作,如果一个无效的返回值(什么时候返回NULL,可能会发生什么,因为你没有检查它) 或者,如果您请求zerosized区域(大小参数为0)并且您返回非零指针并且您使用该指针。 但第二种情况可能不会发生在你的程序中;)