正确使用指针指针

时间:2009-01-22 10:14:29

标签: c pointers

我有一个函数,它指向指向struct的指针。

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]的操作来访问实际值,则会失败。

那么,传递双指针的标准方法是什么。

6 个答案:

答案 0 :(得分:4)

当您将ptr1传递给func时,实际上是在向ptr占用的内存传递指针。问题是func似乎假设ptr1实际指向指针数组的开头,但是你已经向它传递了一个指向只有一个指针的“数组”的指针,{{ 1}}。 ptr可能会对您的筹码造成重大损失。

将指针传递给函数时应该做的是确定该函数是将该指针视为该指针,还是作为指向数组的指针(这里的func似乎就是这种情况)。在后一种情况下,您必须小心确实为函数提供数组。

在你的代码中,我会写

func

顺便说一下,因为C没有数组参数的概念,所以通常最好指定一个具有相关数组长度的附加参数,否则您可能会对缓冲区溢出漏洞敞开心扉。您的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 函数可能已写入func,以更好地反映其打算如何使用其参数。当前的函数签名暗示现实中的func只会使用指针指向指针的指针(尝试快速说三次!)

答案 1 :(得分:3)

从功能界面:

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);

答案 2 :(得分:2)

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实际上不接受数组大小的第二个参数,这可能意味着它要么只接受一定大小的数组(那么,函数的签名应该类似于{{ 1}}),或者,它期望某个元素表示数组的结尾(很可能是func(struct ABC * array[5]))。在这种情况下,你必须做

NULL

另外,另一种解决方案是使用二维数组:

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

答案 3 :(得分:1)

我写过关于如何使用指针和双指针的指南,你可以找到它here,这应该解释一些关于它的基本原理并帮助你前进。

答案 4 :(得分:0)

好吧,你把它标记为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]) );
}

基本上,您不需要做任何太花哨的事情,只需将指针传递给数组的第一个元素,并使用数组的长度。

答案 5 :(得分:0)

使用类型定义使代码阅读更容易:

typedef ABC* ABC_ptr;

然后使用new而不是malloc:

ABC_ptr *dptr2 = new ABC_ptr[2];

您应该能够在func中访问* ptr [0]。你确定初始化的ABC表是初始化的吗?