C内存分配,结构数组中的分段故障/双自由
据我所知,分段错误是指您尚未正确分配内存,而双重释放是指您试图释放已释放的内存 增加结构数组大小的正确方法是什么?您实际需要释放哪些部分 我有一个结构:C内存分配,结构数组中的分段故障/双自由,c,arrays,free,dynamic-memory-allocation,realloc,C,Arrays,Free,Dynamic Memory Allocation,Realloc,据我所知,分段错误是指您尚未正确分配内存,而双重释放是指您试图释放已释放的内存 增加结构数组大小的正确方法是什么?您实际需要释放哪些部分 我有一个结构: struct Data { // Some variables } 我正在用以下命令初始化这些结构的数组: int curEntries = 100; int counter = 0; struct Data *entries = (struct Data *)malloc(curEntries * sizeof(struct D
struct Data {
// Some variables
}
我正在用以下命令初始化这些结构的数组:
int curEntries = 100;
int counter = 0;
struct Data *entries = (struct Data *)malloc(curEntries * sizeof(struct Data));
当我将bin文件中的数据读入这个数组并填充每个结构时,程序会一直工作到需要100多个结构为止。当时,我有以下代码来重新定位数组:
if (counter == curEntries - 1) { // counter = current index, curEntries = size of the array
entries = (struct Data *)realloc(entries, curEntries * 2 * sizeof(struct Data));
// struct Data *temp = (struct Data *)realloc(entries, curEntries * 2 * sizeof(struct Data));
// free(entries);
// entries = temp;
// free(temp);
}
我现在使用的行(entries=…)可以工作,但显然是错误的,因为我没有释放任何内容,对吗
但是当我尝试使用注释掉的代码时,我得到了一个双重自由错误
最后,(因为有一系列自动测试),显然我也需要在代码的其他部分使用malloc等等。我还需要在哪里分配内存
我现在使用的行(entries=…)可以工作,但显然是错误的,因为我没有释放任何内容,对吗
只有当realloc()
失败时才是错误的。成功后,realloc()
会在必要时自动释放先前分配的块(如果是同一块,则可能不需要,系统可以简单地更改大小)
因此,常见的习语如下:
mytype *var = malloc(...);
// ...
mytype *tmp = realloc(var, ...);
if (!tmp)
{
free(var);
return -1; // or whatever error
}
var = tmp;
// ...
free(var);
首先,请不要使用类似的格式
pointerVar = realloc (pointerVar , newsize); // use the same pointer variable
因为,如果realloc()
失败,您也将擦除实际指针
对于realloc()
失败的情况,从C11
,第§7.22.3.5章
realloc
函数返回。。。如果无法创建新对象,则为空指针
分配的
及
[…]如果无法创建新对象的内存
分配后,旧对象不会被解除分配,其值不变
使用realloc的正确方法是
tempPtr = realloc (oldPtr, newSize);
if ( tempPtr ) //allocation successful, oldPtr is `free()`-d can be reused now
{
oldPtr = tempPtr;
} // and continue using `oldPtr`
else
{
// some error handling
// can still make use of `oldPtr`
}
这就是说,
realloc()
引用同一章中的C11
realloc
函数解除分配由ptr
指向的旧对象,并返回
指向新对象的指针,该对象的大小由size
指定
所以,如果您的代码被注释掉了
struct Data *temp = (struct Data *) realloc(entries, curEntries * 2 * sizeof(struct Data));
//assume success, memory pointed to by entries will be automatically freed
free(entries);
// now, you're trying to free already freed memory, UB....
entries = temp;
free(temp);
由于对realloc()
的调用成功,因此上一个指针已被释放,而您调用free(entries)
,因此会出现双重释放错误。库有时可以确定某个块已被释放,但这种健全性检查并不总是有效的。在这方面,C标准不提供任何保证,将释放的指针传递到free()
具有未定义的行为
在具有内存保护的系统上,当您尝试读取或写入尚未分配给进程的内存地址或已对进程无效的内存地址时,可能会发生分段故障。在库确定已释放块之前,取消对已释放块的指针的引用可能会导致分段错误
重新分配阵列的方案应如下所示:
size_t curEntries = 100; // size of the array
size_t counter = 0; // current index
...
if (counter == curEntries) {
// array is full, try and reallocate to a larger size
size_t newSize = curEntries * 2;
struct Data *newArray = realloc(entries, newSize * sizeof(*newArray));
if (newArray == NULL) {
// cannot reallocate, out of memory.
// handle this error, entries is still valid.
abort();
} else {
// array was reallocated possibly to a different address
// entries is no longer a valid pointer
entries = newArray; // update array pointer
curEntries = newSize; // update number of entries
}
}
而且。。。“内存错误”只是指“某种内存相关的错误”,可能由任何原因引起。“双重自由”并不是一个正式的术语,这里的信息是:。顺便说一句,curEntries*2
-->(curEntries*=2)
,这样如果条件检查realloc是否失败?你能解释一下为什么你会在那个时候释放(var),你不想保留它吗,因为没有成功的realloc?你可以保留它,只是大多数时候,原始大小的块对你的程序没有帮助,所以你free()
它并指出错误。你说如果realloc失败,我会擦除指针,但在C11中,我不需要担心,因为“旧对象未被释放”,对吗?先生,为什么malloc sizeof(*newArray)而不是sizeof(newArray)?@snr:t*p=malloc(count*sizeof(*p))
是分配类型为T
的count
元素数组的更安全的方法。使用sizeof(*p)
,由p
指向的对象的大小是正确的,并且不取决于p
的类型。它避免了p
的定义与分配大小中使用的类型之间的潜在不一致sizeof(newArray)
将是指针的大小,而不是它所指向的结构的大小。感谢我得到的,我将这样做
size_t curEntries = 100; // size of the array
size_t counter = 0; // current index
...
if (counter == curEntries) {
// array is full, try and reallocate to a larger size
size_t newSize = curEntries * 2;
struct Data *newArray = realloc(entries, newSize * sizeof(*newArray));
if (newArray == NULL) {
// cannot reallocate, out of memory.
// handle this error, entries is still valid.
abort();
} else {
// array was reallocated possibly to a different address
// entries is no longer a valid pointer
entries = newArray; // update array pointer
curEntries = newSize; // update number of entries
}
}