快速将双重指针阵列转换为单个指针,可能是连续的



我正在使用将图像返回为大2D数组int**的库。我需要将其转换为int* 1D数组。我认为我已经通过复制内存块来快速执行此操作:

// have int labels** as 2D array, also have rows and cols 
//create 1D array
int *labels1D = new int[rows*cols];
//copy contents
for(int i = 0; i < rows; i++) {        
    // Here I don't know anything about how those arrays were allocated
    // Maybe std::copy would handle it for me?
    std::copy_n(labels[i], cols, labels1D + i*cols);
}

那么第一个问题我是否可以在这里做得更好?假设图书馆是黑匣子吗?


我不想修改库代码,但是我还发现了如何创建 this->currentLabels中的源数组:

int** currentLabels; //in class declaration
...
// in the code
this->currentLabels = new int*[this->height];
for (int i = 0; i < this->height; ++i) {
    this->currentLabels[i] = new int[this->width];
    for (int j = 0; j < this->width; ++j) {
     // some code for setting the value
        }
    }

看来已知行和col的值。

所以第二个问题是:我可以修改此代码以使其在一个内存块中分配2D数组:

this->currentLabels = malloc(nrows*sizeof(int*) + (nrows*(ncolumns*sizeof(int)));

允许我然后以某种方式将其映射到我的1D数组而不复制内存?


编辑:感谢@samvarshavchik,该映射似乎以以下方式工作:

// Allocate 2-D array as one block:
// Allocate pointers:
int** labels = new int*[rows];
// Allocate data:
auto ptr=new int[rows*cols];
for(int i = 0; i < rows; i++) {
    labels[i] = &ptr[i*cols];
}
// fill with values ranging 0 to certain number
for(int i = 0; i < rows; i++){
    for(int j = 0; j < cols; j++){
        // the code for setting the values
        labels[i][j] = i+j;
    }
}    
// have int labels** as 2D array, also have rows and cols 
//create 1D array
int *labels1D; // = new int[rows*cols];
//assign contents:
labels1D = &labels[0][0];

在图书馆代码中销毁它的正确方法似乎是

delete[] ptr;  //user2079303 fixed
delete[] labels;

所以第一个问题是我在这里是否可以做得更好?

您可以使用std::vector使内存管理更安全,更简单。我看不到太多要改进。

问题是我需要将int *发送到另一个对象(OpenCV Mat构造器),因此我完全受到这些类型的限制。谢谢!

这不是问题。您可以使用Vector的data成员功能,该功能将返回可以发送到另一个项目的内部数组的指针。


所以第二个问题是:我可以修改此代码以使其在一个内存块中分配2D数组:

我假设您绑定到需要您传递int**的接口。

如果您可以接受两个分配,这很简单:首先分配适当尺寸的指针数组。然后分配一个包含所有值的平面数组,并将其分配给指针数组的第一个元素。然后将其余的指针分配以纠正值数组的位置。

单个分配是可能的,但很棘手。您可以将原始的char数组分配到足够大的指针和值数组的数组,并使用新的位置进行构造。这很棘手,因为它是非常低的水平,并且您必须确保阵列正确对齐,并且必须分配额外的空间以使对齐成为可能。这将在具有aligned_alloc的C中更容易实现(似乎也在即将到来的C 17中)。


在图书馆代码中销毁它的正确方法似乎是

delete ptr;
delete labels;

不,这似乎是错误的。删除用new[]分配的内存的正确方法是delete[]

您可能会通过使用指针算术而不是数组访问获得一些改进。

我们可能会使用指针跟踪我们的源和目标,并在循环的每个通过时将它们递增,这样我们就可以保存乘法。使用每个相关指针进行操作也具有消除对变量i的需求的优势,从而节省了涉及它的所有操作,只需计算最终指针即可。还要检查不等式的速度通常比"小于"比较要快。

//create 1D array
int *labels1D = new int[rows*cols];
//copy contents
int *targetPointer = labels1D;
int **sourcePointer = labels;
int *endTargetPointer = targetPointer + rows*cols;
while( targetPointer != endTargetPointer) {        
    std::copy_n(*sourcePointer++, cols, targetPointer );
    targetPointer += cols;
}

,如果某些优化器能够从OP的原始代码获得这样的代码,我不会感到惊讶。

最新更新