Deep C# - What's The Matter With Pointers?
Written by Mike James   
Thursday, 21 November 2019
Article Index
Deep C# - What's The Matter With Pointers?
Inherent dangers
Fixed Arrays
Memory Allocation

 

Banner

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.

For example,

int[] MyArray = new int[10];
for (int i = 0; i < 10; i++) MyArray[i] = i;
int* pMyArray = &MyArray[0];
MessageBox.Show((*pMyArray).ToString());

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[0] 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:

fixed(pointer declaration){
 instructions to be carried
 out while data is fixed
}

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. 

For example:

fixed (int* pMyArray= &MyArray[0]){
 MessageBox.Show((*pMyArray).ToString());
}

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[0] as in:

fixed (int* pMyArray= MyArray){
 MessageBox.Show((*pMyArray).ToString());
}

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.

pointer

Pointer Arithmetic

If you want to access other array elements then you simply use pointer arithmetic as in:

fixed (int* pMyArray= MyArray){ 
  MessageBox.Show((*pMyArray+5).ToString());
}

which displays MyArray[5].

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

pointer+5*sizeof(pointertype);

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[5] is a synonym for *pointer+5:

fixed (int* pMyArray = &MyArray[0]){
 MessageBox.Show(pMyArray[5].ToString());
}

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:

fixed (int* pMyArray= MyArray){
 int* ptemp = pMyArray;
 MessageBox.Show((*++ptemp).ToString());
}

which displays the contents of MyArray[1].

This sort of pointer manipulator works with multidimensional arrays. For example:

int[,] MyArray = new int[10,10];
fixed (int* pMyArray= &MyArray[0,0]){
 for (int i = 0; i < 100; i++){
  *(pMyArray + i) = i;
 }
}

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.

csharp

Structs

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:

public struct MyStructType{
 public int x;
 public int y;
};
MyStructType MyStruct=new MyStructType();
MyStructType* pMyStruct = &MyStruct;

Now how do you access a field using a pointer? You can use the fairly obvious:

(*pMyStruct).x = 1;

That is, dereference the pointer and use the usual dot selector.

However in a homage to the C++ usage you can also write: 

pMyStruct->y = 2;
MessageBox.Show(pMyStruct->x.ToString());

That is, the -> dereferences the pointer and selects the field in one go.

 

Strings

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.

For example:

string MyString = "Hello pointer world";
fixed (char* pMyString = MyString){
 MessageBox.Show((*(pMyString + 6)).ToString());
}

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.

 

Banner

<ASIN:1449320104>

<ASIN:0735683204>

<ASIN:1494208393>

<ASIN:1430242337>

 



Last Updated ( Saturday, 23 November 2019 )