Getting an unsafe fixed pointer to the start of a rectangular array - c#

Consider a 2D, rectangular array. Say:
int[,] values = new int[len1, len2];
How can you iterate through all of its values in unsafe code?

The following works in an unsafe context.
fixed (int* baseOffset = values)
{
var offset = baseOffset;
var count = len1 * len2;
for (int i = 0; i < count; i++)
{
int value = *offset;
// Do whatever you need to do here
offset++;
}
}
Note that to get a pointer to the first item in an array, the types must match. So if you have a byte* which you want to treat as ushort*, you cannot cast the pointer within the fixed statement's parentheses, although you can do this within the block.

Related

How do i create a struct in C# that contains an array but does not use heap?

What i need:
a polygon with arbitrary amount of vertices ( or at least up to max number of vertices )
it should be a struct, so that it can be fast and can be assigned / passed by value
It seems like i can't use arrays or collections for storing vertices, because then my polygon struct would point to objects on a heap, and when one polygon is assigned to another one by value only shallow copy would be performed, and i would have both polygons pointing to the same vertex array. For example:
Polygon a = new Polygon();
Polygon b = a;
// both polygons would be changed
b.vertices[0] = 5;
Then how do i create a struct that can have arbitrary number (or some fixed number) of vertices, but without using heap at all?
I could just use lots of variables like v1, v2, v3 ... v10 etc, but i want to keep my code clean, more or less.
You have the option to define your array with the fixed keyword, which puts it in the stack.
But you cannot directly access the elements of the array, unless you are in an unsafe context and use pointers.
To get the following behavior:
static void Main(string[] args)
{
FixedArray vertices = new FixedArray(10);
vertices[0] = 4;
FixedArray copy = vertices;
copy[0] = 8;
Debug.WriteLine(vertices[0]);
// 4
Debug.WriteLine(copy[0]);
// 8
}
Then use the following class definition:
public unsafe struct FixedArray
{
public const int MaxSize = 100;
readonly int size;
fixed double data[MaxSize];
public FixedArray(int size) : this(new double[size])
{ }
public FixedArray(double[] values)
{
this.size = Math.Min(values.Length, MaxSize);
for (int i = 0; i < size; i++)
{
data[i] = values[i];
}
}
public double this[int index]
{
get
{
if (index>=0 && index<size)
{
return data[index];
}
return 0;
}
set
{
if (index>=0 && index<size)
{
data[index] = value;
}
}
}
public double[] ToArray()
{
var array = new double[size];
for (int i = 0; i < size; i++)
{
array[i] = data[i];
}
return array;
}
}
A couple of things to consider. The above needs to be compiled with the unsafe option. Also the MaxSize but be a constant, and the storage required cannot exceed this value. I am using an indexer this[int] to access the elements (instead of a field) and also have a method to convert to a native array with ToArray(). The constructor can also take a native array, or it will use an empty array to initialize the values. This is to ensure that new FixedArray(10) for example will have initialized at least 10 values in the fixed array (instead of being undefined as it is the default).
Read more about this usage of fixed from Microsoft or search for C# Fixed Size Buffers.
Heap array field
struct StdArray
{
int[] vertices;
Foo(int size)
{
vertices = new int[size];
}
}
Stack array field
unsafe struct FixedArray
{
fixed int vertices[100];
int size;
Foo(int size)
{
this.size = size;
// no initialization needed for `vertices`
}
}
If it suits your logic, you could use a Span<T>, which is allocated on the stack. Read more here
One other way to just copy the array with a copy constructor
public Polygon(Polygon other)
{
this.vertices = other.vertices.Clone() as int[];
}
then
var a = new Polygon();
a.vertices[0] = 5;
var b = new Polygon(a):
Debug.WriteLine(a.vertices[0]);
// 5
Debug.WriteLine(b.vertices[0]);
// 5
b.vertices[0] = 10;
Debug.WriteLine(a.vertices[0]);
// 5
Debug.WriteLine(b.vertices[0]);
// 10

Sum value to previous value in array

What I'm doing wrong? What I'm trying to do is to add to existing array linesLat values but for next value to insert in linesLat is to take previous from array and summ stepLong. But at the end getting error.
static void Main(string[] args)
{
var stepLong = (10.6237 - 5.9216) / 1000;
var stepLat = (47.7245 - 45.7368) / 1000;
double[] linesLat = { 45.7368 };
double[] linesLong = { 5.9216 };
for (var i = 1; i <= 999; )
{
linesLat[i] = linesLat[i - 1] + stepLat; // throws an error
i++;
}
}
Additional information: Index was outside the bounds of the array.
You should really go back to basics.
Array as a limited size and it will be on the exact size you declare it to be.
In your case you allocated two arrays in the size of 1 (Due to explicit initialization).
double[] linesLat = { 45.7368 }; // Size 1
double[] linesLong = { 5.9216 }; // Size 1
Meaning you can't loop from [0, 999], when you will try to take the value from position 1 (Because C# arrays are zero based; The first element is in the 0 place and not 1) you will get a KABOOM meaning you will get an exception telling you, your index (probably 1) is outside of the legal array bounds.
Solution: You should change your solution to declare a bigger array as #i_a_joref suggested.
var linesLat = new double[1000];
linesLat[0] = 45.7368;
Additionally, your loop can be written more properly:
for (var i = 1; i < linesLat.Length; i++)
{
linesLat[i] = linesLat[i - 1] + stepLat;
}
Possible solution variation for your problem.
If the only goal is to get the sum of the last formula, than array is redundant.
double sumOfFormula = 45.7368;
for (var i = 0; i < 1000; i++) // Will run [0, 999] 1000 iterations
{
sumOfFormula += stepLat;
}
Console.WriteLine("Sum: ", sumOfFormula);
You declared linesLat as an array of size one. If you want to put 999+ elements in it, you need to declare a bigger array.
Your array has a lenght of 1, and you try to iterate up to 999.
You need to instanciate your array with a lengh of 999
double[] linesLat = new double[999];
Your array have size of 1 and in for loop you are trying to access indexes greater then array size.
Just change:
double[] linesLat = { 45.7368 };
to:
double[] linesLat = new double[1000];
linesLat[0] = 45.7368;

In C# datatype* means

what exactly this means
Datatype*
Example : int*, double*, char*,...
Can any one give some explanation for it please.
Thanks in Advance.
It's an unsafe pointer. Unsafe Code Tutorial
Here is an examples using it: How to pull out alpha and count digits using regex?
private static unsafe List<long> ParseNumbers(char[] input)
{
var r = new List<long>();
fixed (char* begin = input)
{
char* it = begin, end = begin + input.Length;
while (true)
{
while (it != end && (*it < '0' || *it > '9'))
++it;
if (it == end) break;
long accum = 0;
while (it != end && *it >= '0' && *it <= '9')
accum = accum * 10 + (*(it++) - '0');
r.Add(accum);
}
}
return r;
}
Have a look at Pointer types (C# Programming Guide)
In an unsafe context, a type may be a pointer type, a value type, or a
reference type. A pointer type declaration takes one of the following
forms:
type* identifier;
void* identifier; //allowed but not recommended
Those are Pointer types.
In an unsafe context, a type may be a pointer type as well as a value type or a reference type. A pointer type declaration takes one of the following forms:
type* identifier;
void* identifier; //allowed but not recommended
They are called Pointer types
In an unsafe context, a type may be a pointer-type as well as a
value-type or a reference-type. However, a pointer-type may also be
used in a typeof expression outside of an unsafe context
as such usage is not unsafe.
A pointer-type is written as an unmanaged-type or the keyword void,
followed by a * token:
The type specified before the * in a pointer type is called the
referent type of the pointer type. It represents the type of the
variable to which a value of the pointer type points.
Unlike references (values of reference types), pointers are not
tracked by the garbage collector—the garbage collector has no
knowledge of pointers and the data to which they point. For this
reason a pointer is not permitted to point to a reference or to a
struct that contains references, and the referent type of a pointer
must be an unmanaged-type.
This is pointer in c#
please take a time to read this Unsafe Code Tutorial
using System;
class Test
{
// The unsafe keyword allows pointers to be used within
// the following method:
static unsafe void Copy(byte[] src, int srcIndex,
byte[] dst, int dstIndex, int count)
{
if (src == null || srcIndex < 0 ||
dst == null || dstIndex < 0 || count < 0)
{
throw new ArgumentException();
}
int srcLen = src.Length;
int dstLen = dst.Length;
if (srcLen - srcIndex < count ||
dstLen - dstIndex < count)
{
throw new ArgumentException();
}
// The following fixed statement pins the location of
// the src and dst objects in memory so that they will
// not be moved by garbage collection.
fixed (byte* pSrc = src, pDst = dst)
{
byte* ps = pSrc;
byte* pd = pDst;
// Loop over the count in blocks of 4 bytes, copying an
// integer (4 bytes) at a time:
for (int n =0 ; n < count/4 ; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren't
// moved in blocks of 4:
for (int n =0; n < count%4; n++)
{
*pd = *ps;
pd++;
ps++;
}
}
}
static void Main(string[] args)
{
byte[] a = new byte[100];
byte[] b = new byte[100];
for(int i=0; i<100; ++i)
a[i] = (byte)i;
Copy(a, 0, b, 0, 100);
Console.WriteLine("The first 10 elements are:");
for(int i=0; i<10; ++i)
Console.Write(b[i] + " ");
Console.WriteLine("\n");
}
}
and output
The first 10 elements are:
0 1 2 3 4 5 6 7 8 9
i tooth this will give you an idea to understated pointer in c# and also how to use it
best of luck

passing arrays in c#

Hi i am working on Grade Calculation. My problem here is if the length of string array is longer that int array it works skipping the last 2 grades.
ex:
int[] unit = new int[] {1,-3,3,4};
string[] letter_grade = new string[] {"A", "B","B","W","D","F"};
but if length of int array longer than that of string array its not working its throwing error Index was outside the bounds of the array.
int[] unit = new int[] {1,-3,3,4,5,6,7};
string[] letter_grade = new string[] {"A", "B","B"};
so my question how do i make it work for both??
int length = unit.Length;
int no_units = length;
double totalGrade_Points = 0.0;
int totalno_units = 0;
totalGPA = 0;
for (int i = 0; i < unit.Length; i++)
{
entrygot = findGpaListentry(letter_grade[i]); //Index was outside the bounds of the array.
if (entrygot != null)
{
//some code calculation
}
}
For array indexing you must have starting and stopping condition defined very well. For accessing two arrays either they must be equal or they are compared under certain valid conditions. Have a look at this:
for(int i=0;i<unit.length;i++){
entrygot = findGpaListentry(letter_grade[i]);// only if letter_grade is valid under all values of i i.e unit.length
}
// either you have to check as if;
if(lenght_of_letter_grade < i-1)
//then access
entrygot = findGpaListentry(letter_grade[i]);
You can't just check if the array item is null, because you would be out of the bounds of the array and you will get an exception before the null check occurs.
I would check the length of the array on each iteration...
for (int i = 0; i < unit.Length; i++)
{
if (currentArray.Length < i - 1) { break; }
// other code...
}
I think in your case, the number of elements will never be large hence performance wont be an issue. So I think you should be using a List instead of an array. With an array you will have to be insert checks each time some logic changes or you add other functionalities.
foreach loop is best for your scenerio.
foreach (string s in letter_grade)
{
entrygot = findGpaListentry(s);
if (entrygot != null)
{
//some code calculation
}
}

Safe Indexing Inside Unsafe Code

Good morning, afternoon or night,
Foreword: The code below does nothing really useful. It is just for explanation purposes.
Is there anything wrong with allocating and using an array "the safe mode" inside unsafe code? For example, should I write my code as
public static unsafe uint[] Test (uint[] firstParam, uint[] secondParam)
{
fixed (uint * first = firstParam, second = secondParam)
{
uint[] Result = new uint[firstParam.Length + secondParam.Length];
for (int IndTmp = 0; IndTmp < firstParam.Length; Result[IndTmp] = *(first + IndTmp++));
for (int IndTmp = 0; IndTmp < secondParam.Length; Result[IndTmp + firstParam.Length] = *(second + IndTmp++);
return Result;
}
}
or should I instead write a separate, unsafe method accepting only pointers and lengths as parameters and use it in the main function?
Also, is there any way I can replace the allocation with
uint * Result = stackalloc uint[firstParam.Length + secondParam.Length]
so that I can use Result as a pointer and still be able to return Result as an uint[]?
Thank you very much.
I see nothing wrong with doing that, although if you're using pointers for speed, it probably makes sense to use a pointer into Result also. Maybe like this:
public static unsafe uint[] Test (uint[] firstParam, uint[] secondParam)
{
uint[] Result = new uint[firstParam.Length + secondParam.Length];
fixed (uint * first = firstParam, second = secondParam, res = Result)
{
for (int IndTmp = 0; IndTmp < firstParam.Length; IndTmp++)
*(res + IndTmp) = *(first + IndTmp);
res += firstParam.Length;
for (int IndTmp = 0; IndTmp < secondParam.Length; IndTmp++)
*(res + IndTmp) = *(second + IndTmp++);
}
return Result;
}
DO NOT return anything you stackalloc! Once the function returns, the area allocated on the stack is reused, giving you an invalid pointer.

Categories

Resources