-1

This is my first question on the site and I am sure I'll find my answer here.

For school, I was trying to do some basic C# coding for a challenge that was given to us.

Here is the problem:

Normally when I pass a value through a method I don't run into issues. Like so:

static void Main(string[] args)
{
    // Declare Integer
    int originalInt = 20;

    // Call the Method
    int multipliedInt = Multiplication(originalInt);

    // Prompt
    Console.WriteLine("Original: {0} Modified: {1}", originalInt, multipliedInt);
}

// Method
static public int Multiplication(int original) 
{
    // Quik Maffs
    int modifiedValue = original * 2;

    return modifiedValue;
}

The above example works just fine. The original value is 20 and the modified value is 40.

However, this changes when I attempt to do that with an array:

static void Main(string[] args)
{
    // Declare Original Array
    int[] originalArray = new int[] {1, 4, 6, 8, 12};

    // Call Method
    int[] multipliedArray = Multiplication(originalArray);

    // Prompt
    Console.WriteLine("Original: [{0}], Multiplied: [{1}]", String.Join(", ", originalArray), String.Join(", ", multipliedArray));
}

// Method
static public int[] Multiplication(int[] original) 
{
    // New Int
    int[] modified = original;

    // Loop
    for (int i = 0; i < modified.Length; i++) 
    {
        modified[i] *= 2;
    }

    return modified;
}

The code above returned the modified value twice. It seems like it modifies the original value as well.

Any idea why this is happening?

Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • Arrays are passed by reference, so you're passing a reference to your original array, and not a copy of it's value as you're expecting. – Jonathon Chase Jun 19 '18 at 22:57
  • The difference is that in the first example, you're passing the variable by value. In the second example, you're passing a reference to the array. When you use the int argument, the method receives a copy of the value. With the array, you're passing a reference to the array instead of a copy of it. – itsme86 Jun 19 '18 at 22:57
  • @JonathonChase Ah, I didn't know this. So I'm assuming what I'd have to do is create a new int array within the method. –  Jun 19 '18 at 22:58
  • You didn't do anything wrong, some people here including @Eser can be elitist. As a previous user mentioned, arrays are passed by reference. You can make your function void and remove your return statement and everything will be good to go. Edit: not quite, you'll need to change which array you're referencing within the function. – emsimpson92 Jun 19 '18 at 22:58
  • Yes. You'd have to create a new array in the method. – itsme86 Jun 19 '18 at 22:59
  • @itsme86 As bad as it is, I didn't know that arrays passed as a reference. I thought it was treated as other datatypes like my first example. Thank you for clarifying! –  Jun 19 '18 at 22:59
  • No problem. There are other types that are passed by value as well. Basically, anything that's a struct (believe it or not, int, double, float, decimal, etc.) is passed by value (a copy is created), and anything that's a class is passed by reference. – itsme86 Jun 19 '18 at 23:01
  • You may find these documents helpful: [Reference Types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) & [Value Types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value-types) – Jonathon Chase Jun 19 '18 at 23:01
  • @emsimpson92 Thanks for this. You mentioned removing the return statement and making the function void: would this require me pass the array through a loop in main and have each index go through the function? Hopefully I worded that correctly. Still trying to get into the lingo. –  Jun 19 '18 at 23:01
  • No, you can just run a loop within your function to modify the various indexes of your original array. – emsimpson92 Jun 19 '18 at 23:03
  • @itsme86 That is actually very useful to know. I'll definitely write that into my notes! –  Jun 19 '18 at 23:03
  • 1
    @emsimpson92 That would still entail modifying the original array. I think OP wants a copy of the array that has the original values and a copy with the new values. – itsme86 Jun 19 '18 at 23:04
  • It would probably be easier to make your array a list and just run a `foreach` loop rather than have a separate function that does this. – emsimpson92 Jun 19 '18 at 23:04
  • In that case, OP can just pass multipliedarray and modify those values. – emsimpson92 Jun 19 '18 at 23:06
  • @mjwills I'm sorry, I didn't know the difference between them and wouldn't have known if this was a duplicate question. –  Jun 19 '18 at 23:07
  • If, instead of `int[] modified = original;` you did `int[] modified = original.ToArray();` that would instantiate a new array, and you'll be able to keep the original values unchanged. – Sach Jun 19 '18 at 23:09
  • 3
    There is no need to apologise. Have a read of the duplicate and hopefully it will be of value of you. – mjwills Jun 19 '18 at 23:09

1 Answers1

3

int is a value type. When you pass a value type to a method, you pass a copy of the value.

Arrays are reference types. When you pass a reference type to a method, you pass a copy of the reference... but both the copy and original still refer to the same object.

Now it seems you may have understood this much, because of this code:
(This is why I re-opened the question... the stock ref-vs-value answer wasn't gonna cut it here)

int[] modified = original;

However, the other thing that happens with reference types is assignments also only copy the reference. So modified and original in that snippet again refer to the same array object.

To fix this, you need to make an actual deep copy of the array. There are several ways to do this. I would tend to write the method this way:

static public IEnumerable<int> Multiplication(IEnumerable<int> original) 
{
    return original.Select(i => i * 2);
}

...and append a .ToArray() at the end of the method call if and only if I really need a full array (hint: very often it turns out you don't), like this:

int[] multipliedArray = Multiplication(originalArray).ToArray();

or like this:

var multipliedArray = Multiplication(originalArray);

But I understand there are a number of things here that aren't very familiar to a beginner. You might try something more like this:

static public int[] Multiplication(int[] original) 
{
    int[] modifed = new int[original.Length];

    for (int i = 0; i < original.Length; i++)
    {
        modified[i] = original[i] * 2;
    }

    return modified;
}
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 1
    Wow, thank you very much for taking the time out of your day to write this answer. Very much appreciated! I also tried your solution and it helped me tremendously. Not only within the code, but in my understanding of the topic. –  Jun 20 '18 at 01:57