Function changes an array it shouldn't interact with at all

With th line marked with many “#” active i get this:

With it inactive i get this:

This line and the line above it changes the p1 array somehow, even though it shouln’t, as far as i understand. What am i missing?

int points_number = 12;

PVector[] p1 = new PVector [points_number];
PVector[] p2 = new PVector [points_number];
//PVector[][] p3 = new PVector [ng][points_number/ng];

void setup () {
  size (800, 450);
  
  randomSeed(0);
  for (int i = 0; i < points_number; i++) {
    p1[i] = new PVector(random(width), random(height));
  }
  
  p2 = bsort (p1);
  
  for (int i = 0; i < points_number; i++) {
    fill (0);
    text (i, p1[i].x, p1[i].y);
  }
}

PVector[] bsort (PVector[] a) {
  PVector m;
  int n = 0;
  for (int i = 0; i < a.length; i++) {
    m = a[i];
    for (int j = i+1; j < a.length; j++) {
      if (m.x > a[j].x) {
  //    a[n] = a[j];
        a[j] = m; // #######################################
  //      n = j;
      }
    }
  }
  
  return a;
}

Arrays are passed by-reference, not by-value. That means in your function, where you are sorting array a, you are sorting p1 and returning it. When you assign that returned array to p2, you are wiping out the previously created array and causing the variable p2 to also point to the same array as p1.

Instead, in your bsort function, you could create a new array b, copy the values from a into b, then sort and return array b, and that might give you what you expected.

Just tested it, changed the bsort() so that it creates a copy of a, processes and returns it and it didn’t work. I also tried to feed a copy of p1 into bsort(), it looked like this:

PVector[] a = p1;
p2 = bsort (a);

And it didn’t help either. Am i still missing something?
Edit: by “and it didn’t work” i mean it didn’t lead to a different result

Hi @Lednev,

This also isn’t a copy of the array, it is just an alias. Means by accessing a you access p1 by the alias a.

check reference for deepcopy an array …

Cheers
— mnse

PS: don’t forget to allocate the target array as well with the same size as the source array…
ie:

  String[] test = {"A","B","C"};
  String[] test2 = new String[test.length];
  arrayCopy(test,test2);
  printArray(test2);

console output:

[0] "A"
[1] "B"
[2] "C"
1 Like

Okay, i think i got it. Thanks a lot!

Think of computer memory as a city full of houses where you can store something in each house. An array variable, such as int[] a is an address to a row of houses. When you say a = new int[5];, you are asking the computer to find you five empty houses and give you their address. int[] b is another address. If you say b = a;, then both a and b have the same address to those same five houses. They don’t have a copy of the houses, they are the same five houses. If I say a[2] = 17; then b[2] will also be 17.

When you pass p1 into your bsort() function, you are passing the address of the array to the function. So any changes you make to elements of that array inside the function where it is called a are changing the same houses as those pointed to by p1. arrayCopy() is shorthand for creating a new array and then looping through the elements in the old array and copying them to the new array.

Even then, you still have to be careful when you have an array of objects. In your case, you have an array of PVectors. PVectors are objects. Objects are also really addresses to yet a different house somewhere else in memory. Even after you copy your array, if you modify, for instance, just the y component of one of your vectors, you’ll see the same change in both arrays. But if you replace one of the elements with a new PVector in one array, they will now point to two different PVectors and so can have separate values. If you were to create entirely new PVectors in your second array and fill them with the values of the vectors in the first, this is what’s called a “deep copy”. In your case, you do not need a deep copy, but you do want the shallow copy so that you can sort the second array without rearranging the first one.

3 Likes

That’s a great explanation, thanks. I have recently encountered the fact that i couldn’t manipulate array layers in c# as easily as in Processing, and i assume, the way Processing approaches arrays and the interacions between them allows for doing a lot of stuff much better performance-wise, while having drawbacks, such as the behaviour similar to what caused the problem i faced. Before i faced it, i thought, that by saying

int[] a = new int [5];
int[] b = a;

i was creating two separate arrays that are just equal. It seems strange though that i didn’t bump into this earlier, but it might explain many problems i left unsolved over the last couple years of occasionally fooling around in Processing. Thanks again!

  • In Java, just declaring a variable doesn’t automatically create an object.
  • Therefore this statement int[] b = a; isn’t creating anything!
  • It’s merely declaring a variable named b which is then initialized w/ the value of a.
  • In the case above, the value of a refers to the memory address of the array created by this expression new int[5].
  • That’s different from other languages such as C, which declaring a variable automatically creates its corresponding datatype object.
  • In Java, declare variables & create objects are 2 different things.
2 Likes

Arrays are passed by-reference, not by-value.

Although that’s a valid PoV, officially Java passes everything by value.
For object datatypes such as arrays or strings, those values are memory address, a.K.a. reference or pointer.
Object datatypes are everything else which isn’t 1 of the 8 primitive datatypes:
Primitive Data Types (The Java™ Tutorials > Learning the Java Language > Language Basics)

By that definition, all languages only pass by value. The point is, if the value being passed is the memory address of the data being referenced, we call it passing by-reference.

C/C++ and Java are no different in that regard. C/C++ just happens to have the additional mechanism where objects (or structs) can exist on the stack such that direct memory copies of them can be passed by value.

Arguably, “object reference” should be the 9th primitive datatype.

1 Like

That’s true. However, C/C++/D/C# can define functions which forcibly get the memory address of the variable argument itself rather than the value stored in that variable.

That’s what they call pass-by-reference. That is, the memory address of a variable.

While pass-by-value is when a function reads the content of a passed variable argument.

1 Like