Thread: Using Pointers to Multidimensional Arrays

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    3

    Using Pointers to Multidimensional Arrays

    Hi,

    I'm trying to write a simple application to initialise a 2d array, and later manipulate the values by performing some maths on the values.

    I started out trying to use the declaration: double array[5][5], which was working until i needed to pass the array into functions. I then thought i would need to use a double pointer: double **array for this purpose. The application successfully initialises the array with random values, but i am unable to access the values in a later function, "relax".

    I have a suspicion that i am initialising the array using call by value, meaning the global array variable in main is not getting set, resulting in a 'bus error'. If this is the case, i am not sure how to transform this to use call by reference? Of course the problem may be something completely different.

    Thanks in advance.

    --------------------------------------------------------------------------------
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
    
    int main (int argc, const char * argv[]) {
    	
    	double **a;
    	int i, j, n;
    	
    	srand(time(0));
    	
    	n=5;
    	
    	a = createMatrix(a, n);
    	
    	//double val = a[1][1];
    	
    	relax(a);
    	
    }
    
    void createMatrix(double **a, int n)
    {	
    	int i;
    	
    	a = calloc(n, sizeof(double *));
    	for (i = 0; i < n; ++i)
    	{
    		a[i] =  calloc(n, sizeof(double));
    	}
    	
    	populateMatrix(a, n);
    }
    
    void populateMatrix(double **a, int n)
    {	
    	int i,j;
    	
    	printf("\n---------------------------------------------------------------\n");
    	
    	for (i = 0; i < n; ++i)
    	{
    		for (j = 0; j < n; ++j) {
    			a[i][j] = (double) (rand() % 10 + 1);
    			//printf("a[%d][%d] = %lf\n", i, j, a[i][j]);
    			printf("%lf     ", a[i][j]);
    		}
    		printf("\n---------------------------------------------------------------\n");
    	}
    	
    	printf("a[%d][%d] = %lf\n", 1, 1, a[1][1]);
    }
    
    void relax(double **a)
    {
    	int i,j;
    	i=1;
    	j=1;
    	
    	a[i][j] = 725;
    	printf("a[%d][%d] = %lf\n", i, j, a[i][j]);
    	
    	printf("a[0][1] = %lf", a[0][1]);
    	printf("a[1][2] = %lf", a[1][2]);
    	printf("a[1][0] = %lf", a[1][0]);
    	printf("a[2][1] = %lf", a[2][1]);
    	
    	double val = (a[0][1] + a[1][2] + a[1][0] + a[2][1])/4;
    	printf("relax: a[1][1] = %lf", val);
    	
    }
    Last edited by shepz87; 11-15-2009 at 09:04 AM.

  2. #2
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    By referene you want to pass the pointer of the type you want. What is the type you want? You want "double**". So you would pass "double***".

    Code:
    void createMatrix(double ***a, int n)
    {		
    	*a = calloc(n, sizeof(double *));
            ...
    Note, that populate array is fine, because you don't change the variable passed. You don't change "a", but the elements it points to, which is fine.

    I need to point out that C++ is much better for these things. It allows you to pass by reference without changing your code
    Code:
    void createMatrix(double& **a, int n)
    {		
    	a = calloc(n, sizeof(double *));
            ...

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    I'm surprised your compiler didn't complain about the "a = createMatrix(a, n);" in main(), because you're trying to assign an integer to a pointer. You really need to prototype all your functions before you use them; that will help your compiler catch some of the problems in your code. Once you do this you'll probably realize what's going wrong.

    If you're using gcc, always build with at least the -Wall option. If you're on another compiler, figure out how to enable higher warning levels. Do not ignore warnings, for they tend to reveal real problems.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by C_ntua
    By referene you want to pass the pointer of the type you want. What is the type you want? You want "double**". So you would pass "double***".
    However, that would make you a Three Star Programmer. You could avoid this by returning the pointer to a pointer to double instead (and in fact the call of createMatrix() in the main function indicates that this should be the case), but it might be even better to define say:
    Code:
    typedef struct Matrix
    {
        double **entries;
        size_t n, m;
    } Matrix;
    Quote Originally Posted by C_ntua
    I need to point out that C++ is much better for these things. It allows you to pass by reference without changing your code
    Sure, but the parameter should be a double**& instead of a double&**.
    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

  5. #5
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    He actually is trying to assign void to a pointer. Which should give an error, not a warning. But I guess he changed the code without compiling?

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    "3 star programming"...okay I dunno what these clowns are trying to prove today but consider this demo:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    double **alloc_dmatrix (int len, int wid) {
    	int i;
    	double **matrix = malloc(sizeof(double*)*len);
    	for (i=0; i<wid; i++) matrix[i] = malloc(sizeof(double)*wid);
    	return matrix;
    }
    
    void test_assign(double **matrix, int len, int wid) {
    	int i, j;
    	for (i=0;i<len;i++)
    		for (j=0;j<wid;j++) matrix[i][j] = (i+1)*(j+1)/2.0;
    }
    
    
    int main() {
    	double **a = alloc_dmatrix(5,5);
    	int i,j;
    	test_assign(a,5,5);
    	for (i=0;i<5;i++) {
    		for (j=0;j<5;j++) printf("%lf\t\t",a[i][j]);
    		printf("\n");
    	}
    	return 0;
    }
    You pretty much have this correct already, I think.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Nov 2009
    Posts
    3
    Quote Originally Posted by laserlight View Post
    However, that would make you a Three Star Programmer. You could avoid this by returning the pointer to a pointer to double instead (and in fact the call of createMatrix() in the main function indicates that this should be the case), but it might be even better to define say:
    Code:
    typedef struct Matrix
    {
        double **entries;
        size_t n, m;
    } Matrix;

    Sure, but the parameter should be a double**& instead of a double&**.
    Thanks. So just to clarify, i should redefine createMatrix() to return a double**, and then use this as a parameter to my relax function?

    I assume the 'bus error' is being caused by the fact the pointer is null, or something like that?

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by shepz87 View Post
    Thanks. So just to clarify, i should redefine createMatrix() to return a double**, and then use this as a parameter to my relax function?
    [edited]
    Yeah, you must use the return value in this case. To understand why, read C_ntua's next post, #10. Beyond that, as long as you are not assigning anything to the supplied parameter, you can just pass "a" around as a parameter. Note that this:
    Code:
    a[3][4] = 12;
    is an assignment, but it does not reassign a new value to "a" itself. The value of "a" is still a memory address. This is sort of like:
    Code:
    int *x;
    *x =12;
    The value of x (a memory address) did not change. What is changed is the value at that address. If you did this:
    Code:
    void somefunc(int *x) {
          x = 12
    without dereferencing the pointer, that would be a dumb move.
    Last edited by MK27; 11-15-2009 at 12:05 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by shepz87
    So just to clarify, i should redefine createMatrix() to return a double**, and then use this as a parameter to my relax function?
    Yes, that certainly is one way. Look at MK27's example, though it does not illustrate error checking since malloc (and calloc) can return a null pointer.

    Quote Originally Posted by shepz87
    I assume the 'bus error' is being caused by the fact the pointer is null, or something like that?
    Make the change and post the updated code. The major problem with what you posted is that it should not even compile.
    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

  10. #10
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Quote Originally Posted by shepz87 View Post
    Thanks. So just to clarify, i should redefine createMatrix() to return a double**, and then use this as a parameter to my relax function?

    I assume the 'bus error' is being caused by the fact the pointer is null, or something like that?
    To make you understand better. If you do this
    Code:
    void foo(double** a)
    then you will pass a pointer to pointer to double (**). Lets say that pointer has a value of "0xA212". Since in C they are passed by value, a copy will be made. If you do
    Code:
    double** ptr = 0xA212;
    foo(ptr);
    Then you can imagine that the function is like
    Code:
    void foo(double** a)
    {
      a = ptr; //a = 0xA212
      ...
    The function returns. The variable "a" is a local variable, thus not used outside foo. So if you do
    Code:
    void foo(double** a)
    {
      a = calloc(...);
      ...
    Then you assign memory to a local pointer. The pointer is destroyed at the end of the function call and nothing points at the memory. Thus you cannot use the memory allocated. And you have a "memory leak". If you do this
    Code:
    void foo(double** a)
    {
      a = calloc(...);
      ...  
      return a;
    Then as before this will happen
    Code:
    void foo(double** a)
    {
      a = ptr; //a = 0xA212
      a = calloc(...);
      ...
      return a; // return  0xA212, thus return ptr
    So you will return a the memory location (a pointer) that points to the memory allocation. Thus you can use that memory.

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Hey, what C_ntua just said is pretty important. For one thing, it means YOU MUST use the return value of your allocate function (I've edited my last post, where I implied something else) since otherwise allocation involves an assignment to the supplied parameter, breaking the connection between it and the caller.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Nov 2009
    Posts
    3
    Quote Originally Posted by MK27 View Post
    Hey, what C_ntua just said is pretty important. For one thing, it means YOU MUST use the return value of your allocate function (I've edited my last post, where I implied something else) since otherwise allocation involves an assignment to the supplied parameter, breaking the connection between it and the caller.
    Sure, so what i was doing before was useless because i was essentially assigning memory and leaving it there at the end of the function by not returning anything.

    I think what caught me out was not being sure how to return pointers to a double. Being too used to Java and C#it seems unintuitive to add the pointers before the function name!

    The code is now working with suggested changes, thanks all for your help

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That's great! Remember to free the memory allocated when you are done with the matrix.
    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

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Input on arrays and pointers
    By cjohnman in forum C Programming
    Replies: 2
    Last Post: 05-01-2008, 01:57 PM
  2. arrays of pointers to function?????
    By andyzjk in forum C++ Programming
    Replies: 11
    Last Post: 04-17-2005, 09:55 AM
  3. pointers to arrays of structures
    By terryrmcgowan in forum C Programming
    Replies: 1
    Last Post: 06-25-2003, 09:04 AM
  4. Help understanding arrays and pointers
    By James00 in forum C Programming
    Replies: 2
    Last Post: 05-27-2003, 01:41 AM
  5. Hello all and pointers to multi-dimensional arrays
    By Mario in forum C++ Programming
    Replies: 16
    Last Post: 05-17-2002, 08:05 AM