Antony
Antony

Reputation: 5454

Why swapping two values based on pointers don't work outside function scope?

I haven't programmed in C++ for a number of years, so I decided to refresh my memories on pointers.

In the classic example of swapping between two numbers, the example is

void swapPointersClassic(double *num1, double *num2) 
{
  double temp;
  temp = *num1;
  *num1 = *num2;
  *num2 = temp;
}

This allows us to make function call like swapPointersClassic(&foo, &bar); and because we pass in the memory addresses of both variables foo and bar, the function will retrieve the values and do the swap. But I started to wonder, why can't I do the following?

void swapPointers(double *num1, double *num2)
{
  double *temp;
  temp = num1;
  num1 = num2;
  num2 = temp;
}

That seems to make more sense to me, because we only have to create enough temporary storage for storing the memory address num1 (instead of a full temporary storage for storing a double value *num1). However, it seems that function scope limits the effect of pointer swapping. After making the call swapPointers(&foo, &bar);, I can see that within the function swapPointers, foo & bar are indeed swapped. Once we exit the swapPointers function, foo and bar are no longer swapped. Can anyone help me understand why this is the case? This behavior reminds me of the typical pass by value approach, but we are passing by pointers here. So that means we can only touch the values pointed by those pointers, but not the pointers themselves?

Upvotes: 11

Views: 3977

Answers (8)

Shashikant Mitkari
Shashikant Mitkari

Reputation: 307

As proper answer(s) to this question had already been posted, I would just make some things clear.

Swapping values of two variable using references is bad practice in general and should be avoided. the reason is references are not supposed to be re-assigned. Look at the following code :

1. void swap(double &a, double &b)
2. {
3.    double temp = a;
4.    a = b;  //Not what you think
5.    b = temp;
6. }
7.
8. float a = 1, b = 2;
9. swap(a, b);

on lines 4 and 5, you are clearly violating the common rule - 'Never Re-assign references'.

If you really need to change value of the variable(s) always prefer 'pass by pointers' rather than 'pass by reference'. The following code makes sense and a good practice IMO.

1.  void swapPointersClassic(double *num1, double *num2) 
2.  {
3.   double temp;
4.   temp = *num1;
5.   *num1 = *num2;
6.   *num2 = temp;
7.  }    
8.
9.  float a = 1, b = 2;
10. swap(&a, &b);

Agreed that references are cleaner and easier to use, and they do a better job of hiding information, as you saw in the first example. References cannot be reassigned, however. If you need to point first to one object and then to another, you must use a pointer.

Rule of Thumb:

  • DON'T use pointers if references will work.
  • DON'T try to reassign a reference to a different variable. You can’t.

Upvotes: 0

Blastfurnace
Blastfurnace

Reputation: 18652

This is a good question but once you have it figured out please use std::swap or std::iter_swap instead of writing your own.

If foo and bar are pointers, calling std::swap(foo, bar) would exchange the addresses between the two pointers. Calling std::swap(*foo, *bar) or std::iter_swap(foo, bar) would dereference the pointers and exchange the objects the pointers point to.

Upvotes: 2

user529758
user529758

Reputation:

In fact you don't really pass by pointer. You pass two pointers by value. Passing pointers in itself is not enough - you have to dereference them. The act of dereferencing the (copies of the) pointers makes the magic happen and it is the actual place where scope traversal is achieved.

Modifying the arguments of a function is local to the function, even if the arguments themselves are pointers. You must dereference them in order to access the memory pointed to by them (again, "passing by pointer" is more than passing pointers - it's passing pointers and using them properly).

Also, consider the following. If your second approach worked, and the two pointers were swapped then it would mean that the addresses of the variables are exchanged. This doesn't quite make sense.

By the way, in C++ we have a true pass-by-reference calling convention, so there's no need to mess with pointers:

void swap(double &a, double &b)
{
    double temp = a;
    a = b;
    b = temp;
}

float a = 1, b = 2;
swap(a, b);

(It's just a matter of implementation that the compiler will most likely realise this behavior by actually using pointers, but at least you don't have the headache.)

Upvotes: 9

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

Pointers 101: a pointer is a piece of paper with the address of a house on it.

By writing &bar, you are taking the house called bar and writing its address down on an anonymous piece of scrap paper.

You then call a function with that pointer as an argument. What happens here is that the function makes another copy of the piece of paper.

Your swap function then takes two such local copies and swaps what address is written on them.

So that does nothing outside the function. Clear?

Now fundamentally even if there was not a copy inside the function of the address all you are working with is scrap paper with house addresses on them. No changes to such paper can actually move the data stored in house bar or foo.

Upvotes: 0

Alessandro Pezzato
Alessandro Pezzato

Reputation: 8802

If you want to swap pointers, not their values, you need to pass pointer of pointer:

void swapPointers(double** num1, double** num2)
{
  double* temp = *num1;
  *num1 = *num2;
  *num2 = temp;
}

You can see an example in: http://ideone.com/iklCta

You can work even with references:

void swapPointers(double*& num1, double*& num2) {
  double* temp = num1;
  num1 = num2;
  num2 = temp;
}

Example: http://ideone.com/w4k9mV

This is useful when you work with huge objects (e.g.: image data) and you do not want to move a lot of memory, but only references.

Upvotes: 6

Bill Carey
Bill Carey

Reputation: 1415

When you pass double *num1 into a function, you're passing in a pointer by value. That creates a variable in the function scope that holds the address of a double. When you assign to that, you're changing the value of the pointer in the function scope.

Just like you have to pass in a pointer to a double, dereference it, and assign to swap a double, you have to pass in a pointer to a pointer, dereference it, and assign to swap a pointer.

Upvotes: 0

Doug T.
Doug T.

Reputation: 65599

When you call

swapPointersClassic(&foo, &bar)

You are taking the address of two items on the stack. These values are being passed in as temporaries and are copied by value. In your function body, you swap where these temporaries point, but don't move where foo and bar are pointing.

Most importantly, foo and bar live on the stack. You can't change where variables live in the stack in C++. A value is mapped to a spot on the stack and lives there. You can get a pointer to where that value lives to do pass-by-pointer (similar to pass-by-reference) but just by changing where that temporary pointer points you aren't changing where the pointed-to object lives.

Upvotes: 0

Praetorian
Praetorian

Reputation: 109119

You are passing the pointers themselves by value; num1 and num2 are local copies of pointers that the caller calls the function with. So the swapping is not visible at the callsite when the function exits since the modifications were only made to variables that are local to the function.

Instead, change the function to take references to the pointers and your swapping code will work as intended to.

void swapPointers(double*& num1, double*& num2) { ... }

Now, your function parameters are aliases for the pointers that the caller passes to the function, and whatever you do to them will affect the pointers in the caller's context as well.

Upvotes: 0

Related Questions