Why is this Unchanged Parameter Value Changing with Successive Calls to the Method?

Viewed 37

Maybe I have not had enough morning coffee. I have been scratching my head over this for a half hour. The solution I whipped up to LeetCode problem https://leetcode.com/problems/flood-fill/ is

using System.Drawing;

public class Solution
{
    private static readonly IReadOnlyCollection<Offset> _offsets = new List<Offset>()
    {
        new Offset { X = 1, Y = 0 },
        new Offset { X = -1, Y = 0 },
        new Offset { X = 0, Y = 1 },
        new Offset { X = 0, Y = -1 }
    };
    
    public int[][] FloodFill(int[][] image, int sr, int sc, int color)
    {     
        int y = sr, x = sc, m = image.Length, n = image[0].Length;
        FloodFill(image, x, y, m, n, image[y][x], color);
        return image;
    }
    
    private static void FloodFill(in int[][] image, in int x, in int y, in int m, in int n, in int sourceVal, in int targetVal)
    {
        Console.WriteLine("Called FloodFill with x = {0}, y = {1}, IsInBounds(x, y, m, n) = {2}, image[y][x] = {3}, sourceVal = {4}, targetVal = {5}", x, y, IsInBounds(x, y, m, n), image[y][x], sourceVal, targetVal); /// TEMP!!!
        if (IsInBounds(x, y, m, n) && image[y][x] == sourceVal)
        {
            image[y][x] = targetVal;
            foreach (Offset offset in _offsets)
                FloodFill(image, x + offset.X, y + offset.Y, m, n, sourceVal, targetVal);
        }
    }
    
    private static bool IsInBounds(in int x, in int y, in int m, in int n)
    {
        return x >= 0 && x < n && y >= 0 && y < m;
    }
    
    private struct Offset
    {
        internal int X { get; init; }
        internal int Y { get; init; }
    }
}

and what's absolutely crazy (unless I'm blind or missing something obvious) is that I see the value of sourceVal is changing as the method is recalled:

Called FloodFill with x = 1, y = 1, IsInBounds(x, y, m, n) = True, image[y][x] = 1, sourceVal = 1, targetVal = 2

Called FloodFill with x = 2, y = 1, IsInBounds(x, y, m, n) = True, image[y][x] = 0, sourceVal = 2, targetVal = 2

Called FloodFill with x = 0, y = 1, IsInBounds(x, y, m, n) = True, image[y][x] = 1, sourceVal = 2, targetVal = 2

Called FloodFill with x = 1, y = 2, IsInBounds(x, y, m, n) = True, image[y][x] = 0, sourceVal = 2, targetVal = 2

Called FloodFill with x = 1, y = 0, IsInBounds(x, y, m, n) = True, image[y][x] = 1, sourceVal = 2, targetVal = 2

How did the value of sourceVal flip from 1 to 2?

It's an in parameter, so it can't change via sourceVal = .., which we can see is not there anyways.

The method is called with sourceVal as 2nd-to-last parameter, not sourceVal + something.

So how the heck is this getting modified?

1 Answers

I removed the in in the parameters and it run the example test successfully on leetcode.

The problem is that in pass the value by reference. so in your code

 public int[][] FloodFill(int[][] image, int sr, int sc, int color)
    {     
        int y = sr, x = sc, m = image.Length, n = image[0].Length;
        FloodFill(image, x, y, m, n, image[y][x], color);
        return image;
    }

you pass image[y][x] which is equal 1 as a reference not as a value. Then here:

 image[y][x] = targetVal;

you assign that reference to targetVal which was equal to 2 So now the sourceVal which reference to image[y][x] is equal to 2 not 1.

Related