Can arrays be resized in C# - c#

Just out of curiosity, coming from C background, I knew that Array cannot be resized.
However, while I see in C#, it's so easy to do like below
var arr = new int[] {1,2,4,6};
arr = new int[2];
Also, there is a method available
Array.Resize(ref arr, 10);
How is it possible?
Thanks!

These operations aren't resizing the array. They're creating a new array of a new size.
Note in the first example that you call new twice. So you're creating two arrays.
In the second example, the documentation explains the same:
This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.

The source code for the Array class can be found here.
This is the relevant portion:
T[] larray = array;
if (larray == null) {
array = new T[newSize];
return;
}
if (larray.Length != newSize) {
T[] newArray = new T[newSize];
Array.Copy(larray, 0, newArray, 0, larray.Length > newSize? newSize : larray.Length);
array = newArray;
}
As you can see, it allocates a new array and then copies whatever it can from the existing array into the new array.

Arrays cannot be resized in C#.
Your first example assigns a new array to the variable arr, it doesn't resize the existing array.
Also Array.Resize is a misnomer: it actually creates a new array and copies the values.
The clue to that is with the ref keyword, which indicates that Array.Resize will be reassigning to arr.

Each of those examples actually creates a brand new array, copies the items one by one from the old to the new, and updates the reference.
If you have a collection where the size will change over time, you're almost always better off using a generic List<T>.

Related

Apply "new" to only one dimension of multi-dimensional array?

I have this C# program, and it has the following code:
/*10 data for one peprson */
private int[] data = new int[10];
private void SomeMethod()
{
/*More code*/
this.data = new int[10];
/*More code*/
}
This program calls this method when an event occurs, and every time that happens, this one-dimensional array gets a "new" instance of an array of size 10, and refresh the array. Kinda like resetting it.
Now, I was told to write a new program that does the same thing, except that there are 5 people now. So I created a 2-dimensional array like
private int[,] data = new int[5, 10];
which will be able to store 10 data for each of the 5 people.
Now I am at a loss on how to refresh/reset only one person's data from this 2-d array. I tried
private void SomeMethod(int index) /*index 0 - 4 for each of the 5 people*/
{
this.data[index] = new int[10];
}
but this clearly does not work, and I get an error saying I am missing a dimension. Is there a way to achieve this?
For the time being, I am using
private void SomeMethod(int index) /*index 0 - 4 for each of the 5 people*/
{
for(int i=0; i<10; i++)
this.data[index, i] = 0;
}
When I tested it with the original code, I noticed that every time it got a "new" instance, it was assigning 0's to the array. Now the difference is that the original one is referencing the new instance with no data (and hence 0?), and the rewritten one is overwriting with 0's.
Do these two basically work the same way, program's-function-wise?
There's nothing wrong with the code you have. It's even likely faster than creating the new array. But if you really want to, you can use a jagged array instead:
private int[][] data = new int[5][];
//...
private void SomeMethod(int index) /*index 0 - 4 for each of the 5 people*/
{
this.data[index] = new int[10];
}
But arrays seem weird for this. A List<T> might be better:
private List<int[]> data = new List<int[]>();
where you can then use the .Add() method as you get new records, and use the Count property to know how many you've added.
Moreover, it's common to find out the int[10] array was actually a stand-in for named fields, where each position in the array has meaning. In that situation, you're usually much better off building a class for this data, where each item in the array is a named field in the class (we'll just call it MyClass for now). Then you end up with something like this:
private List<MyClass> data = new List<MyClass>();

Filling a list with random bytes

I'm trying to fill a buffer with random bytes. The buffer is defined as a list of bytes. This is something that I want to keep as it is. Here is the definition:
namespace NameofProject
{
public partial class Form1 : Form
{
List<byte> buff = new List<byte>();
}
}
And my first attempt is
public static void RandomFillBuffer()
{
Random rnd = new Random();
rnd.NextBytes(buff);
}
Yet this gives such an error for buff:
An object reference is required for the non-static field, method, or property 'Form1.buff'
Then I just deleted the word "static" (I am not sure whether this is true) and it becomes "public void RandomFillBuffer()", but this time I am getting this error for buff:
Argument 1: cannot convert from 'System.Collections.Generic.List' to 'byte[]'
I'd appreciate any help to solve any of the 2 errors if they make sense.
You're getting that problem because NextBytes() expects an array, but you're trying to pass a List<>. One way to solve it would be to change your List<> to an array:
byte[] buff = new byte[someSize];
You're going to have to figure out what someSize should be (it's up to you). You can't fill something without it having a size. Otherwise, how would it know when it's done?
The problem you are having is that NextBytes fills an array[] not a list. You need to define an array with an index of its size
// Put random bytes into this array.
byte[] array = new byte[8];
// Fill array with random bytes.
Random random = new Random();
random.NextBytes(array);
First: you tried to make your method static (it means that this method is not associated with any instance of the object but instead with the class of objects), and tried to reference not static member from it (your buff is not static and thus is associated with a particular instance, a particular Form in your case).
Second: you tried to use Random.NextBytes(System.Byte[]) but provided System.Collections.Generics.List<System.Byte> as an argument.
The code below should work for you (this code assumes at least that buff already has some data and so has a positive length):
var generator = new Random();
var array = new Byte[buff.Count]; // create a local array of the same size as your list
generator.NextBytes(array); // fill the array with random bytes
buff = array.ToList(); // copy array to a new list and let field "buff" reference this freshly created list
Please, note, that this code is not optimal because it copies an array. But it does what you want, I guess.

c # - copying elements of one array to another - compile error

Learning some basics.. I'm trying to copy elements of an array to another. Let's say I don't know the size of the array 'bar'. So, I create an empty array 'arr' to copy the elements to bar into. The code below doesn't work.
It works if I replace
string[] arr ={} to string[] arr ={"",""}
How to declare an empty array and what should I modify in my code to achieve my goal?
Thanks!
//code
string[] bar = {"test", "user"};
string[] arr = {};
//iterate from the first to the last element of array bar
for (int i =0;i<bar.Length-1;i++)
{
Console.WriteLine("copy");
//copy string from bar to arr
arr[i]= bar[i];
//display the copied content from new array
Console.WriteLine(arr[i]);
}
in C#, arrays are of a fixed size. So when you create your array with size 0, you can't change the number of items it will contain, without re-instantiating it.
If you want to use a collection you can actively add/remove from (as is very common), consider using a List<T>:
string[] bar = {"test", "user"};
List<string> list = new List<string>();
for (int i =0;i<bar.Length-1;i++)
{
list.Add(bar[i]);
Console.WriteLine(list[i]);
}
By string[] arr = {}; you're instantiating an empty array of ZERO length, thus you need to define it like string[] arr = string[bar.Length];.
UPD:
Your code worked with string[] arr = {"",""}, because in this case you defined an array of length 2 using a two empty strings, but that's a code smell.
Arrays are fixed in size, which is why things like Lists are preferred over them.
In the case where you change your array definition to: string[] arr ={"",""} you are defining an array with a size of 2, same as your original array. When you try to copy it, the compiler already has everything allocated and ready to go, so it knows where position 0 and position 1 are in the array arr.
In the example in your code, where you have the array defined by string[] arr = {}; you are giving it an empty array (array size 0). The compiler has an issue, because it cannot reference position 0 or position 1 on an array that is empty.
You can modify the line as:
string[] arr = new string[4];
or
List<string> arr = new List<string>();
If you're going to use arrays, you'll want to create the second array as the same size as the first.
string[] bar = {"test", "user"};
string[] arr = new string[bar.Length];
If you know ahead of time that your array will be two, then you can just create it to be size two. Otherwise you'll want to inspect the size of the array you're copying from. If you know that you'll be adding and/or removing items, you'll want to use a different collection.

How to dynamically resize an array?

I have an array with Length = 3 and with values, for example {1,2,3}.
I need to dynamically resize it.
I know that I can use List or
Array.Resize(). But I need to know how to implement my own resize method?
You can try the following code. Create new array with new size and copy the old array data to the newly created array.
public static Array ResizeArray (Array oldArray, int newSize)
{
int oldSize = oldArray.Length;
Type elementType = oldArray.GetType().GetElementType();
Array newArray = Array.CreateInstance(elementType,newSize);
int preserveLength = System.Math.Min(oldSize,newSize);
if (preserveLength > 0)
{
Array.Copy (oldArray,newArray,preserveLength);
}
return newArray;
}
If this is just for practice then do it. but i suggest you use .Net Array.Resize() if you want to use it in your code. usually .Net libraries are best implemented and optimized.
Any way...you can do it with generic method
private static void Resize<T>(ref T[] array,int size)
{
T[] token = array.Take(size).ToArray(); // attempt to take first n elements
T[] temp = new T[size]; // create new reference
token.CopyTo(temp, 0); // copy array contents to new array
array = temp; // change reference
}
Note that you cannot do this without parameter ref. (The other way is to return array of course)
You may think arrays are passed by reference. thats true. But the references it self are passed by value. so whenever you try to change the reference it does not refer to the original array anymore. you can only change the contents. To make this possible you have to use ref to directly pass the reference into method.
About the code:
{1,2,3} if you resize it to 2 obviously it will remove the last parameter. so you will have {1,2}
if you resize it to 4 then it will give the array with new default values. either null for reference types or 0 for value types (false for Boolean type). here you will have {1,2,3,0}
int[] array = new[] {1, 2, 3};
Resize(ref array,4);
Console.WriteLine(array.Length); // outputs 4
Well, you may look on Array.Resize source code before making your own implementation =)
http://referencesource.microsoft.com/#mscorlib/system/array.cs,71074deaf111c4e3
If you want to resize the array use the build in method Array.Resize().It will be easier and faster.
If you need a dynamically sized data structure, use List for that.
You can always do array.ToList() -> fill the list and do .ToArray() later.
Make an array of the new desired size, copy all items over. Make the variable that referenced your old array reference the new one.
Code from MSDN:
public static void Resize<T>(ref T[] array, int newSize) {
if (newSize < 0) {
throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.Ensures(Contract.ValueAtReturn(out array) != null);
Contract.Ensures(Contract.ValueAtReturn(out array).Length == newSize);
Contract.EndContractBlock();
T[] larray = array;
if (larray == null) {
array = new T[newSize];
return;
}
if (larray.Length != newSize) {
T[] newArray = new T[newSize];
Array.Copy(larray, 0, newArray, 0, larray.Length > newSize? newSize : larray.Length);
array = newArray;
}
}
}

What is the difference between the following array declarations in c#?

I'm building a menu in my WinForm app and i was doing something like :
MenuItem[] items = new MenuItem[] { };
And after :
for (int namesIndex = 0; namesIndex < menuNames.Length; namesIndex++)
{
MenuItem item = new MenuItem(menuNames[namesIndex]);
for (int entriesIndex = 0; entriesIndex < menuEntries.GetLength(1); entriesIndex++)
{
item.MenuItems.Add(menuEntries[namesIndex, entriesIndex]);
}
items[namesIndex] = item;
}
And an IndeOutOfRangeException is thrown :
After this annoying exception i modified the array declaration with this :
MenuItem[] items = new MenuItem[] { null };
and everything works like a charm.
And now the question : Does anyone out there knows why the above array declaration works, and the other doesn't?
Thanks alot
You're using array initializers to construct the array, so the length of the array will be given by the data you provide.
The first example declares an array with a length of zero as you don't provide any elements. I.e. it cannot contain any elements.
The second example declares an array of length one.
MenuItem[] items = new MenuItem[] { };
This creates an array with 0 items in it.
MenuItem[] items = new MenuItem[] { null };
This creates an array with 1 item in it (it's null, but that still counts).
You probably want to initialize for the number of items you want (new MenuItem[menuNames.Length], for example). Or use new List<MenuItem>() instead, and call Add().
"Everything works like a charm" only to the extent that menuNames has exactly one item. You need to change the code as follows to make it work:
MenuItem[] items = new MenuItem[menuNames.Length];
The reason you saw a crash in the first case is that you created an array with zero items, while in the second case you created an array with one item. If menuNames has more than one element, your code would start crashing again.
Your for loop iterates over compares the loop variable to menuNames.Length, while your using the indexer of the items array. One of the two is wrong.
Additionally, if you want to be adding additional items to a collection, then you should almost certainly be using a List, not an array.

Categories

Resources