Thread: Passing double pointer by reference

  1. #1
    Registered User
    Join Date
    Oct 2012
    Posts
    3

    Passing double pointer by reference

    Hi all

    I have a 2D array created by double pointer. I would like to pass my double pointer by reference to a function. However, I tried something like function_name(int **&matrix) but it shows compilation error. So I wonder if there is any alternative way of passing the double pointer by reference?

    I also tried to use triple pointer in order to pass the double pointer by reference but it doesn't work.

    My code is something like this for the triple pointer.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void print(int** a)
    {
        int i, j;
        for(i = 0; i <2; i++){
            for(j=0;j<2;j++)
                printf("%d ", a[i][j]);
            printf("\n");
        }
    }
    
    void fill(int*** a)
    {
        int i, j;
        *a = (int**) malloc(sizeof(int*) * 2);
        for( i = 0; i < 2; i++)
            *a[i] = (int*) malloc(sizeof(int)*2);
    
        for(i = 0; i <2; i++)
            for(j=0;j<2;j++)
                *a[i][j] = 9;
    }
    
    
    int main(int argc, char *argv[])
    {
        int **a;
    
        fill(&a);
        print(a);
        return 0;
    }
    Anyone can help me?
    Last edited by snowmoo; 10-10-2012 at 03:47 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Why do you need to pass a pointer to a pointer by reference?

    Quote Originally Posted by snowmoo
    I also tried to use triple pointer but it doesn't work.
    That would be the way to do it since "pass by reference" translates to "pass a pointer to it" in C, except that so many levels of indirection should generally be avoided.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2012
    Posts
    3
    because I have a 2D array and I am modifying the contents of the 2D array in the function.

    If I don't pass by reference, I don't get the final value outside the function.

  4. #4
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    arrays are not pointers and pointers are not arrays
    I suggest you read section 6 of the comp.lang.c FAQ (and the other sections too).

    This works:
    Code:
    #include <stdio.h>
    
    int dummy = 42;
    int *pdummy = &dummy;
    int **ppdummy = &pdummy;
    
    void pointer_reset(int ***p) { *p = ppdummy; }
    
    int main(void) {
        int **x = NULL;
        pointer_reset(&x);
        printf("pointer reset: %s\n", (x == NULL) ? "FAIL" : "OK");
        return 0;
    }
    ~~~~~~~~

    EDIT: After I saw your code

    The various operators you use for dereference the double (or triple) array have an unexepected grammar.
    Abuse parenthesis

    Code:
    void fill(int*** a)
    {
        int i, j;
        *a = (int**) malloc(sizeof(int*) * 2);
        for( i = 0; i < 2; i++)
            (*a)[i] = (int*) malloc(sizeof(int)*2); // PARENTHESIS AROUND *a
     
        for(i = 0; i <2; i++)
            for(j=0;j<2;j++)
                (*a)[i][j] = 9;                 // PARENTHESIS AROUND *a
    }
    Also you shouldn't cast the return value of malloc, and I prefer to use the object itself for argument to the sizeof operator (and swap the multiplication operands). Your code written by me would be
    Code:
    void fill(int*** a) {
        int i, j;
        *a = malloc(2 * sizeof **a);
        for (i = 0; i < 2; i++) {
            (*a)[i] = malloc(2 * sizeof *(*a)[i]);
        }
    
        for (i = 0; i <2; i++) {
            for (j = 0; j < 2; j++) {
                (*a)[i][j] = 9;
            }
        }
    }
    Last edited by qny; 10-10-2012 at 04:05 AM. Reason: my version of fill()

  5. #5
    Registered User
    Join Date
    Oct 2012
    Posts
    3
    Thanks! Anyway, I found a way to make my code works. Just need to modify

    Code:
     *a[i] = (int*) malloc(sizeof(int)*2);
    to

    Code:
     (*a)[i] = (int*) malloc(sizeof(int)*2);

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by snowmoo
    because I have a 2D array and I am modifying the contents of the 2D array in the function.
    As qny noted, when you pass a 2D array as an argument, it is not passed as a pointer to a pointer. Rather, it is passed as a pointer to the first array of the array of arrays.

    Quote Originally Posted by snowmoo
    If I don't pass by reference, I don't get the final value outside the function.
    Not quite: if you just pass the 2D array, then you are passing by reference because it means that you pass a pointer to the first array.

    Alternatively, you can wrap the 2D array in a struct, then pass a pointer to the struct object instead.

    EDIT:
    Oh, I did not see that you edited your post #1 to include code. In this case, using a struct wrapper is advisable, otherwise it becomes hard to reason about your code. Furthermore, the struct can record the dimensions of the dynamic 2D array.

    Quote Originally Posted by qny
    Your code written by me would be
    I hope you are not a three star programmer when writing your own code
    Last edited by laserlight; 10-10-2012 at 04:08 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User rogster001's Avatar
    Join Date
    Aug 2006
    Location
    Liverpool UK
    Posts
    1,472
    I hope you are not a three star programmer when writing your own code
    I Liked this link
    Thought for the day:
    "Are you sure your sanity chip is fully screwed in sir?" (Kryten)
    FLTK: "The most fun you can have with your clothes on."

    Stroustrup:
    "If I had thought of it and had some marketing sense every computer and just about any gadget would have had a little 'C++ Inside' sticker on it'"

  8. #8
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Quote Originally Posted by laserlight View Post
    Alternatively, you can wrap the 2D array in a struct, then pass a pointer to the struct object instead.

    I hope you are not a three star programmer when writing your own code
    No, I'm not a Three Star Programmer
    As you suggested, I think it's way better to wrap the dynamic array in a struct and pass a pointer around. This is what I do!

  9. #9
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by qny View Post
    As laserlight suggested, I think it's way better to wrap the dynamic array in a struct and pass a pointer around.
    I agree.

    To help the OP, here is my favourite (modified to use ints), using C99 syntax. (I'll probably be scolded by Oogabooga and Adak for going overboard with this, but I believe this to be useful to the OP.)
    Code:
    struct table {
        int rows;
        int cols;
        int cell[];
    };
    
    static inline int table_get(const struct table *const table, const int row, const int col)
    {
        if (table && row >= 0 && col >= 0 && row < table->rows && col < table->cols)
            return table->cell[rows * table->cols + col];
        else
            return 0;
    }
    
    static inline int table_set(const struct table *const table, const int row, const int col, const int value)
    {
        if (table && row >= 0 && col >= 0 && row < table->rows && col < table->cols)
            return table->cell[rows * table->cols + col] = value;
        else
            return 0;
    }
    
    struct table *table_free(struct table *const table)
    {
        if (table && table->rows > 0 && table->cols > 0) {
            /* "Poison" the fields; makes easier to notice use-after-free bugs. */
            table->rows = 0;
            table->cols = 0;
            free(table);
            errno = 0;
    
        } else
            errno = EINVAL;
    
        return NULL;
    }
    
    struct table *table_new(const int rows, const int cols)
    {
        const size_t  cells = (size_t)rows * (size_t)cols;
        const size_t  bytes = cells * sizeof (int);
        const size_t  total = bytes + sizeof (struct table);
        struct table *table;
    
        /* Check for valid size. Uses C99 casting rules
         * to detect overflow. */
        if (rows < 1 || cols < 1 ||
            (size_t)(cells / rows) != (size_t)(cols) ||
            (size_t)(bytes / sizeof (int)) != cells ||
            total < bytes) {
            errno = EINVAL;
            return NULL;
        }
    
        table = malloc(total);
        if (!table) {
            errno = ENOMEM;
            return NULL;
        }
    
        table->rows = rows;
        table->cols = cols;
    
        return table;
    }
    
    #define ROWS(table) ((table)->rows)
    #define COLS(table) ((table)->cols)
    #define CELL(table, row, col) ((table)->cell[ (row) * ((table)->cols) + (col) ])
    
    /* Access to row r, column c is
     *     table->cell[ r * table->cols + c ]
     * The data is in row-major order, the same as in 2D arrays in C.
    */
    and here is an example of how to create a 20-row, 30-column array and fill it with (col + row), with upper left corner (row 0, col 0) zero:
    Code:
        struct table *t;
        int          r, c;
    
        t = table_new(20, 30);
        if (!t) {
            fprintf(stderr, "Not enough memory.\n");
            exit(1);
        }
    
        /* Fill in the table with row+column values */
        for (r = 0; r < ROWS(t); r++)
            for (c = 0; c < COLS(t); c++)
                CELL(t, r, c) = r + c;
    
        /* Print the table contents. */
        for (r = 0; r < ROWS(t); r++) {
            for (c = 0; c < COLS(t); c++)
                printf("%3d", CELL(t, r, c));
            printf("\n");
        }
    
        /* Since t is no longer used, discard it. */
       t = table_free(t);
    When working with 2D tables, the edges are often a headache. Instead of CELL(table,row,column)=value you can use table_set(table,row,column,value) which checks its parameters and does nothing if row,column is outside the table. The same goes for table_get(). Both functions return 0 if outside the table.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Passing void pointer by reference
    By sakura in forum C Programming
    Replies: 3
    Last Post: 08-23-2012, 01:16 AM
  2. Passing structure by reference or pointer?
    By 7force in forum C Programming
    Replies: 8
    Last Post: 12-13-2010, 06:49 PM
  3. Basic Question about passing pointer by reference
    By Vall3y in forum C++ Programming
    Replies: 5
    Last Post: 10-05-2009, 01:44 AM
  4. Passing a pointer as a reference
    By hYph3n in forum C++ Programming
    Replies: 5
    Last Post: 10-04-2006, 01:45 PM
  5. Passing pointer...reference...
    By Cheeze-It in forum C++ Programming
    Replies: 1
    Last Post: 07-21-2002, 07:35 PM

Tags for this Thread