Thread: Passing by reference to functions

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    26

    Passing by reference to functions

    Hi all,

    I have a question about passing pointers to functions. Here's what I am doing.. I am defining a pointer to an array in my main and passing this pointer to a function.

    Inside this function I am dynamically allocating a certain amount of memory to the pointer that was passed and filling in the array. But my program crashes if I try to access this array from the main. I tried out several stuff and found that I either have to return a pointer to the array that was filled (basically return the same pointer that I passed to the function) or I have to do the allocation of memory inside the main function itself in order for the program to work.

    I am passing a pointer to the function in the first place because I dont want to return any values from the function. I can do the dynamic memory allocation in the main function itself. But i feel that my function will be more self sufficient and rounded if i do the memory allocation inside the function itself (reduce dependence on outside values). Do you have any suggestion how I can solve this issue.. Appreciate your help.

    best,

    Avinash

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    To simulate pass by reference in C, you pass a pointer to the object. Hence, to simulate pass by reference for a pointer, you pass a pointer to the pointer. You should also have another argument for the size, which would also be "passed by reference" (i.e., you should have another variable to keep track of the size, and then you pass the address of this variable to the function... or you have the function return the size of the array allocated).

    Incidentally, I am assuming that by "pointer to an array" you really mean "pointer to the first element of an array".
    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
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by avi2886 View Post
    I am passing a pointer to the function in the first place because I dont want to return any values from the function. I can do the dynamic memory allocation in the main function itself. But i feel that my function will be more self sufficient and rounded if i do the memory allocation inside the function itself (reduce dependence on outside values). Do you have any suggestion how I can solve this issue.. Appreciate your help.
    There is no point in trying to do this in C. I was frustrated by it too not so long ago, but it seems irrelevant now. As you have realized, either you use the return value, or you do the allocation in the same place you do the declaration.
    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

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by MK27
    There is no point in trying to do this in C. I was frustrated by it too not so long ago, but it seems irrelevant now.
    Why do you say that "there is no point in trying to do this in C"?
    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
    Join Date
    Feb 2009
    Posts
    26
    Hi laserlight,

    Thanks for the reply. I understood what you said about using a seperate variable to keep track of the size of memory being allocated. But how should I use that variable back in the main function.

    for instance my code for now look something like this.
    Code:
    int array_size =10;
    
    
     void fill_array( float *ptr)
     {
       
        ptr = (float *) malloc(array_size *sizeof(float));
    
       ... filling up the array
      
     }
    
    
    main()
    {
      float *ptr;
    
      fill_array(ptr);
    
       for(i=0; i<array_size; i++)
       {
    
          printf("%f", ptr[i]);
       }
    
     }

    I have simplified it to post here.. But my program actually uses 2D arrays. In case its relevant.

    As u see.. I ve declared array_size as a global variable. So in theory this should work right..? But it doesn't..

    The problem seems to be that the memory allocated to the variable inside a block gets deallocated when we move out of the block or something like that. Any insights?

    thanks..

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    It depends. Do you want the function to decide/compute the array size and then return the size to the caller? Or do you want the caller to determine the array size and pass it to the function? For the latter, an example would be:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stddef.h>
    
    void fill_array(float **array, size_t array_size)
    {
        *array = malloc(array_size * sizeof(**array));
    
        if (*array)
        {
            /* filling up the array */
        }
    }
    
    int main(void)
    {
        float *array;
        size_t array_size = 10;
    
        fill_array(&array, array_size);
        if (array)
        {
            size_t i;
            for (i = 0; i < array_size; ++i)
            {
                printf("%f", array[i]);
            }
    
            free(array);
        }
        return 0;
    }
    Notice that I do not use any global variables since global variables are not useful here. I do check the return value of malloc(), and then I use free(). Instead of int, I used size_t, an unsigned integer type available from <stddef.h> but typically included by other standard headers, to store the array size. Oh, and I passed a pointer to a pointer, which is perhaps the most important difference from your own example.
    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
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by laserlight View Post
    Why do you say that "there is no point in trying to do this in C"?
    Because it's true And there's a reason for it (it should never be necessary).

    Quote Originally Posted by avi2886
    But my program actually uses 2D arrays. In case its relevant.
    Oh I'm afraid so. You are only making life harder for yourself. I know you don't want to use the return value but consider this:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    float **testfunc(int x, int y) {
    	float **ray=malloc(y*sizeof(float*));   /* array of float pointers */
    	int i,ii;
    	for (i=0; i<x; i++) {			
    		ray[i]=malloc(y*sizeof(float)); /* each pointer to an array of floats */     
    		for (ii=0; ii<y; ii++) ray[i][ii]=i+(ii*0.1);;
    	}
    	return ray;
    }
    
    
    int main() {	/* 4x6 float array */
    	int i,ii;
    	float **this=testfunc(4,6);
    	for (i=0; i<4; i++) {
    		for (ii=0; ii<6; ii++) printf("%.1f ",this[i][ii]);
    		printf("\n");
    		free(this[i]);      /* malloced seperately... */
    	}
    	free(this);		/* ...free seperately */
    	return 0;			
    }
    
    Output:
    0.0 0.1 0.2 0.3 0.4 0.5 
    1.0 1.1 1.2 1.3 1.4 1.5 
    2.0 2.1 2.2 2.3 2.4 2.5 
    3.0 3.1 3.2 3.3 3.4 3.5
    I didn't check the malloc calls as laserlight rightly does.
    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

  8. #8
    Registered User
    Join Date
    Feb 2009
    Posts
    26
    Thank u, both of u for ur replies..

    @Laserlight : I tried to compile the exact code that u posted (filling in the array filling step ofcourse) and run it. But it still crashes.. I guess even pointer to pointer doesn't do the trick.

    @mk27: Yes, thats the way I am doing it now. Was just hoping there was a way to do it without returning.

    I will be expanding my program to have to fill up several arrays all of which will be required in my main function and that was the reason that I was looking to do it without returning. If this isn't possible, I am planning to try to put pointers to all those arrays into 1 struct and return that struct from the function. I ll try it out and let u know if it works.. Thanks for the help.

    cheers..

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Right, C++ references (or other languages) are really just glorified pointers - behind the scenes, the code generated uses pointers. References are not "magical" or "better" than pointers in any way [well, ok, so the syntax for accessing pointers is slightly different - this is not necessarily a good thing in my book, because it makes it hard to see if the local copy is being modified, or if the calling functions variable is being modified - you need to look back at the function declaration to see which it is].

    If you need to pass several things back to a calling function, pass pointers. If you need a pointer passed back, then pass a pointer to pointer. All of this is done by using the & operator in the calling code - if you want something to be passed back, you need an & in the calling code [nearly always - only exceptions are if it's already a pointer, or you are passing back the content of an array].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by MK27
    And there's a reason for it (it should never be necessary).
    Sometimes it is necessary, e.g., if you want to provide an "extra" parameter for an error message, or otherwise need to dynamically allocate more than one array in the function and have the results be reflected to the caller. (EDIT: heh, there is a good example right here: Swapping strings in an array of strings... and it does not even involve dynamic memory allocation in the function.)

    Quote Originally Posted by avi2886
    I tried to compile the exact code that u posted (filling in the array filling step ofcourse) and run it. But it still crashes.. I guess even pointer to pointer doesn't do the trick.
    That implies that your "filling in the array" is not correctly done. For example, I might implement fill_array() like this:
    Code:
    void fill_array(float **array, size_t array_size)
    {
        *array = malloc(array_size * sizeof(**array));
        if (*array)
        {
            /* filling up the array */
            size_t i;
            for (i = 0; i < array_size; ++i)
            {
                (*array)[i] = i;
            }
        }
    }
    Or if you want to avoid dealing with the extra level of indirection and yet not return a pointer:
    Code:
    void fill_array(float **array, size_t array_size)
    {
        float *temp = malloc(array_size * sizeof(*temp));
        if (temp)
        {
            /* filling up the array */
            size_t i;
            for (i = 0; i < array_size; ++i)
            {
                temp[i] = i;
            }
        }
    
        *array = temp;
    }
    Then again, given the name "fill_array", I might just make the function fill the array, and leave the job of allocation to the caller.

    Quote Originally Posted by avi2886
    I will be expanding my program to have to fill up several arrays all of which will be required in my main function and that was the reason that I was looking to do it without returning. If this isn't possible, I am planning to try to put pointers to all those arrays into 1 struct and return that struct from the function.
    Even though it is possible, that is still a good idea.
    Last edited by laserlight; 03-02-2009 at 11:11 PM.
    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

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by avi2886 View Post
    I will be expanding my program to have to fill up several arrays all of which will be required in my main function and that was the reason that I was looking to do it without returning. If this isn't possible, I am planning to try to put pointers to all those arrays into 1 struct and return that struct from the function. I ll try it out and let u know if it works..
    But this is a stylistic choice (doing everything in one function). Even with just one 2D array -- depending on what it's for -- it might be neater to actually use two smaller nested functions, if possible. And with actual separate arrays -- well look, all this stuff that is creating a situation where "you have to do it this way" probably includes (for example) "I want to malloc everything" (why?), because if you just declare a normal stack array, you can pass as many of them as you want around and do anything to them -- but okay, malloc everything. And again, (for example) "I don't want to use any global variables for anything" (why not?) -- two many is silly, but you know, one single global array of pointers (creating a third dimension to your matrix set) might do the trick. If you decide to tie your own hands, don't be suprised to find them bound.

    On the other hand, using a pointer to a pointer could be the key the whole thing. I guess laserlight's example in the "swapping strings" thread would be that (I still think there is always another way around, but I wouldn't always bother to suggest it).

    I feel like a bit of a hypocrit, too: My priorities when writing a function are to "save" the return value (ie, so it could be used for some detail later) and avoid globals.
    Last edited by MK27; 03-03-2009 at 08:11 AM.
    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
    Feb 2009
    Posts
    26
    Quote Originally Posted by laserlight View Post

    That implies that your "filling in the array" is not correctly done.
    You were right.. I had written *array[i] instead of (*array)[i] while filling the array. That was what was causing the program to crash. Apologies..

    I understand what you were trying to tell me about the pointer to a pointer thing now.
    Basically, when I declare a pointer and pass it to the function without allocating any memory to it I am actually passing an empty variable to it. And this empty value is copied into another pointer which is inside the function..

    So when I allocate memory inside the function, I am writing the address of that memory to a pointer which is only inside the function. And so the pointer in my main function has no idea what the address of the memory allocated is.

    So instead when i pass a pointer to a pointer, I am making the function allocate memory, take the address of this allocated memory, look at the address of the pointer in the main(), go to that address and write the allocated memory address there. It all makes sense now.. I guess this is what you have been trying to tell me all along.. Sorry I was slow to understand..

    @MK27: My array size could be highly variable - could be from 2000 x 2000 to 100,000 x 2000. That is why I didnt try to declare a direct stack array.

    But, yes you may be correct about me trying to do everything in a single function. I tend to do that.. I will see if I can split it up to make it simpler.

    Thanks

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by avi2886
    So when I allocate memory inside the function, I am writing the address of that memory to a pointer which is only inside the function. And so the pointer in my main function has no idea what the address of the memory allocated is.

    So instead when i pass a pointer to a pointer, I am making the function allocate memory, take the address of this allocated memory, look at the address of the pointer in the main(), go to that address and write the allocated memory address there. It all makes sense now..
    Yes, your understanding is correct

    Quote Originally Posted by avi2886
    I will see if I can split it up to make it simpler.
    Yes, ideally a function should do one thing and do it well.
    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. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  3. Passing a 2d array by Reference
    By loko in forum C Programming
    Replies: 8
    Last Post: 07-23-2005, 06:19 AM
  4. Passing by Reference
    By Davros in forum C++ Programming
    Replies: 9
    Last Post: 10-11-2004, 03:51 PM
  5. Pointers and reference passing
    By Denis Itchy in forum C++ Programming
    Replies: 4
    Last Post: 12-13-2002, 01:36 AM