簡體   English   中英

正確使用指針

[英]right usage of pointer to pointer

我有一個函數,它需要指向結構體的指針。

struct ABC;

void func(ABC ** ptr);  //func is provided by someone else and i don't know about the implementation.
{


}

現在,我有以下代碼。

ABC xyz[2];
ABC * ptr = xyz;

ABC **dptr1 = &ptr;     //pointer to ponter

ABC ** dptr2 = (ABC **)malloc(2*sizeof(struct abc*)); //pointer to arrary of pointers

dptr2[0] = &xyz[0];
dptr2[1] = &xyz[1];

如果我將dptr1傳遞給func,並且func執行* ptr [0]和* ptr [1]之類的操作來訪問實際值,它將失敗。

因此,傳遞雙指針的標准方法是什么。

當將ptr1傳遞給func ,實際上是在傳遞指向ptr占用的內存的指針。 問題在於func似乎假設ptr1實際上指向了一個指針數組的開始,但是您已經將它傳遞給了一個僅指向一個指針ptr的“數組”的指針。 func可能會嚴重破壞您的堆棧。

將指針傳遞給函數時,應該確定該函數是將指針視為指針,還是將指針視為數組的指針(在這里func就是這種情況)。 在后一種情況下,必須小心為函數提供一個數組。

在你的代碼中,我會寫

ABC xyz[2];     // two ABC's
ABC * ptrs[2];  // array of pointers to ABC's
ptrs[0] = &xyz[0];
ptrs[1] = &xyz[1];
func(ptrs);    // C compiler convers an array of pointers to
               // a pointer to pointers when passing it to a function 

順便說一句,由於C沒有數組參數的概念,因此通常建議使用具有問題的數組長度指定其他參數,否則您可能會不願處理緩沖區溢出漏洞。 您的func函數可以寫成func(ABC ** ppabc, int elements)以更好地反映它打算如何使用其參數。 當前的函數簽名意味着func實際上將僅使用指向指針的指針所指向的指針(嘗試快三遍!)

從功能界面:

void func(ABC** ptr)
{
}

這可能是兩件事之一。

  • 您正在將指針傳遞給指針
  • 您正在傳遞一個指向二維數組的指針。

差異是細微的。
指向指針的指針表明func()將要更改(* ptr)指向某個對象。 這可能是一些內存分配或其他操作。

如果它是一個二維數組(因為您在問題中也難以理解)

ABC   xyz[2];
ABC*  ptr = xyz;

ABC** dptr1   = &ptr;     //pointer to ponter
// or 
ABC*  dptr1[] = {xyz};    //pointer to an array.
                          //Thus making dptr the 'logical' equivalent of ABC[1][2]


> if i pass dptr1 to func, and func does something like *ptr[0] and *ptr[1] to access the actual values, it fails.

如果傳遞的值是二維數組。 不要將此與此混淆:

ABC  value[1][2];

從技術上講,這也是一個二維數組,但是這兩種形式的內存布局完全不同。 原始數組實際上是ABC數組,而這是真正的二維數組。

ABC   row1[3] = {/*STUFF 1*/};
ABC   row2[3] = {/*STUFF 2*/};
ABC   row3[3] = {/*STUFF 3*/};
ABC*  data[3] = {row1,row2,row3};  // logical ABC data[3][3];

func(data);

C語言中的數組基本上是指針。 唯一真正的區別是,編譯器知道其指向多少個元素。

這意味着,無論您的代碼中期望使用什么指針,都可以改用數組的名稱,因為它將隱式轉換為指向其第一個元素的指針。

如前所述,數組和指針之間的重要區別是sizeof()運算符的結果:對於指針,它將返回存儲指針所需的字節數,對於數組,它將返回存儲指針所需的字節數。元素!

因此,可以使用以下宏來確定數組中元素的數量:

#define count(ARRAY) (sizeof(ARRAY)/sizeof(*ARRAY))

代替*ARRAY ,您也可以使用ARRAY[0]

無論如何,要將數組傳遞給函數,只需將其視為指針即可。 由於編譯器將不知道其包含的元素數量(在轉換過程中會丟失此信息),因此也要傳遞另一個參數來指定該參數:

void func(struct ABC * array, size_t elementCount) {...}

struct ABC anArray[2] = {...};
func(anArray, count(anArray));

我們使用count()宏,以便僅在一個位置更改數組的大小。


那么,為什么您的函數需要雙指針呢? 最有可能允許將數組的元素任意放置在內存中。 因此,如果將元素存儲在普通的舊數組中,則必須對其進行轉換:

struct ABC array[2] = {...};
struct ABC * parray[count(array)];

for(size_t i = 0; i < count(array); ++i)
    parray[i] = &array[i];

另外,如果func確實不接受數組大小的第二個參數,則可能意味着它要么只接受特定大小的數組(然后,函數的簽名應該像func(struct ABC * array[5]) ),或者期望某個元素表示數組的結尾(最有可能為NULL )。 在這種情況下,您必須

struct ABC * parray[count(array) + 1];
parray[count(array)] = NULL;

另外,另一種解決方案是使用二維數組:

struct ABC parray[][1] = {
     { {/* first struct's initializer */} },
     { {/* second struct's initializer */} },
     { {/* third struct's initializer */} }
};

func(parray, count(parray));

我已經編寫了有關如何使用指針和雙指針的指南,您可以在這里找到它,這應該解釋一些有關它的基礎知識並幫助您前進。

好吧,您將其標記為C ++,因此在示例中,我將使用new而不是malloc。 Malloc有點普通的C。如果您真的想正確使用C ++,我建議您實際上使用std :: vector代替。

struct ABC
{
  // some members;
};


void func( ABC* firstElemOfArray, int countOfElementsInArray)
{
  for( int i = 0; i < countOfElementsInArray; ++i )
  {
     ABC* currentElement = firstElemOfArray + i;
     // do something with current elements
  }
}

void useFunc()
{
   ABC array[2] = { new ABC(), new ABC() };

   func( array, sizeof(array/sizeof(array[0]) );
}

基本上,您不需要做任何花哨的事情,只需將指針與數組的長度一起傳遞給數組的第一個元素即可。

使用類型定義使代碼閱讀更容易:

typedef ABC* ABC_ptr;

然后使用new代替malloc:

ABC_ptr *dptr2 = new ABC_ptr[2];

您應該可以在func內部訪問* ptr [0]。 您確定初始ABC表已初始化嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM