当使用任何语言的指针要求某人使用多个指针时,让我们说一个三指针。何时使用三指针而不仅仅使用常规指针是有意义的?
例如:
char * * *ptr;
而不是
char *ptr;
答案 0 :(得分:57)
每个星应该被读作“指针指向”所以
char *foo;
是“由指针foo指向的char”。然而
char *** foo;
是“指针指向指向foo的指针的指针”。因此foo是一个指针。在该地址是第二个指针。在指向的地址是第三个指针。取消引用第三个指针会产生一个char。如果这就是它的全部内容,很难为此做出很多贡献。
但仍然可以完成一些有用的工作。想象一下,我们正在编写bash或其他一些过程控制程序的替代品。我们希望以面向对象的方式管理流程的调用......
struct invocation {
char* command; // command to invoke the subprocess
char* path; // path to executable
char** env; // environment variables passed to the subprocess
...
}
但我们想做一些奇特的事情。我们想要一种方法来浏览每个子进程看到的所有不同的环境变量集。为此,我们将调用实例中的每组env
成员收集到一个数组env_list
中,并将其传递给处理该函数的函数:
void browse_env(size_t envc, char*** env_list);
答案 1 :(得分:11)
如果你在C中使用“对象”,你可能会这样:
struct customer {
char *name;
char *address;
int id;
} typedef Customer;
如果你想创建一个对象,你可以这样做:
Customer *customer = malloc(sizeof Customer);
// Initialise state.
我们在这里使用指向struct
的指针,因为struct
参数是按值传递的,我们需要使用一个对象。 (另外:Objective-C,一种面向对象的C语言包装器语言,使用内部但可见的指向struct
的指针。)
如果我需要存储多个对象,我使用数组:
Customer **customers = malloc(sizeof(Customer *) * 10);
int customerCount = 0;
由于C 中的数组变量指向到第一个项目,我再次使用指针....现在我有双指针。
但现在想象我有一个过滤数组并返回一个新数组的函数。但想象它不能通过返回机制,因为它必须返回错误代码 - 我的函数访问数据库。我需要通过引用参数来完成它。这是我的功能签名:
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);
如果您的应用用于每个级别使用矩阵的酒店,您可能需要一个矩阵阵列:
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);
...安排在一个矩阵(某种大型酒店公司?):
int fetchHotelMatrix(struct customer *******hotelMatrix, int *rows, int *columns, int *levels, int *hotelRows, int *hotelColumns);
我想说的是,您可以想象多个间接的疯狂应用程序。如果多指针是个好主意并决定使用它们,请确保使用typedef
。
(这篇文章是否算作SevenStarDeveloper的申请?)
答案 2 :(得分:5)
指针只是一个保存内存地址的变量。
因此,当您想要保存指针变量的地址时,可以使用指向指针的指针。
如果要返回指针,并且您已经在使用返回变量,则会传入指针的地址。然后该函数取消引用此指针,以便它可以设置指针值。即该函数的参数是指向指针的指针。
多级间接也用于多维数组。如果要返回二维数组,可以使用三重指针。当将它们用于多维数组时,尽管在遍历每个间接层时都要小心地进行强制转换。
以下是通过参数返回指针值的示例:
//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"));
答案 3 :(得分:5)
ImageMagicks的Wand有一个声明为
的函数WandExport char* * * * * * DrawGetVectorGraphics ( const DrawingWand *)
答案 4 :(得分:4)
N维动态分配的阵列,其中N> 1。 3,在C中需要三个或更多个间接层。
答案 5 :(得分:3)
双指针的标准用法,例如:myStruct ** ptrptr,作为指针的指针。例如,作为函数参数,这允许您更改调用者指向的实际结构,而不是仅能够更改该结构中的值。
答案 6 :(得分:3)
Char *** foo可以解释为指向二维字符串数组的指针。
答案 7 :(得分:2)
在必要时使用额外级别的间接 - 或指向 - 而不是因为它会很有趣。你很少看到三指针;我不认为我曾经见过一个四重指针(如果我这样做,我的脑子会陷入困境)。
状态表可以由适当数据类型的2D数组表示(例如,指向结构的指针)。当我写一些几乎通用的代码来做状态表时,我记得有一个函数带有一个三指针 - 它代表了一个指向结构的2D数组。哎哟!
答案 8 :(得分:1)
int main( int argc, char** argv );
答案 9 :(得分:1)
封装资源创建的函数通常使用双指针。也就是说,您传入指向资源的指针的地址。然后,该函数可以创建有问题的资源,并将指针设置为指向它。只有当它具有相关指针的地址时才可以这样做,所以它必须是双指针。
答案 10 :(得分:0)
双重间接简化了许多树平衡算法,通常人们希望能够有效地“解密”#34;来自其父级的子树。例如,AVL树实现可能使用:
void rotateLeft(struct tree **tree) {
struct tree *t = *tree,
*r = t->right,
*rl = r->left;
*tree = r;
r->left = t;
t->right = rl;
}
如果没有"双指针",我们将不得不做一些更复杂的事情,比如明确地跟踪节点的父节点以及它是左边还是右边的分支。
答案 11 :(得分:0)
Particularly in single-threaded dialects of C which don't aggressively use type-based aliasing analysis, it can sometimes be useful to write memory managers which can accommodate relocatable objects. Instead of giving applications direct pointers to chunks of memory, the application receives pointers into a table of handle descriptors, each of which contains a pointer to an actual chunk of memory along with a word indicating its size. If one needs to allocate space for a struct woozle
, one could say:
struct woozle **my_woozle = newHandle(sizeof struct woozle);
and then access (somewhat awkwardly in C syntax--the syntax is cleaner in Pascal): (*my_woozle)->someField=23; it's important that applications not keep direct pointers to any handle's target across calls to functions which allocate memory, but if there only exists a single pointer to every block identified by a handle the memory manager will be able to move things around in case fragmentation would become a problem.
The approach doesn't work nearly as well in dialects of C which aggressively
pursue type-based aliasing, since the pointer returned by NewHandle
doesn't
identify a pointer of type struct woozle*
but instead identifies a pointer
of type void*
, and even on platforms where those pointer types would have
the same representation the Standard doesn't require that implementations
interpret a pointer cast as an indication that it should expect that aliasing
might occur.
答案 12 :(得分:0)
使用嵌套动态分配(或指针链接)数据结构时。这些都是由指针链接。
答案 13 :(得分:0)
指针的指针在C ++中很少使用。它们主要有两种用途。
第一个用途是传递一个数组。例如,char**
是指向char的指针,该指针通常用于传递字符串数组。指向数组的指针不能正常工作,但这是一个不同的主题(如果您想了解更多信息,请参阅comp.lang.c FAQ)。在极少数情况下,您可能会看到第三个*
用于数组数组,但通常更有效的方法是将所有内容存储在一个连续的数组中并手动索引(例如array[x+y*width]
而不是{{1} }})。但是,在C ++中,由于容器类,这种情况不太常见。
第二种用途是通过引用传递。 array[x][y]
参数允许函数修改调用函数指向的整数,通常用于提供多个返回值。这种通过引用传递参数以允许多次返回的模式仍然存在于C ++中,但是,与传递引用的其他用法一样,通常会被引入实际引用所取代。使用C ++参考也可以进行传递引用的另一个原因 - 避免复制复杂的构造。
C ++有第三个因素可以减少多指针的使用:它有int*
。对字符串的引用可能在C中使用类型string
,因此该函数可以更改它传递的字符串变量的地址,但在C ++中,我们通常会看到char**
。
答案 14 :(得分:0)
老实说,我很少看到三重指针。
我浏览了谷歌代码搜索,有some examples,但不是很有启发性。 (见最后的链接 - 所以不喜欢他们)
正如其他人所提到的,你会不时看到双指针。普通单指针很有用,因为它们指向一些已分配的资源。双指针很有用,因为你可以将它们传递给一个函数,并让函数为你填写“普通”指针。
听起来好像你需要一些关于指针是什么以及它们如何工作的解释? 如果你还没有,首先需要了解它。
答案 15 :(得分:0)
当指针实际指向指针时,使用指向指针的指针是有意义的(此链是无限的,因此“三指针”等是可能的)。
创建此类代码的原因是因为您希望编译器/解释器能够正确检查您正在使用的类型(防止出现神秘错误)。
您不必使用这样的类型 - 只要您需要实际取消引用指针并访问指针指向的数据,您总是可以简单地使用简单的“void *”和类型转换。但这通常是不好的做法并且容易出错 - 当然有些情况下使用void *实际上是好的并且使代码更加优雅。把它想象成你的最后一招。
=>它主要是为了帮助编译器确保按照它们应该使用的方式使用它们。
答案 16 :(得分:0)
如果必须修改函数内的指针,则必须传递对它的引用。