6.12.2. The Swapping Problem (3)

Time: 00:03:52 | Download: Large, Large (CC) Small | Streaming, Streaming (CC) | Slides (PDF)
Review

We have studied the swapping problem twice before, but this time, we have a sufficient understanding to change the problem fundamentally. Our previous explorations used the swapping problem as a lens to focus our attention on programming concepts and constructs. But swapping the values in a pair of variables is a real problem with real applications. With the following example, we develop an authentic solution to the swapping problem by creating a swap function.

Our first step is determining how to pass the data into the function. We have three passing techniques at our disposal:

The swap function must change two parameters, which implies that whichever passing technique we choose, it must be an INOUT technique - it must allow data to flow into and out of the function. While that eliminates pass-by-value, it still leaves us two techniques to study. Furthermore, how (or where) we create the data affects how we call the function, increasing the number of combinations we must explore.

int main()
{
	student	s1 = { 123, "dilbert", 3.0 };
	student s2 = { 987, "alice", 4.0 };

	print(s1);
	print(s2);

	swap(s1, s2);

	print(s1);
	print(s2);

	return 0;
}
void swap(student& param1, student& param2)
{
	student temp = param2;
	//student& temp = param2; // doesn't work!!
	param2 = param1;
	param1 = temp;
}








(a)(b)
Three squares represent three instances of the student structure, labeled param1/s1, param2/s2, and labeled temp. Two squares represent two instances of the student structure. One square is labeled param1/s1 as before, but now the second square is labeled param2/s2/temp. This picture illustrates why making temp a reference doesn't work. See the description of (d) below.
(c - student temp)(d - student& temp)
The swap function: pass-by-reference. Pass-by-reference provides the most straightforward function definition and call. Its relative simplicity makes it the most frequently used technique.
  1. The driver. The function call doesn't require any special syntax or operators.
  2. The function definition implements the pass-by-reference. The only curious aspect of the function is that student& temp = param2; doesn't work. Why?
  3. Recall that pass-by-reference creates aliases by mapping multiple variable names to a single variable. So, the swap function (b) maps param1 and s1 together and param2 and s2 together. temp is a distinct local variable.
  4. Pass-by-reference makes param2 and s2 the same variable. If we make temp a reference, then it and param2 become the same variable, and therefore, temp and s2 become the same variable. So, the assignment param2 = param1 is equivalent to s2 = s1, which overwrites and looses the contents of s2.
int main()
{
	student	s1 = { 123, "dilbert", 3.0 };
	student s2 = { 987, "alice", 4.0 };

	print(s1);
	print(s2);

	swap(&s1, &s2);

	print(s1);
	print(s2);

	return 0;
}
void swap(student* param1, student* param2)
{
	student temp = *param2;
	*param2 = *param1;
	*param1 = temp;
}









(a)(b)
The swap function: pass-by-pointer (1). Although the basic structure is the same, pass-by-pointer (aka pass-by-address) is more complex and requires additional operators. However, it's also more broadly applicable, for example, when programs make system calls.
  1. The driver. s1 and s2 are automatic (i.e., local) variables created on the stack. So, we must alter the swap function call to include the address-of operator. Now, the call passes the addresses of the two structure objects.
  2. The most significant changes are to the swap function itself. First, we must make the parameters into pointer variables with the asterisk. However, the most significant change is in each assignment operation. To affect a copy of the entire object from one memory location to another (i.e., from one variable to another), we must dereference each pointer variable whenever the function uses it.
int main()
{
	student* s1 = new student { 123, "dilbert", 3.0 };
	student* s2 = new student { 987, "alice", 4.0 };

	print(s1);
	print(s2);

	swap(s1, s2);

	print(*s1);
	print(*s2);

	return 0;
}
void print(student* temp)
{
	cout << "ID:   " << temp->id << endl;
	cout << "Name: " << temp->name << endl;
	cout << "GPA:  " << temp->gpa << endl;
}









(a)(b)
The swap function: pass-by-pointer (2). We can also create the structure objects dynamically on the heap with the new operator. In that case, the pointer-version of the swap function (Figure 2(b)) continues to work without modification.
  1. The driver. As s1 and s2 are now pointers, we no longer need to get their address to implement pass-by-pointer. However, we must rewrite the print function, making the parameters pointers. Alternatively, we can dereference the arguments, as illustrated here.
  2. Although we don't need to change the swap function, we do need to update the print function from the problem (2) version.