首先,我不是C编程的专家,我现在正在阅读一些遗留的C代码。在那里,我找到了以下函数来初始化2D矩阵:
long int **computeDistanceMatrix(void){
long int i;
long int j;
long int ** matrix;
matrix = malloc(sizeof(long int) * numberOfCities * numberOfCities +
sizeof(long int *) * numberOfCities);
if(matrix == NULL){
fprintf(stderr, "Out of memory, exit.");
exit(1);
}
for (i = 0; i < numberOfCities; i++){
matrix[i] = (long int*) (matrix + numberOfCities) + i * numberOfCities;
for (j = 0; j < numberOfCities; j++){
matrix[i][j] = distanceFunction(i, j);
}
}
return matrix;
}
我发现代码有点奇怪,因为我期待more similar to this这个似乎对我更清楚的东西。无论如何,我想知道以下内容:
malloc(sizeof(long int) * numberOfCities * numberOfCities + sizeof(long int *) * numberOfCities)
表示他们是为数据项分配内存还是指向每行的指针?matrix[i] = (long int*) (matrix + numberOfCities) + i * numberOfCities
?我真的没有得到他们想做的事。答案 0 :(得分:5)
据我所知,到目前为止人们只提出了二维矩阵的仿真。
自C99起,C具有可变长度数组VLA的概念,允许分配具有动态边界的适当2D矩阵。由于通常这些对于堆栈而言太大,您必须通过malloc
分配它们,如下所示:
double (*A)[n] = malloc(sizeof(double[n][n]));
没有复杂的指针指针方案指针,只需要一个连续对象的单个分配。然后,您可以像A[i][j]
一样访问该矩阵的元素,并且编译器正在为您执行所有索引计算。
所以无论何时你(你没有遗留代码强加指针指针,你有一个支持C99的编译器)你应该使用它。它更简单,更不容易出错,效率更高。
答案 1 :(得分:2)
鉴于sizeof (long int) = l
,n
个城市和sizeof (long int *) = p
,这段代码尝试与the article you link to in your question完全相同。只是,它尝试通过一次调用malloc
而不是多次调用来实现。
分配的第一个np
字节用于保存n
指针。这些指针中的每一个指向一个nl
长整数的块。当然,long int
块都是相邻的,第一个块本身与n
块,p大小的指针相邻,并从地址matrix + np
开始。
该行:
matrix[i] = (long int*) (matrix + numberOfCities) + i * numberOfCities
..设置每个n
指针以指向块内的正确位置。并且希望以下的ASCII艺术足够清楚;)
(addr = matrix +) 0 p 2p .. np np+nl np+2nl
[matrix]-------->[ v v v .. ^ ^ ^
| | | | | |
|____|____|_____| | |
|____|__________| |
|________________|
我不知道这种“优化”(以降低可读性为代价)是否带来优势。有些可能是:
它可能会减少malloc
实施所需的簿记量。但是还增加了成本,因为我们现在自己计算指针值。
整个2D数组可以在一个free
调用中被删除(当然,程序员释放代码时应该知道一个free
调用就是他所有的问题/她必须制作)。
可能有优势w.r.t.缓存。阵列在一个区块中,空间局部性发挥作用。另一方面,多个malloc
调用可能会返回远离彼此的块。
答案 2 :(得分:1)
matrix[i] = (long int*) (matrix + numberOfCities) + i * numberOfCities;
就像你自己说的那样 - 他们为数据和指针分配内存,数据将是顺序的。但是分配数据是不够的,因为指针没有初始化(指向垃圾)所以现在他们必须将指针设置为实际指向数据。
重要的是要理解他们所做的是首先你拥有所有指针,然后只有数据,如下所示:[ptr1,ptr2,ptr3,data1 [],data2 [],data3 []]
所以现在让我们看看第一个指针 - 他应该指向数组的开头,所以如果i=0
那么我们得到matrix[0] = (long int*)(matrix + numberOfCities);
指向数据部分的开头。
对于i=1
,我们在数据部分开头之后得到matrix[0] = (long int*)(matrix + numberOfCities) numberOfCities;
,其中正好是“numberOfCities的一个块”。
答案 3 :(得分:1)
numberOfCities
的{{1}}个matrix
项是long int*
,它们指向允许写matrix[i][j]
以获取元素(i,j)的相应行。以下字节被视为long int
。
答案:
1)是的。
2)matrix+numberOfCities
是指向第一个数据行的指针,但它仍然是long int**
。然后将其转换为long int*
,然后通过i*numberOfCities
元素进一步移动它们(每个元素都为long int
)。
3)您可以将内存分配为单个阵列并执行2D-> 1D索引计算。或者您可以分配指针数组,然后为每一行分配一个数组。或者,您可以分配指针数组,然后为所有数据分配数组,然后将指针设置为数据数组中的相应项,以便每个指针指向其行。
答案 4 :(得分:1)
创建2D数组的一种简单方法是:
long** create2DArray(int rows, int cols)
{
// create an array of long* pointers
long** ptr = (long**) malloc(sizeof(long*) * rows);
for(int i = 0; i < rows; i++)
{
// allocate an array for each row
ptr[i] = (long*)malloc(sizeof(long) * cols));
}
return ptr;
}
int main()
{
long int** ptr = create2DArray();
return 0;
}
答案 5 :(得分:0)
这是动态分配2D数组的另一种方法
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE); //or return here
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE); //or return here
}
}
主要思想是声明指向int的指针。这是你的矩阵(数组)。首先,动态分配大小等于所需的第一个维度。然后动态分配另一个整数指针数组。
你真正需要理解的是,当你在内存中动态分配空间时,没有“维度”。它们只是一些随机的地方。考虑到这一点,你可以分配一个ND维数组并超越二维限制。