用于多级指针解引用?
什么时候使用任何语言的指针需要有人使用多个指针,比方说一个三重指针。 什么时候使用三指针而不是使用常规指针是有意义的?
例如:
char * * *ptr;
代替
char *ptr;
每个星标都应该读作“指针指向的”
char *foo;
是“foo指针指向的char”。 然而
char *** foo;
是“指向指向foo的指针的指针指向的char”。 因此foo是一个指针。 在那个地址是第二个指针。 在指向的地址是第三个指针。 解引用第三个指针会导致char。 如果这就是所有这一切,那很难做出这样的事情。
尽pipe如此,它仍然有可能完成一些有用的工作。 想象一下,我们正在写一个bash的替代品,或者其他一些过程控制程序。 我们希望以面向对象的方式pipe理我们的stream程调用…
struct invocation { char* command; // command to invoke the subprocess char* path; // path to executable char** env; // environment variables passed to the subprocess ... }
但我们想要做一些幻想。 我们希望能够浏览每个子stream程所看到的所有不同的环境variables集。 为此,我们从调用实例env_list
每个env
成员集合到一个数组env_list
,并将其传递给处理该函数的函数:
void browse_env(size_t envc, char*** env_list);
如果你在C中使用“对象”,你可能有这样的:
struct customer { char *name; char *address; int id; } typedef Customer;
如果你想创build一个对象,你可以这样做:
Customer *customer = malloc(sizeof Customer); // Initialise state.
我们在这里使用了一个指向struct
的指针,因为struct
参数是按值传递的,我们需要使用一个对象。 (另外:Objective-C,C语言的一个面向对象的包装语言,在内部使用,但明显地指向struct
的指针。)
如果我需要存储多个对象,我使用一个数组:
Customer **customers = malloc(sizeof(Customer *) * 10); int customerCount = 0;
由于C中的数组variables指向第一项,我再次使用指针…。 现在我有双重的指针。
但现在想象我有一个函数,它过滤数组并返回一个新的。 但想象它不能通过返回机制,因为它必须返回一个错误代码 – 我的function访问数据库。 我需要通过一个引用参数来做到这一点。 这是我的function签名:
int filterRegisteredCustomers(Customer **unfilteredCustomers, Customer ***filteredCustomers, int unfilteredCount, int *filteredCount);
该函数接受一个客户数组,并返回一个客户数组的引用(这是指向一个struct
指针)。 它也取用户的数量,并返回过滤客户的数量(再次,参考论证)。
我可以这样称呼它:
Customer **result, int n = 0; int errorCode = filterRegisteredCustomers(customers, &result, customerCount, &n);
我可以继续想象更多的情况……这个没有typedef
:
int fetchCustomerMatrix(struct customer ****outMatrix, int *rows, int *columns);
显然,我会是一个可怕的和/或残酷的开发者离开这种方式。 所以,使用:
typedef Customer *CustomerArray; typedef CustomerArray *CustomerMatrix;
我可以这样做:
int fetchCustomerMatrix(CustomerMatrix *outMatrix, int *rows, int *columns);
如果您的应用程序在您使用每个级别matrix的酒店中使用,那么您可能需要一个matrix数组:
int fetchHotel(struct customer *****hotel, int *rows, int *columns, int *levels);
或者只是这个:
typedef CustomerMatrix *Hotel; int fetchHotel(Hotel *hotel, int *rows, int *columns, int *levels);
不要让我开始在一系列酒店:
int fetchHotels(struct customer ******hotels, int *rows, int *columns, int *levels, int *hotels);
…排成一个matrix(某种大酒店公司?):
int fetchHotelMatrix(struct customer *******hotelMatrix, int *rows, int *columns, int *levels, int *hotelRows, int *hotelColumns);
我想说的是,你可以想象疯狂的应用程序的多个indirections。 只要确保你使用typedef
如果多指针是一个好主意,你决定使用它们。
(这篇文章是否被视为SevenStarDeveloper的应用程序?)
指针只是一个保存内存地址的variables。
所以当你想要保存一个指针variables的地址的时候,你使用了一个指向指针的指针。
如果你想返回一个指针,并且你已经使用了返回variables的东西,你会传入一个指针的地址。 然后函数取消引用这个指针,这样它就可以设置指针的值。 即该函数的参数将是一个指针的指针。
多维度数组也使用多个间接层次。 如果你想返回一个二维数组,你可以使用三重指针。 当使用它们作为multidimensional array时,虽然要小心地正确转换,因为要经过每个间接级别。
这是一个通过参数返回指针值的例子:
//Not a very useful example, but shows what I mean... bool getOffsetBy3Pointer(const char *pInput, char **pOutput) { *pOutput = pInput + 3; return true; }
你可以这样调用这个函数:
const char *p = "hi you"; char *pYou; bool bSuccess = getOffsetBy3Pointer(p, &pYou); assert(!stricmp(pYou, "you"));
ImageMagicks的魔杖有一个声明为的函数
WandExport char* * * * * * DrawGetVectorGraphics ( const DrawingWand *)
我不是这样做的 。
双指针的标准使用,例如:myStruct ** ptrptr,是作为指针的指针。 例如,作为一个函数参数,这允许你改变调用者所指向的实际结构,而不是只能够改变该结构中的值。
N维dynamic分配数组,其中N> 3,在C中需要三个或更多的间接级别。
Char *** foo可以被解释为一个指向二维string数组的指针。
在必要的时候,你可以使用额外的间接 – 或指向 – 不是因为它很有趣。 你很less看到三分球。 我不认为我曾经见过一个四重指针(如果我这样做,我的脑海里会浮现)。
状态表可以用适当的数据types的二维数组来表示(例如,指向结构的指针)。 当我写了一些几乎generics的代码来完成状态表时,我记得有一个函数需要一个三重指针 – 它代表了一个指向结构的二维数组。 哎哟!
int main( int argc, char** argv );
封装资源创build的函数通常使用双指针。 就是说,你传递一个指向资源的地址。 该函数可以创build有问题的资源,并将指针设置为指向它。 这是唯一可能的,如果它有问题的指针的地址,所以它必须是一个双指针。
如果您必须修改函数内的指针,则必须传递对它的引用。
只要指针实际指向一个指针(这个链是无限的,因此“三指针”等是可能的),使用指向指针的指针是有意义的。
创build这样的代码的原因是因为你希望编译器/解释器能够正确地检查你正在使用的types(防止神秘的错误)。
您不必使用这种types – 只要您需要实际取消引用指针并访问指针所指向的数据,您总是可以简单地使用简单的“void *”和types转换。 但这通常是不好的做法,容易出错 – 当然有些情况下使用void *实际上是好的,使代码更优雅。 想想它更像你最后的手段。
=>它主要是为了帮助编译器确保使用它们应该被使用的方式。
说实话,我很less看到一个三重指针。
我瞥了一下谷歌代码search,有一些 例子 ,但不是很明显。 (见末尾的链接 – SO不喜欢他们)
正如其他人所提到的,你会不时看到双重的指针。 普通单指针是有用的,因为它们指向一些分配的资源。 双指针是有用的,因为你可以将它们传递给一个函数,并为你的函数填充“普通”指针。
这听起来也许你需要一些关于什么是指针和它们是如何工作的解释? 如果你还没有,你首先需要明白。
但这是一个单独的 问题 (:
指针的指针在C ++中很less使用。 它们主要有两个用途。
第一个用途是传递一个数组。 例如, char**
是一个指向char的指针,它通常用于传递一个string数组。 指向数组的指针不能正常工作,但是这是一个不同的主题(如果想了解更多信息,请参阅comp.lang.c常见问题解答 )。 在一些罕见的情况下,你可能会看到第三个*
用于数组数组,但通常更有效的方法是将所有的数据存储在一个连续的数组中,并手工build立索引(例如array[x+y*width]
而不是array[x][y]
)。 然而,在C ++中,由于容器类的原因,这种方法非常less见。
第二个用途是通过引用传递。 int*
参数允许函数修改调用函数指向的整数,通常用于提供多个返回值。 这种通过引用来传递参数以允许多个返回的模式仍然存在于C ++中,但是像其他使用传递引用一样,通常被引入实际引用所取代。 通过引用传递的另一个原因 – 避免复杂的构造 – 也可以用C ++引用。
C ++有第三个因素,减less多个指针的使用:它有string
。 对string的引用可能在C中使用char**
types,以便函数可以更改它传递的stringvariables的地址,但在C ++中,我们通常会看到string&
。
当你使用嵌套dynamic分配(或指针链接)的数据结构。 这些东西都是通过指针链接的。
特别是在C语言的单线程方言中,它不积极地使用基于types的别名分析,编写可容纳可重定位对象的内存pipe理器有时会很有用。 应用程序不是直接将指针指向内存块,而是接收指向一个句柄描述符表的指针,每个指针都包含一个指向实际内存块的指针以及一个指示其大小的单词。 如果需要为struct woozle
分配空间,可以这样说:
struct woozle **my_woozle = newHandle(sizeof struct woozle);
然后访问(在C语法中比较笨拙 – 语法在Pascal中更清晰):(* my_woozle) – > someField = 23; 在调用分配内存的函数时,应用程序不保留直接指向任何句柄的目标是重要的,但是如果只有一个指向每个由句柄标识的块的指针,内存pipe理器将能够移动事物以防碎片化一个问题。
这种方法在C语言的方法中并不能很好地进行基于types的别名,因为NewHandle
返回的指针没有标识struct woozle*
types的指针,而是标识了void*
types的指针,在这些指针types具有相同表示的平台上,标准并不要求实现将指针强制转换为可能会出现别名的指示。
双重间接简化了许多树平衡algorithm,通常人们希望能够有效地将子树与其父节点“断开连接”。 例如,一个AVL树实现可能使用:
void rotateLeft(struct tree **tree) { struct tree *t = *tree, *r = t->right, *rl = r->left; *tree = r; r->left = t; t->right = rl; }
如果没有“双指针”,我们将不得不做更复杂的事情,比如明确地跟踪一个节点的父节点,以及它是左分支还是右分支。