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

前端 未结 18 2230
失恋的感觉
失恋的感觉 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: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 
    #include 
    #include 
    
    /* 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;
    }
    

提交回复
热议问题