How do pointer to pointers work in C?

前端 未结 14 1278
渐次进展
渐次进展 2020-11-22 02:03

How do pointers to pointers work in C? When would you use them?

相关标签:
14条回答
  • 2020-11-22 02:59

    How it works: It is a variable that can store another pointer.

    When would you use them : Many uses one of them is if your function wants to construct an array and return it to the caller.

    //returns the array of roll nos {11, 12} through paramater
    // return value is total number of  students
    int fun( int **i )
    {
        int *j;
        *i = (int*)malloc ( 2*sizeof(int) );
        **i = 11;  // e.g., newly allocated memory 0x2000 store 11
        j = *i;
        j++;
        *j = 12; ;  // e.g., newly allocated memory 0x2004 store 12
    
        return 2;
    }
    
    int main()
    {
        int *i;
        int n = fun( &i ); // hey I don't know how many students are in your class please send all of their roll numbers.
        for ( int j=0; j<n; j++ )
            printf( "roll no = %d \n", i[j] );
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-22 03:05

    I like this "real world" code example of pointer to pointer usage, in Git 2.0, commit 7b1004b:

    Linus once said:

    I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc.
    For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like:

    
       if (prev)
         prev->next = entry->next;
       else
         list_head = entry->next;
    

    and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.

    People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a

    *pp =  entry->next
    

    Applying that simplification lets us lose 7 lines from this function even while adding 2 lines of comment.

    - struct combine_diff_path *p, *pprev, *ptmp;
    + struct combine_diff_path *p, **tail = &curr;
    

    Chris points out in the comments to the 2016 video "Linus Torvalds's Double Pointer Problem " by Philip Buuck.


    kumar points out in the comments the blog post "Linus on Understanding Pointers", where Grisha Trubetskoy explains:

    Imagine you have a linked list defined as:

       typedef struct list_entry {
           int val;
           struct list_entry *next;
       } list_entry;
    

    You need to iterate over it from the beginning to end and remove a specific element whose value equals the value of to_remove.
    The more obvious way to do this would be:

       list_entry *entry = head; /* assuming head exists and is the first entry of the list */
       list_entry *prev = NULL;
       
       while (entry) { /* line 4 */
           if (entry->val == to_remove)     /* this is the one to remove ; line 5 */
               if (prev)
                  prev->next = entry->next; /* remove the entry ; line 7 */
               else
                   head = entry->next;      /* special case - first entry ; line 9 */
       
           /* move on to the next entry */
           prev = entry;
           entry = entry->next;
       }
    

    What we are doing above is:

    • iterating over the list until entry is NULL, which means we’ve reached the end of the list (line 4).
    • When we come across an entry we want removed (line 5),
    • we assign the value of current next pointer to the previous one,
    • thus eliminating the current element (line 7).

    There is a special case above - at the beginning of the iteration there is no previous entry (prev is NULL), and so to remove the first entry in the list you have to modify head itself (line 9).

    What Linus was saying is that the above code could be simplified by making the previous element a pointer to a pointer rather than just a pointer.
    The code then looks like this:

       list_entry **pp = &head; /* pointer to a pointer */
       list_entry *entry = head;
    
       while (entry) {
           if (entry->val == to_remove)
               *pp = entry->next;
           else
                pp = &entry->next;
           entry = entry->next;
       }
    

    The above code is very similar to the previous variant, but notice how we no longer need to watch for the special case of the first element of the list, since pp is not NULL at the beginning. Simple and clever.

    Also, someone in that thread commented that the reason this is better is because *pp = entry->next is atomic. It is most certainly NOT atomic.
    The above expression contains two dereference operators (* and ->) and one assignment, and neither of those three things is atomic.
    This is a common misconception, but alas pretty much nothing in C should ever be assumed to be atomic (including the ++ and -- operators)!

    0 讨论(0)
  • 2020-11-22 03:05

    When a reference to a pointer is required. For example, when you wish to modify the value (address pointed to) of a pointer variable declared in a calling function's scope inside a called function.

    If you pass a single pointer in as an argument, you will be modifying local copies of the pointer, not the original pointer in the calling scope. With a pointer to a pointer, you modify the latter.

    0 讨论(0)
  • 2020-11-22 03:06

    You have a variable that contains an address of something. That's a pointer.

    Then you have another variable that contains the address of the first variable. That's a pointer to pointer.

    0 讨论(0)
  • 2020-11-22 03:07

    A pointer to a pointer is also called a handle. One usage for it is often when an object can be moved in memory or removed. One is often responsible to lock and unlock the usage of the object so it will not be moved when accessing it.

    It's often used in memory restricted environment, ie the Palm OS.

    computer.howstuffworks.com Link>>

    www.flippinbits.com Link>>

    0 讨论(0)
  • 2020-11-22 03:07

    it's a pointer to the pointer's address value. (that's terrible I know)

    basically, it lets you pass a pointer to the value of the address of another pointer, so you can modify where another pointer is pointing from a sub function, like:

    void changeptr(int** pp)
    {
      *pp=&someval;
    }
    
    0 讨论(0)
提交回复
热议问题