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

前端 未结 18 2047
失恋的感觉
失恋的感觉 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:27

    Simple example that you probably have seen many times before

    int main(int argc, char **argv)
    

    In the second parameter you have it: pointer to pointer to char.

    Note that the pointer notation (char* c) and the array notation (char c[]) are interchangeable in function arguments. So you could also write char *argv[]. In other words char *argv[] and char **argv are interchangeable.

    What the above represents is in fact an array of character sequences (the command line arguments that are given to a program at startup).

    See also this answer for more details about the above function signature.

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

    Strings are a great example of uses of double pointers. The string itself is a pointer, so any time you need to point to a string, you'll need a double pointer.

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

    Compare modifying value of variable versus modifying value of pointer:

    #include <stdio.h>
    #include <stdlib.h>
    
    void changeA(int (*a))
    {
      (*a) = 10;
    }
    
    void changeP(int *(*P))
    {
      (*P) = malloc(sizeof((*P)));
    }
    
    int main(void)
    {
      int A = 0;
    
      printf("orig. A = %d\n", A);
      changeA(&A);
      printf("modi. A = %d\n", A);
    
      /*************************/
    
      int *P = NULL;
    
      printf("orig. P = %p\n", P);
      changeP(&P);
      printf("modi. P = %p\n", P);
    
      free(P);
    
      return EXIT_SUCCESS;
    }
    

    This helped me to avoid returning value of pointer when the pointer was modified by the called function (used in singly linked list).

    OLD (bad):

    int *func(int *P)
    {
      ...
      return P;
    }
    
    int main(void)
    {
      int *pointer;
      pointer = func(pointer);
      ...
    }    
    

    NEW (better):

    void func(int **pointer)
    {
      ...
    }
    
    int main(void)
    {
      int *pointer;
      func(&pointer);
      ...
    }    
    
    0 讨论(0)
  • 2020-11-22 11:31

    For instance if you want random access to noncontiguous data.

    p -> [p0, p1, p2, ...]  
    p0 -> data1
    p1 -> data2
    

    -- in C

    T ** p = (T **) malloc(sizeof(T*) * n);
    p[0] = (T*) malloc(sizeof(T));
    p[1] = (T*) malloc(sizeof(T));
    

    You store a pointer p that points to an array of pointers. Each pointer points to a piece of data.

    If sizeof(T) is big it may not be possible to allocate a contiguous block (ie using malloc) of sizeof(T) * n bytes.

    0 讨论(0)
  • 2020-11-22 11:33
    • Let’s say you have a pointer. Its value is an address.
    • but now you want to change that address.
    • you could. by doing pointer1 = pointer2, you give pointer1 the address of pointer2.
    • but! if you do that within a function, and you want the result to persist after the function is done, you need do some extra work. you need a new pointer3 just to point to pointer1. pass pointer3 to the function.

    • here is an example. look at the output below first, to understand.

    #include <stdio.h>
    
    int main()
    {
    
        int c = 1;
        int d = 2;
        int e = 3;
        int * a = &c;
        int * b = &d;
        int * f = &e;
        int ** pp = &a;  // pointer to pointer 'a'
    
        printf("\n a's value: %x \n", a);
        printf("\n b's value: %x \n", b);
        printf("\n f's value: %x \n", f);
        printf("\n can we change a?, lets see \n");
        printf("\n a = b \n");
        a = b;
        printf("\n a's value is now: %x, same as 'b'... it seems we can, but can we do it in a function? lets see... \n", a);
        printf("\n cant_change(a, f); \n");
        cant_change(a, f);
        printf("\n a's value is now: %x, Doh! same as 'b'...  that function tricked us. \n", a);
    
        printf("\n NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' \n");
         printf("\n change(pp, f); \n");
        change(pp, f);
        printf("\n a's value is now: %x, YEAH! same as 'f'...  that function ROCKS!!!. \n", a);
        return 0;
    }
    
    void cant_change(int * x, int * z){
        x = z;
        printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", x);
    }
    
    void change(int ** x, int * z){
        *x = z;
        printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", *x);
    }
    

    Here is the output: (read this first)

     a's value: bf94c204
    
     b's value: bf94c208 
    
     f's value: bf94c20c 
    
     can we change a?, lets see 
    
     a = b 
    
     a's value is now: bf94c208, same as 'b'... it seems we can, but can we do it in a function? lets see... 
    
     cant_change(a, f); 
    
     ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see
    
     a's value is now: bf94c208, Doh! same as 'b'...  that function tricked us. 
    
     NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' 
    
     change(pp, f); 
    
     ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see
    
     a's value is now: bf94c20c, YEAH! same as 'f'...  that function ROCKS!!!. 
    
    0 讨论(0)
  • 2020-11-22 11:33

    A little late to the party, but hopefully this will help someone.

    In C arrays always allocate memory on the stack, thus a function can't return a (non-static) array due to the fact that memory allocated on the stack gets freed automatically when the execution reaches the end of the current block. That's really annoying when you want to deal with two-dimensional arrays (i.e. matrices) and implement a few functions that can alter and return matrices. To achieve this, you could use a pointer-to-pointer to implement a matrix with dynamically allocated memory:

    /* Initializes a matrix */
    double** init_matrix(int num_rows, int num_cols){
        // Allocate memory for num_rows float-pointers
        double** A = calloc(num_rows, sizeof(double*));
        // return NULL if the memory couldn't allocated
        if(A == NULL) return NULL;
        // For each double-pointer (row) allocate memory for num_cols floats
        for(int i = 0; i < num_rows; i++){
            A[i] = calloc(num_cols, sizeof(double));
            // return NULL if the memory couldn't allocated
            // and free the already allocated memory
            if(A[i] == NULL){
                for(int j = 0; j < i; j++){
                    free(A[j]);
                }
                free(A);
                return NULL;
            }
        }
        return A;
    } 
    

    Here's an illustration:

    double**       double*           double
                 -------------       ---------------------------------------------------------
       A ------> |   A[0]    | ----> | A[0][0] | A[0][1] | A[0][2] | ........ | A[0][cols-1] |
                 | --------- |       ---------------------------------------------------------
                 |   A[1]    | ----> | A[1][0] | A[1][1] | A[1][2] | ........ | A[1][cols-1] |
                 | --------- |       ---------------------------------------------------------
                 |     .     |                                    .
                 |     .     |                                    .
                 |     .     |                                    .
                 | --------- |       ---------------------------------------------------------
                 |   A[i]    | ----> | A[i][0] | A[i][1] | A[i][2] | ........ | A[i][cols-1] |
                 | --------- |       ---------------------------------------------------------
                 |     .     |                                    .
                 |     .     |                                    .
                 |     .     |                                    .
                 | --------- |       ---------------------------------------------------------
                 | A[rows-1] | ----> | A[rows-1][0] | A[rows-1][1] | ... | A[rows-1][cols-1] |
                 -------------       ---------------------------------------------------------
    

    The double-pointer-to-double-pointer A points to the first element A[0] of a memory block whose elements are double-pointers itself. You can imagine these double-pointers as the rows of the matrix. That's the reason why every double-pointer allocates memory for num_cols elements of type double. Furthermore A[i] points to the i-th row, i.e. A[i] points to A[i][0] and that's just the first double-element of the memory block for the i-th row. Finally, you can access the element in the i-th row and j-th column easily with A[i][j].

    Here's a complete example that demonstrates the usage:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    /* Initializes a matrix */
    double** init_matrix(int num_rows, int num_cols){
        // Allocate memory for num_rows double-pointers
        double** matrix = calloc(num_rows, sizeof(double*));
        // return NULL if the memory couldn't allocated
        if(matrix == NULL) return NULL;
        // For each double-pointer (row) allocate memory for num_cols
        // doubles
        for(int i = 0; i < num_rows; i++){
            matrix[i] = calloc(num_cols, sizeof(double));
            // return NULL if the memory couldn't allocated
            // and free the already allocated memory
            if(matrix[i] == NULL){
                for(int j = 0; j < i; j++){
                    free(matrix[j]);
                }
                free(matrix);
                return NULL;
            }
        }
        return matrix;
    }
    
    /* Fills the matrix with random double-numbers between -1 and 1 */
    void randn_fill_matrix(double** matrix, int rows, int cols){
        for (int i = 0; i < rows; ++i){
            for (int j = 0; j < cols; ++j){
                matrix[i][j] = (double) rand()/RAND_MAX*2.0-1.0;
            }
        }
    }
    
    
    /* Frees the memory allocated by the matrix */
    void free_matrix(double** matrix, int rows, int cols){
        for(int i = 0; i < rows; i++){
            free(matrix[i]);
        }
        free(matrix);
    }
    
    /* Outputs the matrix to the console */
    void print_matrix(double** matrix, int rows, int cols){
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                printf(" %- f ", matrix[i][j]);
            }
            printf("\n");
        }
    }
    
    
    int main(){
        srand(time(NULL));
        int m = 3, n = 3;
        double** A = init_matrix(m, n);
        randn_fill_matrix(A, m, n);
        print_matrix(A, m, n);
        free_matrix(A, m, n);
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题