I was wondering when we use Pointer to Pointer in C++ and why we need to point to a pointer? I know that when we point to a pointer it means we are saving the memory address of a variable into the memory but I don't know why we need it? Also I have seen some examples that always the use Pointer-to-pointer in creating a Matrix! But why a Matrix may need Pointer to Pointer?
When to use Pointer-to-Pointer in C++?
I'd say it is better to never use it in C++. Ideally, you will only have to use it when dealing with C APIs or some legacy stuff, still related to or designed with C APIs in mind.
Pointer to pointer has pretty much been made obsolete by the C++ language features and the accompanying standard library. You have references for when you want to pass a pointer and edit the original pointer in a function, and for stuff like a pointer to an array of strings you are better off using a std::vector<std::string>. The same applies for multidimensional arrays, matrices and whatnot, C++ has a better way of dealing with those things than cryptic pointers to pointers.
When you want to change the value of variable passed to a function as the function argument, and preserve updated value outside of that function, you require pointer(single pointer) to that variable.
void modify(int* p)
{
*p = 10;
}
int main()
{
int a = 5;
modify(&a);
cout << a << endl;
}
Now when you want to change the value of the pointer passed to a function as the function argument, you require pointer to a pointer.
In simple words, Use ** when you want to preserve (OR retain change in) the Memory-Allocation or Assignment even outside of a function call. (So, Pass such function with double pointer arg.)
This may not be a very good example, but will show you the basic use:
void safe_free(int** p)
{
free(*p);
*p = 0;
}
int main()
{
int* p = (int*)malloc(sizeof(int));
cout << "p:" << p << endl;
*p = 42;
safe_free(&p);
cout << "p:" << p << endl;
}
We basically need pointer to pointer when we want to change the address of the pointer it is pointing to. very good example will be the case of linked list where we send a pointer to pointer to the head node when we try to insert a value to the beginning. Snippet of code pasted below.
int main()
{
/* Start with the empty list */
struct node* head = NULL;
/* Use push() to construct below list
1->2->1->3->1 */
push(&head, 1);
push(&head, 2);
.....
....
}
/* Given a reference (pointer to pointer) to the head
of a list and an int, push a new node on the front
of the list. */
void push(struct node** head_ref, int new_data)
{
/* allocate node */
struct node* new_node = (struct node*) malloc(sizeof(struct node));
.....
.....
}
This is basically because, say a pointer was initially pointing to a memory location 0X100 and we want to change it to point it to some other location say 0X108. In such case pointer to pointer is passed.
You have probably seen int main() before, have you seen this:
int main(int argc, char** argv)
argv is indeed a double pointer, it's not actually a double pointer but it is a pointer to an array of pointers, each pointing to an array of characters pertaining to the command line arguments.
This is not the best example, as you probably want a more practical example. I will write up a better example and edit my post :)
Edit:
If you are familiar with classes and virtual functions then you may also be aware that any class who has a virtual function is automatically given a _vftp member variable.
The _vftp member is a pointer to a list of all the function pointers to your virtual functions. It is inserted at the very beginning of the structure.
If you created a new object as follows:
class myclass
{
public:
//void *_vftp; this is where the _vftp member gets inserted automatically
virtual void vfunc1();
};
void myclass::vfunc1() {printf("yay");}
void main() {
myclass *pMyObject = new myclass();
}
Upon instantiating myclass, the _vftp is added to the object structure and it is the very first variable. Because pMyObject is a pointer to this structure in memory, *pMyObject is eqal to _vftp.
Because _vftp is a pointer to the array of virtual function pointers, *_vftp is equal to vfunc1 (a function pointer).
This means if we dereference pMyObject twice, and call it, we will call vfunc1():
typedef (void* (__thiscall* fnVFunc1))(void);
((fnVFunc)**pMyObject)();
Although this is not a real use for double pointers this is a prime example of applying them. The most common place for double pointers lays in hacking and reverse engineering, where you commonly need to find a pointer in memory and alter whatever it points to.
Anytime you're dealing with C libraries. There are two common answers for the same question in C :
First, anytime you want doubly subscripted array, like :
int main(int argc, char** argv)
Second, anytime you want another return value from a function. There are many functions in libgit2 that do this because they wish to return a meaningful error type as opposed to just null, like the first argument in git_branch_create for example.
You could return a two item struct of course, but that's usually two extra lines of code. In fact, the pointer-to-pointer lets you write the pointer directly into a struct where it'll live.
In C++, you'd avoid using pointers directly whenever suitable C++ data types exist, and my libgit2 example is subsumed by C++'s exceptions, but..
You cannot call C++ from most high level languages, so if you're writing a library that you want available in say Perl, Python, and C++, then you write it in C.
Say you wanna instantiate an object in C++...
MyClass * obj = new MyClass();
You have to do this because new returns a pointer to the allocated object in dynamic memory. The following would be wrong:
MyClass obj = new MyClass(); // wrong. 'new' returns a pointer.
Say you want an array of objects...
MyClass ** objArray = new MyClass*[10];
Related
I was wandering through the code of Sequitur G2P and found a really strange line of code:
public:
...
const Node *childrenEnd() const { return (this+1)->finalized.firstChild_; }
I know that this is a pointer to the current object, and since it is a pointer, the operation is perfectly legal, but what does this+1 actually refer to?
Presumably this is part of an array, so this+1 would refer to the next object in that array.
this is simply a pointer which refers to this object. Since it's a pointer, you can apply pointer arithmetic and even array indexing.
If this object is an element in an array, this+1 would point to the next object in the array.
If it's not, well it's just going to treat whatever is at that memory the same as this object, which will be undefined behaviour unless it is the same type.
As it is NLP it makes sense to optimize memory management. I assume you find overloaded new/delete methods as well.
The this+1 construct assumes all objects reside in an array. The name 'childrenEnd' of the method indicates it returns a pointer to an address of the end of the children of the current node.
Thus you are looking at an implementation of a tree structure. All siblings are adjacent and their children as well.
"this + 1" in C++ class means:
if the "this" object is a member of another object it will point to the address of the parent's object next variable declared just after the "this" object variable:
Example:
class B
{
public:
void* data()
{
return this + 1;
}
};
class A
{
public:
B m_b;
char m_test;
};
int main(int argc, char* argv[])
{
A a;
a.m_test = 'H';
void* p = a.m_b.data();
char c;
memcpy(&c, p, sizeof(char));
return 0;
}
c is equal 'H'.
Long story short it allows to access to parent's class data without passing parent's pointer to the child class. In this example this + 1 point to the m_test member of the class A.
Actually, there is a case, when this thing could be used. I don't recommend to use this method, but it certainly works.
I believe, in NLP code it was used something like that:
when you want your object to behave as a collection (an array etc) to use it similarly as an array with something range-based etc, you can do this trick:
struct Obj {
...
Obj* begin() { return this; }
Obj* end() { return this+1; }
...
}
Now, you can use this object in, for example, range-based for-loops...
Sometimes all that is necessary... but just even there you'd better use "nullptr" or even do refactoring than to use this trick.
I have a function used to initialize array in C++. after the initialization, main can not access the data in the array. Don't know why. Any help?
void testArray(int *listPtr)
{
listPtr=new int[2];
listPtr[0]=0;
listPtr[1]=1;
}// end testArray
void main()
{
int *list;
testArray(list);
cout<<list[0]<<list[1]<<endl; // this gives some random output
} // end main
This is because the pointer is passed by value. The argument to the function is copied, and the first line of your function replaces the local copy of the pointer with the result of the new expression. The original copy of your pointer, back in main(), is unaffected by this.
You can "fix" this by either passing the pointer by reference:
void testArray(int*& listPtr)
{
listPtr = new int[2];
// ...
}
int main()
{
int* list = 0;
testArray(list);
// ...
delete list;
return 0;
}
or by passing a pointer to the pointer:
void testArray(int** listPtr)
{
*listPtr = new int[2];
// ...
}
int main()
{
int* list = 0;
testArray(&list);
// ...
delete list;
return 0;
}
or, better still, by using a C++ standard library container that provides value semantics (in conjunction with a reference argument):
void testVec(std::vector<int>& list)
{
list.resize(2);
list[0] = 0;
list[1] = 1;
}
int main()
{
std::vector<int> list;
testVec(list);
// ...
return 0;
}
Analogy time:
The problem arises because a pointer is a separate entity (object) that points to some other object. Pointers can be copied just as regular objects can, and there is no special consideration given to them to make sure that the thing they point to is updated to reflect any change made to the pointer. A reference is a different beast entirely. Once a reference has been bound to some object, it is (to all intents and purposes) indistinguishable from the object itself; any operation on the reference is an operation on the underlying object. You can think of it as though you possess a cat named Fluffy, and you let your friend borrow Fluffy; but your friend calls her Buffy. It's the same cat, and if your friend trims her claws, the next time you see Fluffy, she'll have trimmed claws.
For the pointer example, you have Fluffy, and you give your friend a note with Fluffy's address written on it. Your friend goes and gets a new cat, and writes the new cat's address on top of the note you gave them. Now, when your friend trims the claws of the new cat, nothing at all happens to Fluffy. The note just allows your friend to go to the place where Fluffy lives; right up to the point where your friend overwrites the note with the address of some other cat.
References make it much easier to reason about the behaviour of your code, and should be preferred in almost all situations.
You need pass by reference, so that the change to the pointer listPtr itself can be passed out to the outter variable. Remember, you are changing the value of "the pointer itself", which is invisible to the caller if pass by value.
void testArray(int * &listPtr)
{
listPtr=new int[2];
listPtr[0]=0;
listPtr[1]=1;
}// end testArray
You need to use pass by reference, so that listPtr get updated while initializing it in testarray function.
To do that do the following -
void testArray(int * &listPtr)
{
listPtr=new int[2];
listPtr[0]=0;
listPtr[1]=1;
}
If you are confused about the above solution you can simply declare and initialize this one globally.
I have been working on linked lists and trees recently. But i am not sure when to declare a function as:
preorder(struct node* root);
or
preorder(struct node** root);
when both work quite the same. To be more precise when do i have to design my function as double pointer and as a single pointer.
Thanks.
P.S: insertion of a node in linked list needs to have double pointer as in:
insert(struct node** root,int value);
unless the root node is defined as a global value. While the preorder works well with a single pointer. If anyone can explain with this as an example it would be highly helpful.
That depends on what preorder() does. If it prints some stuff without modifying the list/tree, you only need a single pointer. If there is a chance that the root will have to be replaced, you need a double pointer.
This is because arguments are passed by value in C. You cannot modify the original variable if a copy of it is passed to your function:
int inc(int x)
{
x = x + 1; // this will never work
}
To get around this, instead of passing in the argument you can pass in the address of that argument (a pointer to it). The function can then dereference the pointer and modify the value it points to.
// usage: inc(&x) where x is an int
int inc(int *ptr)
{
*ptr = *ptr + 1; // this will work
}
With your list/tree, you are already using pointers. This lets you access and modify the pointed-to object (e.g. get/set the next member of the root), but doesn't let you modify the pointer itself (e.g. replace the root with a different node). To do that, another level needs to be introduced, hence the pointer-to-pointer-to-node.
preorder(struct node** root);
Here you pass the address of root, because you may wish to update it withing the function.
preorder(struct node* root);
Here you simply use root to transverse the data structure, without modifying the root.
It's kind of confusing, but I will give it a shot and maybe my way of explaining will make sense to someone :)
Every variable in a function's scope is defined in a standard way, essentially.. (variable type) (variable name). Whether that's:
int foo; // an int called foo
or
char *bar; // a char * called bar
or
struct xyz *blah; // a struct xyz * called blah
and the way you treat foo, bar, and blah are the same when you pass them as arguments to another function. If you want the called function to just look at or use the variables, you can pass them as they are (by value) which creates a copy of the values (an int, or the address of a char, or the address of a struct xyz). So, if you change the value of the int, or the address of the struct xyz in the called function, it is only changed for that local copy of the original variable.
If you want the called function to actually change the value of the original variable (increment foo, malloc memory for bar, or change which element in a list blah points to for example) you need to tell the called function WHERE to make that change (pass them by reference) which results in the called function being declared as f(int *foo) or f(char **bar) or f(struct xyz **blah).
People get caught up on levels of indirection but all that really matters when you're calling another function is what your intentions are with respect to using or changing the variables in the local scope.
You pass a pointer instead when you want to change the thing being passed to the routine. Your confusion arises because the thing is also a pointer.
So if you want to pass a pointer to a routine, and you also want to (potentially) modify the pointer itself, use a double pointer.
If you want to pass a pointer to a routine but all you want to do is change or query what the pointer is pointing to use a single pointer.
That's the difference, do you want to change the pointer or do you want to access what the pointer is pointing to.
Since question is tagged both C and C++, here is a look at the difference from that perspective. This answer does not touch C++ container classes or smart pointers, which should usually be preferred in C++ code. Below are 4 cases, two which can modify caller's struct and caller's pointer, and two which can only modify contents of given struct.
C++ modify pointer
When you want the function to modify a pointer, and have the pointer values returned to the caller in C++, you would do this using a reference to pointer:
void clearNode(struct node *&n){
n->field = 0; // modify caller's struct
n = nullptr; // set caller's pointer to NULL (C++11)
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, np becomes null, n.field becomes 0
clearNode(&np); // will not compile, &np is not right type
clearNode(&n); // will not compile, &n is not lvalue
C modify pointer
In C, same code would be like this (also works in C++, though above version would be better and cleaner):
void clearNode(struct node **n){
(*n)->field = 0; // modify caller's struct
*n = NULL; // set caller's pointer to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not right type
clearNode(&np); // OK, np becomes NULL, n.field becomes 0
clearNode(&n); // will not compile, &n is not of right type
C modify only struct
But if we write same code with just pointer, it will work just a bit differently:
void clearNode(struct node *n){
n->field = 0; // modify caller's struct
n = NULL; // change local parameter, which in this case has no effect anywhere
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, except np is not modified, n.field becomes NULL
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // OK, n.field becomes NULL
C++ modify only struct
And finally, same code in C++ would be cleaner this way:
void clearNode(struct node &n){
n.field = 0; // modify caller's struct
// no pointer, nothing to set to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not of right type
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // will not compile, &n is not of right type
// these work, n.field becomes 0:
clearnode(n);
clearnode(*np);
Your question
So, the thing to take from above is, if you need to modify callers pointer, pass pointer to pointer (C and C++) or refrence to pointer (C++). This comes at a cost: you must always pass a modifiable pointer variable, and double indirection also has small overhead. Syntax for both is shown above.
If you do not need to modify callers pointer, but need to modify the struct contents, pass a pointer (C and C++) or reference (C++) to struct. Syntax for both is shown above.
Third case, when you don't need to modify anything, is not covered above, but has 3 basic alternatives: pass by value (C and C++, clean syntax but copies entire struct), pass by pointer to const (C and C++, a bit uglier syntax but passes just address) or pass by const reference (C++ only, clean syntax and passes only address).
To summarize, use double pointer (or reference to pointer) when you need to modify caller's pointer. Otherwise, pass a pointer (or a reference), or even a value if struct is small.
I use boost shared_ptr to wrap a pointer. However I can only get the correct value in test_shared_ptr(), while in main(), I get the wrong value.
Expected output:
100
100
Actual output:
100
-572662307
It seems that the pointer becomes invalid in that case. Any correct approach to do the job? Thanks in advance.
Below is the source code.
#include <memory>
#include <iostream>
class TestClass
{
public:
TestClass(int &i);
void print_i();
private:
int *_i;
};
TestClass::TestClass(int &i) : _i(&i)
{
}
void TestClass::print_i()
{
std::cout << *_i << std::endl;
}
void print_i(int &i)
{
std::cout << i << std::endl;
}
TestClass *test_shared_ptr()
{
std::tr1::shared_ptr<int> i(new int());
*i = 100;
print_i(*i);
return new TestClass(*i);
}
int main(int argc, char** argv)
{
TestClass *p = test_shared_ptr();
p->print_i();
return 0;
}
You need to pass around the shared pointer, rather than references and pointers directly to the int.
What's happening is the shared pointer is never passed anywhere outside the test_shared_ptr() function. When that function returns, the shared pointer is destroyed. When it sees that nothing else has a reference to it's memory, it destroys the memory it was pointing at.
Basically, where you are using int &i and int *i change both to use std::tr1::shared_ptr<int> i.
You probably need to read up on shared pointer a bit more. Basically, they keep a reference count for the pointer they are pointing to. When they are copied, they up the reference count, and when they are destroyed the decrement it. When the reference count reaches 0 (nothing else is referencing the memory it is pointing at) it frees that memory. So, even though something is using that pointer in your case, because it did not use a shared pointer there is no way for the shared pointer to know that the memory is still being used, so it frees it.
It seems that the pointer becomes invalid in that case
Of course it becomes invalid. shared_ptr gets deleted when you leave test_shared_ptr, and i does not exist after that.
Any correct approach to do the job?
1) simply copy value of i. (use int i instead of int* i in TestClass). int is small, you won't lose anything.
or
2) use std::tr1::shared_ptr<int> instead of int* in TestClass.
The issue you are having is with your API contract.
I don't want to use shared pointer to pass variable values in TestClass's constructor, since I don't want to force the api user to use smart pointer
Your TestClass contract is currently looking like you want the caller to maintain the int item so that it has a lifetime longer than TestClass.
Your test case doesn't follow this contract rule however.
Actually I want to pass object by reference instead of generic type in my application.
Passing by reference or by pointer does not have anything to do with 'generic' type.
Here is a possible fix for your code testing your API, the scope of your int is then longer then sufficiently long (untill the end of the app) to handle all usages within TestClass
TestClass *test_shared_ptr(int &i)
{
i = 100;
print_i(i);
return new TestClass(i);
}
int main(int argc, char** argv)
{
std::tr1::shared_ptr<int> i(new int());
TestClass *p = test_shared_ptr(*i);
p->print_i();
return 0;
}
What you are doing really breaks the point of shared_ptr. Basically when you pass it out of that function is it magically supposed to break and, thus, not free the pointed too memory?
No. It frees it. Are you expecting the shared_ptr to still exist outside of the function so that when "p" drops out of scope it manages to call teh shared_ptr destructor? This can't happen. p is a pointer not a shared_ptr class.
Either return a shared_ptr or return the new'd pointer and delete it yourself.
When does using pointers in any language require someone to use more than one, let's say a triple pointer. When does it make sense to use a triple pointer instead of just using a regular pointer?
For example:
char * * *ptr;
instead of
char *ptr;
each star should be read as "which pointed to by a pointer" so
char *foo;
is "char which pointed to by a pointer foo". However
char *** foo;
is "char which pointed to by a pointer which is pointed to a pointer which is pointed to a pointer foo". Thus foo is a pointer. At that address is a second pointer. At the address pointed to by that is a third pointer. Dereferencing the third pointer results in a char. If that's all there is to it, its hard to make much of a case for that.
Its still possible to get some useful work done, though. Imagine we're writing a substitute for bash, or some other process control program. We want to manage our processes' invocations in an object oriented way...
struct invocation {
char* command; // command to invoke the subprocess
char* path; // path to executable
char** env; // environment variables passed to the subprocess
...
}
But we want to do something fancy. We want to have a way to browse all of the different sets of environment variables as seen by each subprocess. to do that, we gather each set of env members from the invocation instances into an array env_list and pass it to the function that deals with that:
void browse_env(size_t envc, char*** env_list);
If you work with "objects" in C, you probably have this:
struct customer {
char *name;
char *address;
int id;
} typedef Customer;
If you want to create an object, you would do something like this:
Customer *customer = malloc(sizeof Customer);
// Initialise state.
We're using a pointer to a struct here because struct arguments are passed by value and we need to work with one object. (Also: Objective-C, an object-oriented wrapper language for C, uses internally but visibly pointers to structs.)
If I need to store multiple objects, I use an array:
Customer **customers = malloc(sizeof(Customer *) * 10);
int customerCount = 0;
Since an array variable in C points to the first item, I use a pointer… again. Now I have double pointers.
But now imagine I have a function which filters the array and returns a new one. But imagine it can't via the return mechanism because it must return an error code—my function accesses a database. I need to do it through a by-reference argument. This is my function's signature:
int filterRegisteredCustomers(Customer **unfilteredCustomers, Customer ***filteredCustomers, int unfilteredCount, int *filteredCount);
The function takes an array of customers and returns a reference to an array of customers (which are pointers to a struct). It also takes the number of customers and returns the number of filtered customers (again, by-reference argument).
I can call it this way:
Customer **result, int n = 0;
int errorCode = filterRegisteredCustomers(customers, &result, customerCount, &n);
I could go on imagining more situations… This one is without the typedef:
int fetchCustomerMatrix(struct customer ****outMatrix, int *rows, int *columns);
Obviously, I would be a horrible and/or sadistic developer to leave it that way. So, using:
typedef Customer *CustomerArray;
typedef CustomerArray *CustomerMatrix;
I can just do this:
int fetchCustomerMatrix(CustomerMatrix *outMatrix, int *rows, int *columns);
If your app is used in a hotel where you use a matrix per level, you'll probably need an array to a matrix:
int fetchHotel(struct customer *****hotel, int *rows, int *columns, int *levels);
Or just this:
typedef CustomerMatrix *Hotel;
int fetchHotel(Hotel *hotel, int *rows, int *columns, int *levels);
Don't get me even started on an array of hotels:
int fetchHotels(struct customer ******hotels, int *rows, int *columns, int *levels, int *hotels);
…arranged in a matrix (some kind of large hotel corporation?):
int fetchHotelMatrix(struct customer *******hotelMatrix, int *rows, int *columns, int *levels, int *hotelRows, int *hotelColumns);
What I'm trying to say is that you can imagine crazy applications for multiple indirections. Just make sure you use typedef if multi-pointers are a good idea and you decide to use them.
(Does this post count as an application for a SevenStarDeveloper?)
A pointer is simply a variable that holds a memory address.
So you use a pointer to a pointer, when you want to hold the address of a pointer variable.
If you want to return a pointer, and you are already using the return variable for something, you will pass in the address of a pointer. The function then dereferences this pointer so it can set the pointer value. I.e. the parameter of that function would be a pointer to a pointer.
Multiple levels of indirection are also used for multi dimensional arrays. If you want to return a 2 dimensional array, you would use a triple pointer. When using them for multi dimensional arrays though be careful to cast properly as you go through each level of indirection.
Here is an example of returning a pointer value via a parameter:
//Not a very useful example, but shows what I mean...
bool getOffsetBy3Pointer(const char *pInput, char **pOutput)
{
*pOutput = pInput + 3;
return true;
}
And you call this function like so:
const char *p = "hi you";
char *pYou;
bool bSuccess = getOffsetBy3Pointer(p, &pYou);
assert(!stricmp(pYou, "you"));
ImageMagicks's Wand has a function that is declared as
WandExport char* * * * * * DrawGetVectorGraphics ( const DrawingWand *)
I am not making this up.
N-dimensional dynamically-allocated arrays, where N > 3, require three or more levels of indirection in C.
A standard use of double pointers, eg: myStruct** ptrptr, is as a pointer to a pointer. Eg as a function parameter, this allows you to change the actual structure the caller is pointing to, instead of only being able to change the values within that structure.
Char *** foo can be interpreted as a pointer to a two-dimensional array of strings.
You use an extra level of indirection - or pointing - when necessary, not because it would be fun. You seldom see triple pointers; I don't think I've ever seen a quadruple pointer (and my mind would boggle if I did).
State tables can be represented by a 2D array of an appropriate data type (pointers to a structure, for example). When I wrote some almost generic code to do state tables, I remember having one function that took a triple pointer - which represented a 2D array of pointers to structures. Ouch!
int main( int argc, char** argv );
Functions that encapsulate creation of resources often use double pointers. That is, you pass in the address of a pointer to a resource. The function can then create the resource in question, and set the pointer to point to it. This is only possible if it has the address of the pointer in question, so it must be a double pointer.
If you have to modify a pointer inside a function you must pass a reference to it.
It makes sense to use a pointer to a pointer whenever the pointer actually points towards a pointer (this chain is unlimited, hence "triple pointers" etc are possible).
The reason for creating such code is because you want the compiler/interpreter to be able to properly check the types you are using (prevent mystery bugs).
You dont have to use such types - you can always simply use a simple "void *" and typecast whenever you need to actually dereference the pointer and access the data that the pointer is directing towards. But that is usually bad practice and prone to errors - certainly there are cases where using void * is actually good and making code much more elegant. Think of it more like your last resort.
=> Its mostly for helping the compiler to make sure things are used the way they are supposed to be used.
To be honest, I've rarely seen a triple-pointer.
I glanced on google code search, and there are some examples, but not very illuminating. (see links at end - SO doesn't like 'em)
As others have mentioned, double pointers you'll see from time to time. Plain single pointers are useful because they point to some allocated resource. Double pointers are useful because you can pass them to a function and have the function fill in the "plain" pointer for you.
It sounds like maybe you need some explanation about what pointers are and how they work?
You need to understand that first, if you don't already.
But that's a separate question (:
http://www.google.com/codesearch/p?hl=en#e_ObwTAVPyo/security/nss/lib/ckfw/capi/ckcapi.h&q=***%20lang:c&l=301
http://www.google.com/codesearch/p?hl=en#eVvq2YWVpsY/openssl-0.9.8e/crypto/ec/ec_mult.c&q=***%20lang:c&l=344
Pointers to pointers are rarely used in C++. They primarily have two uses.
The first use is to pass an array. char**, for instance, is a pointer to pointer to char, which is often used to pass an array of strings. Pointers to arrays don't work for good reasons, but that's a different topic (see the comp.lang.c FAQ if you want to know more). In some rare cases, you may see a third * used for an array of arrays, but it's commonly more effective to store everything in one contiguous array and index it manually (e.g. array[x+y*width] rather than array[x][y]). In C++, however, this is far less common because of container classes.
The second use is to pass by reference. An int* parameter allows the function to modify the integer pointed to by the calling function, and is commonly used to provide multiple return values. This pattern of passing parameters by reference to allow multiple returns is still present in C++, but, like other uses of pass-by-reference, is generally superseded by the introduction of actual references. The other reason for pass-by-reference - avoiding copying of complex constructs - is also possible with the C++ reference.
C++ has a third factor which reduces the use of multiple pointers: it has string. A reference to string might take the type char** in C, so that the function can change the address of the string variable it's passed, but in C++, we usually see string& instead.
When you use nested dynamically allocated (or pointer linked) data structures. These things are all linked by pointers.
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.
Double indirection simplifies many tree-balancing algorithms, where usually one wants to be able to efficiently "unlink" a subtree from its parent. For instance, an AVL tree implementation might use:
void rotateLeft(struct tree **tree) {
struct tree *t = *tree,
*r = t->right,
*rl = r->left;
*tree = r;
r->left = t;
t->right = rl;
}
Without the "double pointer", we would have to do something more complicated, like explicitly keeping track of a node's parent and whether it's a left or right branch.