在看大型C工程的時候,經常能看到char ** 甚至 void **這樣指向指針的指針,有很多人都不明白,爲什麼要非得用指向指針的指針
其實總結起來,如果你在函數外定義的指針有內容,或者這個內容只是供調用他的函數使用 ,那麼你完全沒有必要使用void **這樣
的方式來訪問你的數據,只需要void * 這樣的指針就行了,但是當我們需要在函數內部修改外部指針時,那麼這時候就顯的尤爲必要
了,總的來說,使用void ** 是因爲我沒要修改或使用指針,而不僅僅使用指針指向的數據。比如我們看個例子來說明下:
假如我們使用指針作爲參數傳遞給一個函數,並希望返回新的指針值,這個時候是錯誤的
char* ptr = NULL;
function(char* p)
{
p = malloc(1024);
//p的內容爲1024個字節的內存起始地址
}
//但是執行到這裏的時候依然是 ptr == NULL;
//並不是我想要得到的結果,說到底,這也是個變量
只有使用指針的指針纔可以實現返回新的指針
char* ptr = NULL;
char** pp= &ptr;
int function(char** pp)
{
*pp = malloc(1024);
//*pp的內容爲1024個字節的內存起始地址
}
//執行到這裏的時候 *pp的內容仍然爲ptr的地址;
//但是*ptr的內容已經指向了新分配的1024的內存空間
上面的例子可能只是說明性的例子,可能還是沒有足夠的說服力,來讓你相信有時候沒有指向指針的指針還真的不好辦!
比如在V4l2應用中的代碼:
int catch_Oneframe(uchar **p_fram,__u32 *fameSize) {
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(m_cameraFd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("VIDIOC_DQBUF");
}
}
else
{
assert(buf.index < n_buffers);
(*p_fram) = (uchar *)buffers[buf.index].start;
*fameSize = buffers[buf.index].length;
//qDebug() << "imagesize is" << framSize << "\n";
}
return SUCCESS;
}
這段代碼中我們希望通過在函數外申明一個uchar *fram的指針來指向我們要獲取的一幀圖像,之後申明瞭一個表示這個圖像的大小的int 型變量。而返回值表示我們到底時成功了還是失敗了。所以實際看到的應用是這樣的:
uchar *p_fram = NULL;
unsigned int size = 0,ret = 0;
ret = catch_Onefram(&p_fram,&size);
if(ret)
transform(p_fram,size);
//do other img processing
else
//return false
有的人會問,可以把函數改寫成返回指針的形式呀,yes,是的可以這樣做,比如改寫成這樣: uchar * catch_Oneframe(int *return_value,__u32 *fameSize); 這樣改寫函數本身是沒有錯誤的,並且能夠正常的工作,但是在C語言編程時保持鏈式表達的支持,這樣寫會有好處的比如說:
uchar *p_fram = NULL;
unsigned int size = 0,ret = 0;
if(catch_Onefram(&p_fram,&size))
transform(p_fram,size);
//do other img processing
else
//return false