Переписываю код с Си на C#. Столкнулся со следующей проблемой.
Вот код на си.
int right[2 * par - 1];
int left[2 * par - 1];
...
void func()
{
int *p;
// some code
if (k & mask)
p = &right[*p];
else
p = &left[*p];
}
А вот мой вариант на C#.
int[] right = new int[2 * par - 1];
int[] right = new int[2 * par - 1];
...
unsafe void func()
{
int *p;
//some code
if ((k & mask) != 0)
p = &right[*p];
else
p = &left[*p];
}
В if VS выдаёт следующую ошибку
Адрес нефиксированного выражения можно получить только внутри инициализатора оператора fixed
Пока не понимаю, как решить проблему, используя этот оператор. Помогите разобраться, пожалуйста.
P.S.
используя оператор fixed, как показано в примере из msdn, ничего не получилось, поскольку в том примере необходимо в круглых скобках писать конструкцию типа int *p = &variable, а у меня уже в начале кода идёт объявление int *p, и в процессе работы оно успешно присваивается и изменяется, но вот доходя до if, вылетает ошибка.
Переписывать подобный код на C# "в лоб" - не лучшая идея.
Фактически, в этом коде указатель p используется для обозначения сразу массива и его элемента. И раз уж язык C# не дает так делать - можно вернуться к полной форме:
int[] parray;
int[] pindex;
//some code
if ((k & mask) != 0)
{
int v = parray[pindex]; // Ранее *p
parray = right;
pindex = v;
}
else
{
int v = parray[pindex]; // Ранее *p
parray = left;
pindex = v;
}
Если подобного кода много - можно завести себе в помощь структуру, которая будет себя вести аналогично указателю на ячейку массива:
struct ArrayCell<T>
{
private readonly T[] array;
private readonly int index;
public ArrayCell(T[] array, int index)
{
this.array = array;
this.index = index;
}
public T Value
{
get { return array[index]; }
set { array[index] = value; }
}
}
static class ArrayCellExtensions
{
public static ArrayCell<T> Cell<T>(this T[] array, int index) => new ArrayCell<T>(array, index); // Немного сахара
}
// ...
ArrayCell<int> p;
//some code
if ((k & mask) != 0)
p = right.Cell(p.Value);
else
p = left.Cell(p.Value);
Здесь два варианта, если массивы создаются и живут внутри функции, и их размер небольшой то можно их выделить на стеке:
int* right = stackalloc int[2 * par - 1];
...
if ((k & mask) != 0)
p = &right[*p];
В вашем случае это не ок, потому что размер массива у вас переменный, можно нарваться на StackOverflow ); Вариант два, зафиксировать расположение в памяти:
fixed (int* _right = &right[0], _left = &left[0])
{
...
if ((k & mask) != 0)
p = &_right[*p];
}
Работать с укзателями на массив, можно только внутри блока фиксед. Можно схитрить и написать как-нибудь:
if ((k & mask) != 0)
fixed(int* ptr = &right[*p]) { p = ptr; }
но первая же сборка мусора, может переместить данные куда угодно и указатель соответственно станет не валиден.
p.s. у вас проблема не в присваивании p и не в if, а в попытке взять адрес массива который не закреплен в памяти.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости