已经有很多东西了。他们似乎都暗示你每次调用malloc时都需要做的就是免费调用,并且可能会释放指针的指针"最后 - 所以你不会在它被释放后最终引用该内存
例如,如果我有
int** myPtr
然后我只需要
free(myPtr[j])
为每个j,最后释放指针指针
free(myPtr)
冷却。我在我的程序中已经完成了几次,它看起来工作得很好 - 除了一个案例。我试图弄清楚这种情况有什么不同,我能够在最小程序中复制症状。
#include "stdafx.h"
#include <stdlib.h>
signed char** getPtr()
{
unsigned char n = 10;
unsigned char k = 2;
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));
if (myPtr == NULL) {return NULL;}
for (unsigned char i = 0; i < n; i++)
{
myPtr[i] = (signed char*)malloc(k*sizeof(signed char));
if (myPtr[i] == NULL) {return NULL;}
}
for (unsigned char j = 0; j < n; j++)
{
for (unsigned char k = 0; k <= 1; k++)
{
myPtr[j][k] = 42;
}
}
return myPtr;
}
int _tmain(int argc, _TCHAR* argv[])
{
signed char** potato = getPtr();
if (potato != NULL)
{
for (unsigned char j = 0; j < 10; j++)
{
free(potato[j]);
}
free(potato);
}
return 0;
}
答案 0 :(得分:11)
您的立即问题如下:
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));
这是错误的,因为它为n
字符分配了足够的空间。相反,它应该是:
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char*));
// ^
// char POINTER
char
的大小通常小于指针的大小,但即使不是,也应该使用正确的类型。事实上,我倾向于选择以下形式,以便我不必重复这种形式(重复有可能在将来改变一种,忘记另一种):
signed char** myPtr = (signed char**) malloc (n * sizeof (*myPtr));
除此之外,你应该考虑你实际编码的语言。虽然C和C ++有很多基本的东西,但它们绝不是同一种语言,你编写代码的方式取决于你所针对的是什么。
让我们首先介绍C.在该语言中,您不应该从malloc
转换返回值,因为它可以隐藏某些不调试的微妙错误。放弃演员会给你:
signed char **myPtr = malloc (n * sizeof (*myPtr));
此外,由于sizeof (char)
(裸,有符号和无符号)总是一,因此每当您看到自己乘以时,就更容易丢弃乘法。将其与之前的指南相结合,您可以转向:
myPtr[i] = (signed char*)malloc(k*sizeof(signed char));
更具可读性:
myPtr[i] = malloc (k);
现在,如果您正在编写C ++代码,还需要考虑其他事项。
在C ++中,使用该语言的new
和delete
方面而不是像malloc
和free
这样的传统C语言更为可接受。您已经提到的指南(确保每个delete
都有new
)仍然有效,但确保您在释放数组时使用delete[]
会增加复杂性 of items。
这并不是说malloc
和free
不起作用;它们仍然是C ++语言规范的重要组成部分。只是C ++的处理方式可以更加强大,因为它可以在一次命中中分配和初始化对象,并在内存不足时引发异常,这意味着你没有用NULL
检查来加密您的代码。
此外,C ++在其标准库中提供了许多集合,这些集合使处理事务组比使用原始数组容易得多。其中一个是vector
,基本上是一个可调整大小的数组,您应该考虑在以前使用过数组的情况下使用它。
您展示的代码将更容易实现为字符串向量(C ++字符串,而不是那些微不足道的C字符串)。而且,实际上,我会考虑更进一步,实际上将整个数据结构封装到自己的类中,隐藏它完全使用向量的事实。
如果你这样做,并提供你需要的所有setter / getter方法,你可以稍后替换整个底层数据结构而不会影响使用它的代码。
答案 1 :(得分:5)
您没有为指针指针分配足够的空间。 这样:
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));
应该是:
signed char** myPtr = malloc(n*sizeof(signed char*));
如果malloc
失败,你也会泄漏内存:
for (unsigned char i = 0; i < n; i++)
{
myPtr[i] = (signed char*)malloc(k*sizeof(signed char));
if (myPtr[i] == NULL) {return NULL;}
}
我有点假设您希望此代码的C版本不能完全移植到C ++。可能有更合适的方法在C ++中完成你真正想要做的事情。
答案 2 :(得分:4)
您需要为n
的{{1}} 指针分配空间,而不是n signed char
:
signed char
答案 3 :(得分:3)
您应该使用:
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char*));
^^ The missing *
而不是
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));
否则,您没有为指针分配足够的内存。
当然,您不应该转换malloc
的返回值。它已知会引起问题。有关详细信息,请参阅Specifically, what's dangerous about casting the result of malloc?。
使用:
signed char** myPtr = malloc(n*sizeof(signed char*));
答案 4 :(得分:1)
在getPtr
你:
// 1 byte
malloc n*sizeof(signed char)
但是您存储了一个指向已签名字符的指针,该字符为32或64位,4或8字节。
您可以使用以下方法修复它:
signed char* zz;
signed char** myPtr = (unsigned char)malloc(n*sizeof(zz));
答案 5 :(得分:1)
最简单的方法是使用真正的2D数组,而不仅仅是指向数组的指针数组。您可以像这样分配2D数组:
signed char (*myPtr)[k] = malloc(n*sizeof(*myPtr));
通过此分配,您不需要循环到malloc()
行数组。您可以直接使用2D数组:
for (unsigned char j = 0; j < n; j++)
{
for (unsigned char i = 0; i < k; i++)
{
myPtr[j][i] = 42;
}
}
请注意,即使内存布局有点不同,访问数组元素的方式也没有变化。但是,由于您在一个大块中分配了内存,因此您还可以在一次free()
调用中解除分配:
free(myPtr);
学习C指向数组语法的指针确实是值得的。