我已经编写了一些在OS X 10.6上运行的C代码,这恰好很慢,所以我使用valgrind来检查内存泄漏等。在这样做时我注意到了一件事:
如果我将内存分配给这样的2D数组:
double** matrix = NULL;
allocate2D(matrix, 2, 2);
void allocate2D(double** matrix, int nrows, int ncols) {
matrix = (double**)malloc(nrows*sizeof(double*));
int i;
for(i=0;i<nrows;i++) {
matrix[i] = (double*)malloc(ncols*sizeof(double));
}
}
然后检查矩阵的存储器地址是0x0。
但是,如果我这样做
double** matrix = allocate2D(2,2);
double** allocate2D(int nrows, int ncols) {
double** matrix = (double**)malloc(nrows*sizeof(double*));
int i;
for(i=0;i<nrows;i++) {
matrix[i] = (double*)malloc(ncols*sizeof(double));
}
return matrix;
}
这很好用,即返回指向新创建的内存的指针。
当我还有free2D函数来释放内存时。它似乎没有正确释放。即指针仍指向与调用free之前相同的地址,而不是0x0(我认为可能是默认值)。
void free2D(double** matrix, int nrows) {
int i;
for(i=0;i<nrows;i++) {
free(matrix[i]);
}
free(matrix);
}
我的问题是:我是否误解了malloc / free的工作方式?否则有人会建议发生什么事情?
亚历
答案 0 :(得分:4)
释放指针时,指针的值不会改变,如果希望它为null,则必须将其显式设置为0.
答案 1 :(得分:3)
在第一个示例中,您只将malloc
返回的指针存储在局部变量中。当函数返回时它会丢失。
C语言中的常规做法是使用函数的返回值将指向已分配对象的指针传递回调用者。正如Armen指出的那样,你也可以传递一个指针,指向函数应该存储输出的位置:
void Allocate2D(double*** pMatrix...)
{
*pMatrix = malloc(...)
}
但我认为大多数人会在看到***
后立即尖叫。
您可能还会认为指针数组不是矩阵的有效实现。分别分配每一行会导致内存碎片,malloc
开销(因为每个分配涉及一些簿记,更不用说你必须存储的额外指针)和缓存未命中。并且每次访问矩阵的元素都涉及2个指针解引用,而不仅仅是一个,这可能会引入停顿。最后,你需要做更多的工作来分配矩阵,因为你必须检查每个malloc
的失败并清理你已经完成的所有事情(如果它们中的任何一个失败)。
更好的方法是使用一维数组:
double *matrix;
matrix = malloc(nrows*ncols*sizeof *matrix);
然后将元素(i,j)作为matrix[i*ncols+j]
访问。潜在的缺点是乘法(在古代cpus上很慢但在现代cpu上很快)和语法。
更好的方法不是寻求过度的普遍性。 SO上的大多数矩阵代码不适用于可能需要任意矩阵大小的高级数值数学,但对于3D游戏,其中2x2,3x3和4x4是任何实际使用的唯一矩阵大小。如果是这种情况,请尝试类似
的内容double (*matrix)[4] = malloc(4*sizeof *matrix);
然后您可以使用单个解除引用和极快的乘常值来访问元素(i,j)为matrix[i][j]
。如果只在本地范围或结构内部需要matrix
,只需将其声明为:
double matrix[4][4];
如果你不是非常熟悉C类型系统和上面的声明,那么最好还是将所有矩阵包装在结构中:
struct matrix4x4 {
double x[4][4];
};
然后声明,指针转换,分配等变得更加熟悉。唯一的缺点是你需要做matrix.x[i][j]
或matrix->x[i][j]
(取决于matrix
是指向struct的指针的结构)而不是matrix[i][j]
。
编辑:我确实想到了将矩阵实现为行指针数组的一个有用属性 - 它使行的排列变得微不足道。如果您的算法需要执行大量行排列,这可能是有益的。请注意,对于小矩阵而言,好处不会太大,而且列排列也不能以这种方式优化。
答案 2 :(得分:1)
在C ++中你应该通过引用传递指针:)
Allocate2D(double**& matrix...)
关于发生了什么 - 你有一个NULL指针,你将该指针的副本传递给分配了mamory的函数,并用新分配的内存的地址初始化指针的副本,但是你的原始指针保持为NULL。至于free,你不需要通过引用传递,因为只有指针的值是相关的。 HTH
由于C中没有引用,您可以通过指针传递,即
Allocate2D(double*** pMatrix...)
{
*pMatrix = malloc(...)
}
后来打电话给
Allocate2D(&matrix ...)