【发布时间】:2017-05-17 11:28:05
【问题描述】:
我做了一个函数来创建一个像这样的连续二维数组:
void** create2DArray(int row, int col, size_t s) {
void *pool = malloc(s * row * col);
void **array = malloc(s * row);
if(pool==NULL || array==NULL) return NULL;
for(int i=0;i<row;i++) {
array[i] = pool + i * col * s;
}
return array;
}
上面的函数是这样使用的:
int **edge_matrix = create2DArray(num_vertices, num_vertices, sizeof(int));
它可以正常工作。但是有一天,我以为我做错了,我把一行代码改成了这样:
array[i * s] = pool + i * col * s;
由于指针算术规则,void* 将始终增加 i * 1 个字节。我改变了它,所以它会增加 i * s 字节,就像非 void* 类型的通常指针算术一样。但是为什么第一个有效而第二个无效呢?
【问题讨论】:
-
因为
void**不是void*。*array的类型为void*(即是一个指针)而不是void。此外,您可能希望实现更强大的错误检查。 -
如果
pool或array分配失败而另一个分配成功,您永远不会取消分配第一个的内存并最终导致内存泄漏。当然这是一个边缘案例。 -
您的代码中没有二维数组,也没有任何可以指向的数组!
int **之类的东西(更糟糕的是:void **是一个完全不同的数据结构。不要对类型转换过于花哨!这样的代码很难维护和理解。它也容易出现类型错误。 -
扩展我的评论:二维数组会让这一切变得不必要。
-
“由于指针运算规则,
void*将始终增加 i * 1 字节” - 仅供参考,pool上的指针运算,void*无论如何都不是标准的。一些(绝不是全部)工具链支持它作为非标准扩展,but it is not standard.