|Deep C# - What's The Matter With Pointers?|
|Written by Mike James|
|Thursday, 21 November 2019|
Page 3 of 4
Pointers, Arrays And Fixed
There is a very close relationship between pointers and arrays, indeed you could say that pointers in languages such as C and C++ were introduced just so that it was possible to create arrays.
In principle the address of the first element of an array can be used to find any element of an array but things are a little more complicated.
This should create a pointer to the first element of the array but if you try it you will discover that you simply get an error to the effect that you can’t take the address of an unfixed expression.
The reason is that while MyArray is just an integer variable the compiler knows that the array is a managed object and can be moved at any time.
If you were to take the address of an array and then it moved the address would be useless and the pointer would end up pointing to some other location. You can see the danger in a pointer not pointing at what you thought is was pointing at.
To take a meaningful array address you have to use the fixed keyword:
The fixed construction tells the compiler that the array or any data type in the pointer declaration should not change its location until the end of the fixed block. In other words within the fixed block it is safe to use the pointer.
will work and will display the contents of the first element of the array.
You can also use the array name as a shorthand for &MyArray as in:
Notice that the pointer declared in the fixed statement goes out of scope when it ends so you can’t use pMyArray unless the array is fixed.
If you want to access other array elements then you simply use pointer arithmetic as in:
which displays MyArray.
Notice that this is rather more subtle than you might think as adding 5 to the address of the start of the array actually adds 5 times the size of a single integer element.
That is, the arithmetic operators have been overloaded to work in units of the size of the data type being pointed to. There is a sizeof operator which returns the size of any value type and this is used to work out what to add to a pointer.
That is, pointer+5 is translated to
That is pointer+n doesn't mean add n to the address in pointer but move on n elements in the array.
To complete the connection between arrays and pointers you can also use array indexing as a shortcut to dereferencing and pointer arithmetic.
That is pointer is a synonym for *pointer+5:
There is a restriction on the use of the fixed pointer in that it cannot be modified within the fixed statement.
This isn’t a problem as you can simply make a copy of it:
which displays the contents of MyArray.
This sort of pointer manipulator works with multidimensional arrays. For example:
This initialises a two-dimensional array by accessing it as a linear block of memory. Of course, the order in which the array is initialised depends on how it is stored in memory and I leave it to you to breakpoint the example and discover if it is stored in row or column order.
It is this sort of trick, i.e. accessing a 2D array as if it was a 1D structure, that made, and still makes to some, pointers so attractive.
Notice that you can initialise multiple pointers within a fixed statement as long as they are all of the same type. To initialise multiple pointers of different types you have to use nested fixed statements one for each type.
It is time now to turn our attention to structs and pointers to structs.
You might well imagine that if an array is something you have to fix before using pointers to it then you would certainly have to fix a struct in the same way. You don’t have to because a struct is a value type and allocated on the stack. So you can use:
Now how do you access a field using a pointer? You can use the fairly obvious:
That is, dereference the pointer and use the usual dot selector.
However in a homage to the C++ usage you can also write:
That is, the -> dereferences the pointer and selects the field in one go.
It is usually said that you can’t have a pointer to a string because a string is a managed object but, just like an array, you can fix a string and then you can initialise a char pointer to the first character in the string.
creates a string in the usual way, fixes it and obtains a char pointer to its first char. Then we can perform pointer arithmetic to access the 6th character in the string.
|Last Updated ( Saturday, 23 November 2019 )|