Page 1 of 1

Passing By Reference A Comparison Among Languages

#1 KYA  Icon User is offline

  • g++ jameson.cpp -o beverage
  • member icon

Reputation: 3089
  • View blog
  • Posts: 19,137
  • Joined: 14-September 07

Posted 07 March 2009 - 09:14 PM

Passing By Reference

At some point, I imagine you have had the need for functions to communicate with one another. It usually takes the form of function parameters since global variables are not good programming practice. A basic version looks like:

void function (int theNum)
{
   //do stuff with the num
}
int main()
{
   int a = 5;
   function(a);
  return 0;
}



There are two ways to pass a parameter and the distinguishing between them is very important; it can create bugs and make or break your program in some instances. First let's consider C++. C++, by default has parameters passed as shallow copies of whatever they are supposed to be. consider the following snippet:

void function (int theNum)
{
	theNum = 6;
}
int main()
{
   int a = 5;
   function(a);
   cout << a << endl;
  return 0;
}



What do you expect the output to be? 6? Nope, a shallow copy of the 'a' integer was passed to the function. This copy's value was modified to 6, but as soon as the function returns it goes out of scope and 'a' remains the same. This is where references and pointers come in handy. Consider this snippet:

void function(int& theNum)
{
	theNum = 6;
}
int main()
{
	int a = 5;
		cout << a << endl;
	function(a);
	cout << a << endl;
	return 0;
}



When we pass 'a' from main to the function, a copy is not passed, we pass the reference to 'a' to the function. This allows us to modify the value of a directly. This is both powerful and dangerous since (unless we are careful) we can accidentally modify a value and have a tough bug to find. The output of this snippet is 5, 6, indicating we successfully modified a's value. We can achieve the same effect with pointers (which are more often used then references since they have more abilities, but that goes out of the scope of what I'm talking about in this tutorial). Consider this:

void function(int* theNum)
{
	*theNum = 6;
}
int main()
{
	int a = 5;
	cout << a << endl;
	function(&a);
	cout << a << endl;
	return 0;
}



We pass a reference to a as the param in main, this is assigned to the pointer "theNum" in function and then we assign the value of theNum (its derefernece location to 6). The output is the same as the previous snippet: 5, 6. Effectively two ways to reach the same destination. The ability to expressly use pointers and references is an advantage (and both a curse?) C++ has over java. Consider a typical swap function:

void swap(int* first, int* second)
{
	int temp = *first;
	*first = *second;
	*second = temp;
}
int main()
{
	int a = 5, b = 6;
	cout << a << " " << b << endl;
	swap(&a, &b);
	cout << a << " " << b << endl;
	return 0;
}



We create two integers, pass their references and "swap" their values using a temp holder. This is only possibly by using pointers. If we tried the exact same concept with java it would fail. Consider the same snippet in java:

	public static void swap (int first, int second)
	{
		int temp = first;
		first = second;
		second = temp;
	}
	public static void main (String args[]) 
	{
	
		int a = 5, b = 6;
		System.out.println(a + " " + b);
		swap (a,b);
		System.out.println(a + " " + b);
	
	}



The output is 5,6 5,6. Why? Because we did not pass the reference to the numbers (in this instance it was a shallow copy). This can get confusing since java handles objects as reference, but method parameters by value. "Java does manipulate objects by reference, and all object variables are references. However, Java doesn't pass method arguments by reference; it passes them by value." The scope of the parameters end with the death of the function.

In short: If the argument is a primitive type, then it is passed by value. If the argument is an object (or an array), then it "can be" considered pass-by-reference. However, java does not pass by reference--at all.

Java does not allow programmers to directly access and play around with object pointers. To protect us I suppose, but it requires a little extra effort on our part to solve the problem. If the numbers are a part of a data structure and we pass the structure as well, then any assignments will remain in effect, even after the death of the function:

	public static void swap (int[] arr)
	{
		int temp = arr[0];
		arr[0] = arr[1];
		arr[1]= temp;
	}
	public static void main (String args[]) 
	{
	
		int[] nums = {5,6};
		System.out.println(nums[0] + " " + nums[1]);
		swap (nums);
		System.out.println(nums[0] + " " + nums[1]);
	
	}



The array is passed as an object reference [by value] (remember that an array has an implicit pointer to the first element in C++ which we can access and it also exists in java, but we cannot manipulate it the same way, i.e. directly). You can change an object reference's values and such, but you cannot change what it points at. Sidenote: the subscript operator [] is the same as dereferencing the pointer + the element you want to access in C++:

//Neat little thing to know
arr[3] == *(arr + 3);



For a final look-see, I'll show you two string permutation algorithms, one in C++ and the other in Java. Both work, however, see if you can notice the difference needed to make it work in java:

//C++
#include <iostream>
#include <string>
using namespace std;

void swap(char* first, char* second)
{
		char ch = *second;
		*second = *first;
		*first = ch;
}

int permute(char* set, int begin, int end)
{
		int i;
		int range = end - begin;
		if (range == 1) {
				cout << set << endl;
		} else {
				for(i=0; i<range; i++) {
						swap(&set[begin], &set[begin+i]);		//initial swap
						permute(set, begin+1, end);			//recursion
						swap(&set[begin], &set[begin+i]);	   //swap back
				}
		}
		return 0;
}

//Example Implementation -- Up to you on how to use
int main()
{
		char str[255]; //string 
	cout << "Please enter a string: ";
	cin.getline(str, 255); //take string
		permute(str, 0, strlen(str)); //permutate the string
		return 0;
}



VS.

//java
import java.io.*;

public class Permute {
	
	public static void swap(char[] set, int first, int second) 
	{
			char ch = set[second]; 
			set[second] = set[first]; //swap the values
			set[first] = ch;
	}
	
	public static int permute(char[] set, int begin, int end)
	{
			int i;
			int range = end - begin;
			if (range == 1) {
					System.out.println(set); //print out each permutation
			} else {
					for(i=0; i<range; i++) {
							swap(set, begin, begin+i);		//initial swap
							permute(set, begin+1, end);		//recursion
							swap(set, begin, begin+i);	   //swap back
					}
			}
			return 0;
	}

	//***************TEST EXAMPLE********************
	public static void main(String[] args) {
		
		char[] test = {'a','b','c','d'};;
		permute(test, 0, 4);
	}

}




Found it? The answer is, in java I had to pass the array so the swapping would be permanent, otherwise it wouldn't display the permutations correctly; it would be as if the swap never happened. Specifically here:

public static void swap(char[] set, int first, int second) {}

//versus

void swap(char* first, char* second)



As with most programming endeavors, there are many routes to solve a problem. It is knowing how best to utilize your tools at your disposal that makes you a good programmer. In the above work, one way is not necessarily better then the other, as it would be comparing apples to oranges. Each has a different manner in which things must be handled. Hopefully you found this both useful and interesting. Happy coding!

--KYA

Is This A Good Question/Topic? 0
  • +

Page 1 of 1