我有一个函数,它指向指向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]的操作来访问实际值,则会失败。
那么,传递双指针的标准方法是什么。
答案 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表是初始化的吗?