双指针以及如何修改函数中的指针

时间:2012-03-22 13:18:15

标签: c pointers opencv double-pointer

在这个例子中来自opencv,为什么我们不创建一个简单的变量img(而不是指针)然后在函数cvReleaseImage的参数中使用一个简单的指针(而在这里,我们将使用一个参数中的双指针,因为我们传递了指针的地址:&img):

IplImage* img = NULL; 
img = cvLoadImage(argv[1], CV_LOAD_IMAGE_UNCHANGED);
cvReleaseImage (&img);

此外,当我们在函数中使用简单指针时,我们可以通过向指针添加另一个*来更改指向的值:

例如:

function random(int* pointer, int* pointer2){
    *pointer = *pointer2 / 2;
}

所以用双指针,我们应该这样做吗? :

function random(int** doublepointer, int* pointer2){
    **doublepointer = *pointer2 / 2;
}

感谢您的帮助

5 个答案:

答案 0 :(得分:2)

简单:cvLoadImage()顾名思义,将整个图像加载到内存(考虑10MB文件)并返回IplImage*,表示图像数据在内存中的位置。

这非常有用,因为如果它返回IplImage,我们的应用程序需要分配另外10MB的内存,复制程序内存中的数据!因此,返回带有数据内存地址的指针实际上是一个非常聪明的设计决策。

cvReleaseImage()收到一个反映此设计的双指针。如果您下载OpenCV v2.3源代码,您可以在modules/core/src/array.cpp看到它的实现:

2979 CV_IMPL void
2980 cvReleaseImage( IplImage ** image )
2981 {
2982     if( !image )
2983         CV_Error( CV_StsNullPtr, "" );
2984 
2985     if( *image )
2986     {
2987         IplImage* img = *image;
2988         *image = 0;
2989 
2990         cvReleaseData( img );
2991         cvReleaseImageHeader( &img );
2992     }
2993 }

很明显,内存资源的实际释放是由另外两个辅助函数完成的,这些函数在某些时候会调用cvFree()来释放内存。

但@Nikolai共享的cvReleaseImage()的简化是正确的。

编辑,以回答您的评论。

分配指向0的指针永远不会释放用malloc() / new保留的内存,它只是使指针指向其他地方,在这种情况下,无处可去!让我们理解cvReleaseImage (&img)的含义。一切都始于:

IplImage* img = NULL; 

指针声明与常规变量声明的作用相同:它分配一定量的内存来存储一些数据。像上面那样的指针声明(在32位拱门中)分配4个字节的内存来存储其他变量的地址。换句话说,指针本身在声明的函数中消耗4个字节的内存。

调用cvReleaseImage(&img)会传递指针的地址,而不是它指向的数据的地址(此处为A-HA时刻)。

现在,让我们分析其余的代码:

2985     if( *image ) // does the original pointer points somewhere?
2986     {
             // img copies the address of the data pointed by it's cousing image 
2987         IplImage* img = *image; 
             // and handles the deallocation procedure from now own using img.

             // By clearing the original pointer,
2988         *image = 0; 
             // OpenCV allows us to test for it's release 
             // after cvReleaseImage() executes. 

2989 
2990         cvReleaseData( img );

2991         cvReleaseImageHeader( &img );
2992     }

所以做*image = 0;只是标准程序,所以稍后我们可以检查这样的成功解除分配:

cvReleaseImage (&img);
if (img != NULL)
{
  // OOPS! Something went wrong, memory was not released!
} 

答案 1 :(得分:1)

我相信这里的想法是cvReleaseImage()可以这样做:

void cvReleaseImage( IplImage** ppimg ) {
    /* ... */
    free( *ppimg );
    *ppimg = NULL;
}

即。释放内存并清理原始指针。

答案 2 :(得分:1)

在“release”或“free”函数中传递一个指向指针的指针非常典型,以便用户看到的实际指针(在本例中为img)可以设置为NULL,因此在删除后不会意外使用

是的,你只是双重引用来改变指向指针的数据,但我建议使用括号:

(*(*doublepointer)) = (*pointer)/2;

我觉得它看起来更好。

答案 3 :(得分:1)

关于第一个问题:IplImage的大小在加载之前可能是未知的,而“简单变量”的大小必须在编译时才知道。

答案 4 :(得分:0)

函数cvLoadImage返回一个指向IplImage的指针,因此你不能使用本地定义的IplImage:

IplImage* cvLoadImage( const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR );

cvReleaseImage需要指向IplImage结构的指针的地址。通过执行此操作,他们可以在删除结构时将指针设置为NULL值,以便不会无意中使用已删除的对象。