Why use double indirection? or Why use pointers to pointers?

前端 未结 18 2045
失恋的感觉
失恋的感觉 2020-11-22 10:37

When should a double indirection be used in C? Can anyone explain with a example?

What I know is that a double indirection is a pointer to a pointer. Why would I ne

相关标签:
18条回答
  • 2020-11-22 11:19

    If you want to have a list of characters (a word), you can use char *word

    If you want a list of words (a sentence), you can use char **sentence

    If you want a list of sentences (a monologue), you can use char ***monologue

    If you want a list of monologues (a biography), you can use char ****biography

    If you want a list of biographies (a bio-library), you can use char *****biolibrary

    If you want a list of bio-libraries (a ??lol), you can use char ******lol

    ... ...

    yes, I know these might not be the best data structures


    Usage example with a very very very boring lol

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int wordsinsentence(char **x) {
        int w = 0;
        while (*x) {
            w += 1;
            x++;
        }
        return w;
    }
    
    int wordsinmono(char ***x) {
        int w = 0;
        while (*x) {
            w += wordsinsentence(*x);
            x++;
        }
        return w;
    }
    
    int wordsinbio(char ****x) {
        int w = 0;
        while (*x) {
            w += wordsinmono(*x);
            x++;
        }
        return w;
    }
    
    int wordsinlib(char *****x) {
        int w = 0;
        while (*x) {
            w += wordsinbio(*x);
            x++;
        }
        return w;
    }
    
    int wordsinlol(char ******x) {
        int w = 0;
        while (*x) {
            w += wordsinlib(*x);
            x++;
        }
        return w;
    }
    
    int main(void) {
        char *word;
        char **sentence;
        char ***monologue;
        char ****biography;
        char *****biolibrary;
        char ******lol;
    
        //fill data structure
        word = malloc(4 * sizeof *word); // assume it worked
        strcpy(word, "foo");
    
        sentence = malloc(4 * sizeof *sentence); // assume it worked
        sentence[0] = word;
        sentence[1] = word;
        sentence[2] = word;
        sentence[3] = NULL;
    
        monologue = malloc(4 * sizeof *monologue); // assume it worked
        monologue[0] = sentence;
        monologue[1] = sentence;
        monologue[2] = sentence;
        monologue[3] = NULL;
    
        biography = malloc(4 * sizeof *biography); // assume it worked
        biography[0] = monologue;
        biography[1] = monologue;
        biography[2] = monologue;
        biography[3] = NULL;
    
        biolibrary = malloc(4 * sizeof *biolibrary); // assume it worked
        biolibrary[0] = biography;
        biolibrary[1] = biography;
        biolibrary[2] = biography;
        biolibrary[3] = NULL;
    
        lol = malloc(4 * sizeof *lol); // assume it worked
        lol[0] = biolibrary;
        lol[1] = biolibrary;
        lol[2] = biolibrary;
        lol[3] = NULL;
    
        printf("total words in my lol: %d\n", wordsinlol(lol));
    
        free(lol);
        free(biolibrary);
        free(biography);
        free(monologue);
        free(sentence);
        free(word);
    }
    

    Output:

    total words in my lol: 243
    0 讨论(0)
  • 2020-11-22 11:20

    One reason is you want to change the value of the pointer passed to a function as the function argument, to do this 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 allocate(int** p)
    {
      *p = (int*)malloc(sizeof(int));
    }
    
    int main()
    {
      int* p = NULL;
      allocate(&p);
      *p = 42;
      free(p);
    }
    
    0 讨论(0)
  • 2020-11-22 11:23

    For example, you might want to make sure that when you free the memory of something you set the pointer to null afterwards.

    void safeFree(void** memory) {
        if (*memory) {
            free(*memory);
            *memory = NULL;
        }
    }
    

    When you call this function you'd call it with the address of a pointer

    void* myMemory = someCrazyFunctionThatAllocatesMemory();
    safeFree(&myMemory);
    

    Now myMemory is set to NULL and any attempt to reuse it will be very obviously wrong.

    0 讨论(0)
  • 2020-11-22 11:25

    Why double pointers?

    The objective is to change what studentA points to, using a function.

    #include <stdio.h>
    #include <stdlib.h>
    
    
    typedef struct Person{
        char * name;
    } Person; 
    
    /**
     * we need a ponter to a pointer, example: &studentA
     */
    void change(Person ** x, Person * y){
        *x = y; // since x is a pointer to a pointer, we access its value: a pointer to a Person struct.
    }
    
    void dontChange(Person * x, Person * y){
        x = y;
    }
    
    int main()
    {
    
        Person * studentA = (Person *)malloc(sizeof(Person));
        studentA->name = "brian";
    
        Person * studentB = (Person *)malloc(sizeof(Person));
        studentB->name = "erich";
    
        /**
         * we could have done the job as simple as this!
         * but we need more work if we want to use a function to do the job!
         */
        // studentA = studentB;
    
        printf("1. studentA = %s (not changed)\n", studentA->name);
    
        dontChange(studentA, studentB);
        printf("2. studentA = %s (not changed)\n", studentA->name);
    
        change(&studentA, studentB);
        printf("3. studentA = %s (changed!)\n", studentA->name);
    
        return 0;
    }
    
    /**
     * OUTPUT:
     * 1. studentA = brian (not changed)
     * 2. studentA = brian (not changed)
     * 3. studentA = erich (changed!)
     */
    
    0 讨论(0)
  • 2020-11-22 11:26

    Adding to Asha's response, if you use single pointer to the example bellow (e.g. alloc1() ) you will lose the reference to the memory allocated inside the function.

    void alloc2(int** p) {
       *p = (int*)malloc(sizeof(int));
       **p = 10;
    }
    
    void alloc1(int* p) {
       p = (int*)malloc(sizeof(int));
       *p = 10;
    }
    
    int main(){
       int *p = NULL;
       alloc1(p);
       //printf("%d ",*p);//undefined
       alloc2(&p);
       printf("%d ",*p);//will print 10
       free(p);
       return 0;
    }
    

    The reason it occurs like this is that in alloc1 the pointer is passed in by value. So, when it is reassigned to the result of the malloc call inside of alloc1, the change does not pertain to code in a different scope.

    0 讨论(0)
  • 2020-11-22 11:26

    One thing I use them for constantly is when I have an array of objects and I need to perform lookups (binary search) on them by different fields.
    I keep the original array...

    int num_objects;
    OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);
    

    Then make an array of sorted pointers to the objects.

    int compare_object_by_name( const void *v1, const void *v2 ) {
      OBJECT *o1 = *(OBJECT **)v1;
      OBJECT *o2 = *(OBJECT **)v2;
      return (strcmp(o1->name, o2->name);
    }
    
    OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
      int i = 0;
      for( ; i<num_objects; i++)
        object_ptrs_by_name[i] = original_array+i;
      qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);
    

    You can make as many sorted pointer arrays as you need, then use a binary search on the sorted pointer array to access the object you need by the data you have. The original array of objects can stay unsorted, but each pointer array will be sorted by their specified field.

    0 讨论(0)
提交回复
热议问题