Thread: how can i pass by reference by "malloc 2d array"?

  1. #1
    Registered User
    Join Date
    Apr 2005
    Posts
    77

    how can i pass by reference by "malloc 2d array"?

    the code shows below:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min_range 1
    #define max_range 20
    
    void init(int **a, int *n)
    {
    	int i, j;
    	FILE *f;
    	srand(time(NULL));
    	printf("n = ");
    	scanf("%d", n);
    	a = (int**)malloc((*n)*sizeof(int*));
    	for (i = 0; i < *n; i++)
    		a[i] = (int*)malloc((*n)*sizeof(int));
    	f = fopen("FindMaxValue.dat", "w");
    	fprintf(f, "%d\n", *n);
    	for (i = 0; i < *n; i++) {
    		for (j = 0; j < *n; j++) {
    			a[i][j] = rand()%(max_range-min_range+1)+min_range;	
    			fprintf(f, "%d ", a[i][j]);
    		}
    		fprintf(f, "\n");
    	}
    	fclose(f);
    }
    
    int main()
    {
    	int **a;
    	int n, BestValue;
    	init(a, &n);
    	printf("working...\n");
    	printf("a[0][0] = %d\n", a[0][0]);
    	// BestValue = FindMaxValue(a, n);
    	// printf("%d\n", BestValue);
    	return 0;
    }
    The program was terminated in "printf("a[0][0] = %d\n", a[0][0]);". I think the problem relate the function init. It can't pass the "malloc 2d array" to main function. Please tell me how can i solve the passing 2d array. Thanks.
    [The FindMaxValue function is omitted as it doesn't relate the problem]

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    In your case, just return it.
    Code:
    int **make2darray( int x, int y )
    {
        int **array;
    
        ...allocate it...
    
        return array;
    }
    On an aside, don't typecast malloc. Read the FAQ as to why.

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Apr 2005
    Posts
    77
    Quote Originally Posted by quzah
    In your case, just return it.
    Code:
    int **make2darray( int x, int y )
    {
        int **array;
    
        ...allocate it...
    
        return array;
    }
    On an aside, don't typecast malloc. Read the FAQ as to why.

    Quzah.
    q1) is it right of make2darray function?
    Code:
    int **make2darray(int x, int y)
    {
    	int i;
    	int **array;
    	array = (int**)malloc(x*sizeof(array));
    	for (i = 0; i < y; i++)
    		array[i] = (int*)malloc(y*sizeof(array));
    	return array;
    }
    q2) um... how can i pass by reference in function? The mean that the function like this,
    init(int **2darray, int n). [pass as reference of **2darray]

  4. #4
    Registered User
    Join Date
    May 2005
    Posts
    28
    Quote Originally Posted by Mathsniper
    The program was terminated in "printf("a[0][0] = %d\n", a[0][0]);". I think the problem relate the function init. It can't pass the "malloc 2d array" to main function. Please tell me how can i solve the passing 2d array. Thanks.
    [The FindMaxValue function is omitted as it doesn't relate the problem]
    The problem can be solved as another user posted, just return the array. The reason it doesn't work as is is that you are passing a in by value, and then binding the local (to the init function) value of it to the value returned by malloc. This is the same problem you would see if you passed a char * into a function and then tried to change the char * via assignment, ie saying foo = bar, as opposed to using say strcpy or its ilk.


    Mezzano

  5. #5
    Registered User
    Join Date
    May 2005
    Posts
    28
    Quote Originally Posted by Mathsniper
    q1) is it right of make2darray function?
    q2) um... how can i pass by reference in function? The mean that the function like this,
    init(int **2darray, int n). [pass as reference of **2darray]
    Whats that old saying "All software engineering problems can be solved by adding another layer of abstraction, all performance problems can be solved by removing a layer of abstraction" Anyways, if you make it something hideous like init(int ***2dArray, int n) it should work, of course at the call site you need to pass &a and in the function you would need to say something like *a = malloc, other than that it should work, although imho it would look hideous



    Mezzano

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You don't really need to pass it by reference, unless you plan on creating it, or resizing it, inside the function. Also, in both these cases you can work around it by simply passing as per normal, and returning the new version of it.

    But, just like any other variable, if you need to change it inside a function, pass a pointer to it.

    However, if all you're doing is trying to modify its contents inside a function, just pass it like you normally would any other array. Remember that all arrays are passed "by reference" in effect. Meaning, any changes to the contents of an array inside a function happen to the array outside the function also.

    The exception to this is if again you're trying to resize it, or create it (ie: change what the pointer is pointing at).

    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    May 2005
    Posts
    28
    Quote Originally Posted by quzah
    You don't really need to pass it by reference, unless you plan on creating it, or resizing it, inside the function. Also, in both these cases you can work around it by simply passing as per normal, and returning the new version of it.

    This opens up the ugly decision about who is responsible for freeing the memory, assuming the memory for the original array was alloced. If you have them pass in a pointer to the array as it is and you create a new one and return it, they presumably are expected to overwrite the old pointer with the return value. Has the memory for the old array been freed? Is that the callers responsibility or yours? It almost has to be the callers because you can't be sure the memory was alloced vie malloc/calloc, it could be they pass you a pointer to a stack allocated array and you return a pointer to a heap allocated array. In this case the worry about freeing memory doesn't exist (except on the newly allocated array) but your function can't know not to free the incoming array once the new one is created.


    Mezzano

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    It doesn't really matter actually. In either case you always have to keep track of your own memory. It's your job to know if it failed or not. This is no different than using realloc. You don't assign the return value of realloc before you find out if it failed. The same goes for this scenario.

    In either case, you still have to make sure it didn't fail. Consider:
    Code:
    int func( foo ***bar, int newx, int newy )
    {
        ...resize bar...
    }
    
    if( func( baz, 10, 10 ) != 0 )
    {
        ...resize failed, so the old size should still remain...
    }
    Code:
    foo **func( foo **bar, int newx, int newy )
    {
         ...resize bar...
    }
    
    foo **bar, **baz;
    
    ...
    
    baz = func( bar, 10, 10 )
    
    if( baz == NULL )
    {
        ...resize failed, so don't reassign the pointer...
    }
    else
    {
        bar = baz;
    }
    In either case, they work exactly the same. You test a return value to see if your resize failed. If not, you know that you can't treat it as a different size. If so, you can.

    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    Registered User
    Join Date
    Apr 2005
    Posts
    77
    now, i post my full code below:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min_range 1
    #define max_range 20
    							   
    int **make2darray(int x, int y)
    {
    	int i;
    	int **array;
    	array = (int**)malloc(x*sizeof(int*));
    	for (i = 0; i < y; i++)
    		array[i] = (int*)malloc(y*sizeof(int));
    	return array;
    }
    
    void init(int **a, int n)
    {
    	int i, j;
    	FILE *f;
    	srand(time(NULL));
    	f = fopen("FindMaxValue.dat", "w");
    	fprintf(f, "%d\n", n);
    	for (i = 0; i < n; i++) {
    		for (j = 0; j < n; j++) {
    			a[i][j] = rand()%(max_range-min_range+1)+min_range;	
    			fprintf(f, "%d ", a[i][j]);
    		}
    		fprintf(f, "\n");
    	}
    	fclose(f);
    }
    
    int FindMaxValue(int **a, int n)
    {
    	int i, j;
    	int **valueA;
    	valueA = make2darray(n, n);
    	for (i = 0; i < n; i++)
    		for (j = 0; j < n; j++)
    			valueA[i][j] = 0;
     	
    	for (i = 1; i < n; i++) {
    		valueA[0][i] = a[0][i-1]+a[0][i];
    		valueA[i][0] = a[i-1][0]+a[i][0];
    	}
    	for (i = 1; i < n; i++)
    		for (j = 1; j < n; j++)
    			valueA[i][j] = max(valueA[i][j-1], valueA[i-1][j]) + a[i][j];
    	return valueA[n-1][n-1];
    }
    
    int main()
    {
    	int **a;
    	int n, BestValue;
    	FILE *f;
    	printf("n = ");
    	scanf("%d", &n);
    	a = make2darray(n, n);
    	init(a, n);
    	BestValue = FindMaxValue(a, n);
    	f = fopen("FindMaxValue.out", "w");
    	fprintf(f, "%d\n", BestValue);
    	fclose(f);
    	return 0;
    }
    at this moment, i know why it doesn't work when do this action void init(**array, n);. because the **array was going to destory(free) the memory when it had ran the init function, right? thus i have to allocate at main function.
    but may you tell how that, how can i allocate 2darray at other function and then pass by refernece.

  10. #10
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    We've already told you how to do it. Pass a pointer to it. Also, stop typecasting malloc. Read the FAQ if you want to know why it's wrong.

    Also, why do you think it should destroy any memory in your init function? You don't free anything there. You simply use what you're passing to it. Why would that be destroying anything?

    Why are you making a new array inside of FindMaxValue? Oh, by the way, you don't actually free anything you allocate.


    Quzah.
    Hope is the first step on the road to disappointment.

  11. #11
    Registered User
    Join Date
    May 2005
    Posts
    28
    Quote Originally Posted by quzah
    In either case, they work exactly the same. You test a return value to see if your resize failed. If not, you know that you can't treat it as a different size. If so, you can.

    Quzah.
    Yes, but as I mentioned (I think I did) it is a style decision. I personally prefer not to make an extraneous variable just to hold the return value so I can see whether to do the assignment or not, I prefer the first method myself. Again it is a design/style decision, I am not saying one is right, I am simply saying I think one is cleaner and more efficient, that is all. As to avoid a long argument I mean "more efficient" in that the extra variable doesn't have to be created in the stack frame, even if you argued the compiler could enregister it that is fine but to do so means depriving another variable of using that register, perhaps a more deserving one, and I believe since there is an alternative that avoids this problem all together it is preferable.


    Mezzano

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 05-13-2011, 08:28 AM
  2. In over my head
    By Shelnutt2 in forum C Programming
    Replies: 1
    Last Post: 07-08-2008, 06:54 PM
  3. Passing 2D arrays by reference
    By samGwilliam in forum C++ Programming
    Replies: 9
    Last Post: 04-27-2002, 12:20 PM
  4. how can i pass 2d arrays
    By Unregistered in forum C++ Programming
    Replies: 5
    Last Post: 11-02-2001, 07:33 AM
  5. how to pass 2D array into function..?
    By IngramGc in forum C++ Programming
    Replies: 2
    Last Post: 10-21-2001, 08:41 AM