C# passing int[] (array) with and without ref [duplicate] - c#

This question already has answers here:
Why would ref be used for array parameters in C#?
(2 answers)
What is the use of "ref" for reference-type variables in C#?
(10 answers)
Closed 7 years ago.
I am slightly confused about this, as I have read that an int[] array, although int is a primitive type, since it's an array, it's a reference type variable.
What is the different then between a method such as:
public static void ChangeSomething(ref int[] array)
{
array[0] = 100;
}
and
public static void ChangeSomething(int[] array)
{
array[0] = 100;
}
When the array is modified, I can see the new value of 100 at index 0 for both of these calls.
Is there something different that happens under the covers which makes one better than another? Does the VS IDE allow both simply because perhaps the "ref" keyword clarifies the intention?

The difference is that you can assign the original variable directly in the method. If you change your method to the this:
public static void ChangeSomething(ref int[] array)
{
array = new int[2];
}
And call it like this:
var myArray = new int[10];
ChangeSomething(ref myArray);
Console.WriteLine(array.Length);
You will see that myArray only have a length of 2 after the call. Without the ref keyword you can only change the content of the array, since the array's reference is copied into the method.

If you modify the items of the array, there is no difference.
But if you redefined the array itself with larger array, there is the difference:
public static void ChangeSomething(ref int[] array)
{
array = new int[100]; //you are changing the variable of caller
}
and
public static void ChangeSomething(int[] array)
{
array = new int[100]; //you are changing local copy of array variable, the caller array remains same.
}

Related

C#: Default Value for Constructor with Array Argument [duplicate]

This question already has answers here:
Setting the default value of a C# Optional Parameter
(3 answers)
Closed 9 years ago.
How does one define a function that takes an optional array with an empty array as default?
public void DoSomething(int index, ushort[] array = new ushort[] {},
bool thirdParam = true)
results in:
Default parameter value for 'array' must be a compile-time constant.
You can't create compile-time constants of object references.
The only valid compile-time constant you can use is null, so change your code to this:
public void DoSomething(int index, ushort[] array = null,
bool thirdParam = true)
And inside your method do this:
array = array ?? new ushort[0];
(from comments) From C# 8 onwards you can also use the shorter syntax:
array ??= new ushort[0];
If you can make the array the last argument you could also do this:
public void DoSomething(int index, bool wasThirdParam = true, params ushort[] array)
The compiler will automatically pass an empty array if it is not specified, and you get the added flexibility to either pass an array as a single argument or put the elements directly as variable length arguments to your method.
I know it's an old question, and whilst this answer doesn't directly solve how to get around the limitations imposed by the compiler, method overloading is an alternative:
public void DoSomething(int index, bool thirdParam = true){
DoSomething(index, new ushort[] {}, thirdParam);
}
public void DoSomething(int index, ushort[] array, bool thirdParam = true){
...
}

What's wrong with my array declaration?

The following works:
int[] numbers = new int[2];
The following doesn't:
int Size = 2;
int[] numbers = new int[Size];
Error: "A field initializer cannot reference the non-static field, method, or property"
I know this must be me doing something stupid but can't work out what it is at all.
You can give size of array by constant but not variable as the size of array could not be given at class level if you declare the array out side the method at class level. C# does not guarantee the order in which fields within a class are initialized so you cannot use one non-static field to initialize another non-static field outside of a method, reference.
const int Size = 2;
int[] numbers = new int[Size];
void SomeFun()
{
}
If you declare it inside some method then you wont get error.
void SomeFun()
{
int Size = 2;
int[] numbers = new int[Size];
}
You can use list instead of array if your collection size in unknown at runtime.
List<int> lst = new List<int>();
Put these initializations into the constructor:
public class MyClass
{
const int Size;
int[] numbers;
public MyClass()
{
this.Size = 2;
this.numbers = new int[this.Size];
}
}
In this way you are providing a guarantee of order in which initializations should be executed.
You cannot use an instance variable to initialize another instance variable. There is no guarantee that the 'Size' variable will be initialized before the 'number' array. The initial values for fields need to use constants - it's not as restrictive as that; they can also reference static fields, methods or properties.

In C#, is it the same as in Java refering to object creation during methods?

I have a programming competition tomorrow and I have a quick question:
In Java, if you would pass an object in a parameter for a method, you actually got not a copy of the object, but the actual object.
Is it the same as C#?
public static void PunchyManager(string[] inputArray, ref int a, ref int b)
{
string[] tempStrArray = inputArray;
}
If I do that will I basically make a pointer to inputArray, instead of having a copy?
Just a quick question, thanks!
In regard to your basic question in relation to Java Yes.
More generally Yes and no. Reference types (classes) are passed by reference which is like a single pointer. For something that can truly modify references outside the caller you should use the ref keyword even on reference types. This is similiar to a double pointer (assuming we are referring to pointers as they work in C for our pointer analogies).
class RefRefExample
{
static void Method(ref string s)
{
s = "changed";
}
static void Main()
{
string str = "original";
Method(ref str);
// str is now "changed"
}
}
In the above example if we passed str without using the ref keyword we would reassign the local reference of s instead of the original reference of str. By passing our reference by reference we can modify the original reference outside of the function as well. References themselves are still copied by value (but the copied reference still points to the same value) without the ref keyword.
http://msdn.microsoft.com/en-us/library/14akc2c7(v=vs.80).aspx
For practical usage in the scenario you are describing the modern C# idiom usually uses lists and they will likely be much faster to use as far as programming in your competition:
public static void PunchyManager(List<string> inputList, ref int a, ref int b)
{
var tempList = new List<string>();
foreach (var item in inputList)
tempList.Add(item);
}
Working on the original input list would modify objects through the reference so you would be affecting the original values outside of the method whereas the templList is a copy - Lists are very convenient.
Furthermore you can convert them back to Arrays using .ToArray()
*edit Oh, you wish to know if it is the same in c# as java, your wording was a bit off.
Correct, if you do
public static void main(String[] args)
{
int myArray[] = new int[1];
test(myArray);
System.out.println(myArray[0]);
}
public void test(int[] array)
{
array[0] = 1;
}
You will get an output of 1
In CLR there are two kinds of objects:
Reference types (also known as just "objects")
Value types (also known as "structures" or "structs", even they are technically objects too).
The difference between them is that "objects" are located on heap, when "structs" are located on stack.
Types like Int32, Int64, Float, Double, etc are value types (structs). You can also define your own structure:
public struct MyStruct { ... }
Therefore, when you pass a "struct" around it is passed by copying the value.
Example:
int x = 5; //creates a value type on stack
int y = x; //makes a copy so now we have two objects on stack, not just one
"Objects" are passed by reference.
object x = new Object(); //create an object, x holds a reference to this object
object y = x; // y now holds a reference to the same object x has a reference to.
When you pass reference types around you generally don't need to use a ref keyword. However, if you want to pass a reference to a value type instance you may want to use this keyword.
Yes, class instances are passed as references in C#. If you want to pass value type (like Int32) as reference you need to use ref keyword.
Thing is, If you pass the parameter with keyword ref, modification of the variable inside the method will be reflected to caller as well. This is applicable to even struct(exmple int). But for struct or class, if you pass the parameter with out ref/out, this will be assumed as pass by value, which means, modification inside the method cannot be reflected to caller for structs. For classes, modification will be reflected to caller still without passing with out ref. BUT, StringBuilder sb = new StringBuilder() statement ask the sb to point to this one (an newly created new StringBuilder()). So reference knot will be moved from one which was pointed in the caller to new StringBuilder() in the callee. This has to be remembered always.
Pass by value with ref:
static void Main(string[] args)
{
StringBuilder y = new StringBuilder();
y.Append("hello");
Foo(ref y);
Console.WriteLine(y);
}
private static void Foo(ref StringBuilder y)
{
StringBuilder sb = y;
sb.Append("99");
}
o/p : hello99
Pass by value without ref:
static void Main(string[] args)
{
StringBuilder y = new StringBuilder();
y.Append("hello");
Foo(y);
Console.WriteLine(y);
}
private static void Foo(StringBuilder y)
{
StringBuilder sb = new StringBuilder
sb.Append("99");
}
o/p : hello
To assign something different to your array you'd want to have the parameter use the 'ref' keyword.
http://msdn.microsoft.com/en-us/library/szasx730(v=vs.71).aspx

Passing array elements by ref [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C# parameters by reference and .net garbage collection
I was thinking of using ref arguments to limit the bounds checking of an array. For example the code of swapping two elements is :
class Test {
int[] array;
private void qSort() {
...blah...
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
}
which has 4 access to the array
the alternative will be :
class Test {
int[] array;
private void qSort() {
...blah...
Swap( ref array[a], ref array[b] );
}
static void Swap(ref int a,ref int b) {
int temp = a;
a=b;
GC.Collect(); // suppose this happens
b=temp;
}
}
which theoretically has only 2 access to the array
What confusing me is that I don't know what exactly happens when I pass an array element by ref. If Garbage Collector kicks in, while executing code in the Swap function, will be able to move the array ? or the array is pinned for the duration of the call ?
Mind that the above code is a simple test case. I want to use it in much more complex scenarios
Edit: As BrokenGlass pointed out, this is answered by Eric Lippert here C# parameters by reference and .net garbage collection
The array will not be pinned and GCollector can move it and will update accordinly any ref to an element of it, that resides on the stack
The Swap function still access the array 3 or 4 times, the Swap function does not offer any performance adavantage over the simpler code. It might be useful if it is reused.
static void Swap(ref int a, ref int b)
{
int temp = a; //<-- Here, a is in the array
a=b; //<-- a and b are in the array
b=temp; //<-- b is in the array
}
The garbage collector will not release memory you have a reference to, as happens when you pass by reference.
The stack could look like this:
qSort() has a reference to the array
Swap()
So if GC.Collect() executes in swap there is still a reference to the array in qSort() which means it won't be collected.

Dynamically setting value on array of pointers to integers

I have a multidimentional array of pointers to integer (of unknown rank) being passed into my function as such:
public unsafe static void MyMethod(Array source, ...)
{
//...
}
Multidimensional arrays of pointers are being constructed outside of the method and being passed in. Here's an example:
int*[,,,] testArray = new int*[10,10,5,5];
MyMethod(testArray);
How can I set a value at an runtime-computed index in the array? Array.SetValue(...) works perfectly fine for non-pointer arrays, but refuses to work for my int* array. Using reflector, I see SetValue reduces down to calling InternalSetValue which takes an object for the value but it's marked as extern and I can't see the implementation. I took a shot in the dark and tried passing in boxed pointer, but no luck.
This works:
unsafe static void MyMethod(int** array)
{
array[10] = (int*)0xdeadbeef;
}
private static unsafe void Main()
{
int*[, , ,] array = new int*[10, 10, 10, 10];
fixed (int** ptr = array)
{
MyMethod(ptr);
}
int* x = array[0, 0, 1, 0]; // == 0xdeadbeef
}
Does that help?
Question to the experts: Is it wrong to assume that the array is allocated consecutively in memory?
This doesn't work because it's not possible to box a pointer in .NET, so you can never call the Array.SetValue and pass an int*.
Can you declare MyMethod to accept int*[,,,] instead?
Edit: for further reading, an interesting recent post from Eric Lippert.

Categories

Resources