2

Apologies if this issue has already come up: I have looked on the questions asked and googled but did not see any explanation.

I am starting to use C#, after nearly 30 years of C, a few months of Java and a couple of years of C++ 15 years ago ... which may explain my perplexity. In C#, if I want an array of int, I can do:

int[] a = new int[10];

At this point, I can access the elements of the array

a[0] = 1; // This is OK

I now have a class (say, SomeClass) and I want to create an array of these:

SomeClass[] o = new SomeClass[10]

I would expect (for symmetry) that I can access the elements of the array, but

a[0].someField = val; // exception, must do a[0] = new SomeClass(); first

So, the first new[]really only allocates 10 pointers, not 10 objects, despite the syntax. I have to repeat that my knowledge of C# is not perfect (:)), so please correct me if I am wrong, but another problem with this (aside from what in my opinion is a confusion between values and references) is memory fragmentation: with C I would have allocated 10 "pointers" (malloc(10 * sizeof (void *));, then allocated the whole area (malloc(10 * sizeof (SomeClass)), then used offsets to initialize the array of pointers to point to the area just malloc'd, minimizing the memory fragmentation ... is there anything similar in C#?

  • Instead of pointers, think C++ references. C# classes are called reference types for a reason. You can have an array of class instances just like you can have a `std::vector` of instances. You have to add something in there before you can access it – Panagiotis Kanavos Sep 29 '16 at 10:40
  • If you change it to `SomeStruct` sure, but you can't get an array of "objects themselves" if they are of a reference type. – harold Sep 29 '16 at 10:45

1 Answers1

2

Unlike C++ array of class type which has class instances, C# array of class type creates an array of references. This is similar to creating a C++ array of pointers:

SomeClass *o[10] = {0};

Before making any access to o[i] you need to assign it a new object:

cout << o[0]->a;      // ERROR: o[0] is nullptr
o[0] = new SomeClass; // Assign a new object
cout << o[0]->a;      // Works fine

This is the same way that it works in C#: you must assign an object to an array element prior to accessing its attributes.

The reason you don't need to do the same with an int in C# is that int is a value type. Declaring an array of value types populates elements with default values. This applies to user-defined structs as well.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thanks, that's what I thought. I have to get used to the new syntax. In C it is, in my opinion, more explicit whether you refer to "references" (pointers, also addresses) and objects (areas pointed by the addresses). –  Sep 29 '16 at 10:46
  • @MarcoBertoncin You could think of class-typed objects in C# as carrying an implicit asterisk. This streamlined the syntax at the expense of creating a tiny bit of an initial confusion. – Sergey Kalinichenko Sep 29 '16 at 11:01
  • @MarcoBertoncin, also, have a look at Value Types vs Reference Types ([this](http://stackoverflow.com/a/5057284/3276027) is a good start). They have different behavior from this point of view: oversimplifying, a value type variable will never be null. Int (actually an alias for System.Int32 struct) is the first exaample of value type – Gian Paolo Sep 29 '16 at 11:05
  • Thanks all. I understand. As an aside, I completely agree with the implementation (allocate references and objects only after: you may only need a few and this improves memory usage). What about memory fragmentation? (My second point in the original post). –  Sep 29 '16 at 14:49
  • 1
    @MarcoBertoncin Since C#'s references are slightly more than pointers, because they must participate in the garbage collection game, C# offers no API for co-locating your references with your objects. The flip side of this is that [.NET can deal with fragmentation automatically](https://blogs.msdn.microsoft.com/mariohewardt/2013/06/26/no-more-memory-fragmentation-on-the-net-large-object-heap/). – Sergey Kalinichenko Sep 29 '16 at 14:55