Ошибка при использовании указателей в c#

139
16 февраля 2018, 16:17

Переписываю код с Си на 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, вылетает ошибка.

Answer 1

Переписывать подобный код на 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);
Answer 2

Здесь два варианта, если массивы создаются и живут внутри функции, и их размер небольшой то можно их выделить на стеке:

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, а в попытке взять адрес массива который не закреплен в памяти.

READ ALSO
Как Отслеживать запросы ReacJS

Как Отслеживать запросы ReacJS

Прошу помощи найти инструмент для лова запросов ReacJS Уже замучился весь инет обрыскал не нашел ответа, как отследить запросы ReactJS

285
Не обновляются JS скрипты при нажатии F5 в Chrome

Не обновляются JS скрипты при нажатии F5 в Chrome

Походу не один я столкнулся с такой проблемой, но ответ в гугле найти не могуВообщем суть такая, сохраняю я код скрипта js, нажимаю f5 и f12->sources,...

333
Изменить число в строке javascript

Изменить число в строке javascript

Здравствуйте, такая задача: нужно написать функцию, которая будет выводить измененную строку, а именно если мы получаем строку 'foo' -> 'foo1', 'foo000'...

301