4

I'm working with a program that uses two-dimensional arrays of Strings (probably not that smart to begin with, but eh), and I'd like to write a function that takes one of these arrays (let's say array1), makes an independent copy, and returns it (let's say array2). However, when I then change a value in array2, it seems to be reflected in array1.

My function currently looks something like this:

public static String[][] copy(String[][] matrix, int n) { String[][] out = new String[n+1][n+1]; for (int i = 0; i < n+1; i++) for (int j = 0; j < n+1; j++) { if(matrix[i][j] != null) { String cp = new String(matrix[i][j]); out[i][j] = cp; } } return out; } 

I declare a new array of Strings, and then iterate through it, copying each value individually. When that didn't work, I even tried explicitly declaring a new string from each old string and putting that in the array instead.

Can anyone tell me where I'm going wrong?

5
  • Seems like it should work to me... can you provide some example code that illustrates the problem you've been having? Commented Apr 1, 2009 at 18:20
  • +1: works fine for me... can you provide the code for your whole test setup? Commented Apr 1, 2009 at 18:28
  • Is there an edit function? Sorry, all, I realized that the problem was actually with my print function. Thanks for your thorough help, though: I cleaned up the function with the suggestions and learned a lot about how Java passes arguments. Commented Apr 1, 2009 at 18:48
  • Actually, there is an edit function ... go ahead, find and use it :-) ... Commented Apr 1, 2009 at 18:57
  • Works for me. Provide a small, complete example of this not working, or it's not a question. Commented Apr 1, 2009 at 19:44

7 Answers 7

5

I'm not sure what the n parameter is for, but if I needed such a function, I'd use something like this:

public static String[][] copy(String[][] matrix) { String[][] copy = new String[matrix.length]; for (int idx = 0; idx < matrix.length; ++idx) copy[idx] = matrix[idx].clone(); return copy; } 

You don't need to create a copy of the String, because they are immutable. As pointed out by Michael in the comments, the String(String) constructor might be useful if the original string was created as a substring of some very large string. Another use is when you are using String objects as locks (not recommended), and want a private instance to avoid deadlocks.

Also, your check to see whether an element is null before assigning is unnecessary; if you have your loops setup correctly, the element is guaranteed to be null. (And if it's not, what's the harm in overwriting it?)

Sign up to request clarification or add additional context in comments.

3 Comments

Another useful reason to use String(String) could be to force substrings of a large base String to be trimmed down so that the base String's memory can be reclaimed (since substring() usually keeps a reference to the entire base string)
Since String is immutable, you don't need to clone it.
@Michael: good point; will update accordingly. @Steve: no one is cloning any Strings. Could you explain what you are talking about?
3

Your method looks like it should work, though passing in n as a parameter makes it brittle, using the input array's length field would be better, and you could even handle jagged arrays that way.

Making a copy of the contents is not necessary, since Strings cannot be changed - which leads to the main question: What kind of changes are you making that seem to be reflected in the copy? Show us the code that does this.

Comments

3

Have a look at System.arraycopy. That way you can get rid of the inner loop.

Comments

1

Maybe Arrays.copyOf would be of some use?

Comments

1

I tried with your code : got exception java.lang.ArrayIndexOutOfBoundsException

It's working for me, please try like this :

 public static String[][] copy(String[][] matrix, int n) { String[][] out = new String[n][n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { if(matrix[i][j] != null) { String cp = new String(matrix[i][j]); out[i][j] = cp; } } return out; } 

Comments

0

Take a look at this question Is Java pass by reference? It can be a little confusing how Java passes objects, but this would explain why making a change to one array also makes the change to your other array.

2 Comments

-1 it doesn't explain, for the code given, why making a change to one array also changes the other.
Thats b/c the problem was not with the code given, re-read the first part of the question. From the question comments "I cleaned up the function with the suggestions and learned a lot about how Java passes arguments. – Lily"
0

Your use of the 'n' parameter, as noted above is redundant, but also flawed by your code with n+1?? Your code would produce an ArrayIndexoutOfBoundsException if run something like:

  String [][] m1 = { {"A", "B"}, {"C", "D" } }; String [][] m2 = copy(m1, 2);  

Which presumably is how you intend it to be invoked?

It also limits your function to square 'matrices' of Strings. But as for the problem you cited, I see no reason why the program should behave that way... I even ran it using the above call (but with n=1???) then changed

m2[0][1] = "X";

and m1 was unaffected as expected. Even replacing the innermost code line to:

 out[i][j] = matrix[i][j]; 

does not change this, as the compiler rewrites it to what you originally had. In fact a lot of the String sytax is simply syntactic sugar for StringBuffers (such as concatenation and assignment). eg the compiler will rewrite

 String s = "Hello "; s += "World"; // Makes it appear that String is builtin type! 
to
 String s = new String("Hello "); s = new StringBuffer(s).append("World").toString(); 
Which is why is you have lots of string concatenation inside loops they can perform very poorly.

I do not understand why you are having the problem you cited either.

And as you are not modifying the parameter 'matrix', 'Pass By Reference' has nothing to do with it.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.