Отсутствует IndexOutOfRangeException при попытке обратиться к несуществующему индексу строки в unsafe-коде

Почему не вылетает исключение? Как я понимаю, char* - непрерывная область памяти из 4 элементов и если я обращаюсь к [10], то обращаюсь к несуществующей ячейки памяти. Но если память выделяется только для 4 элементов, то почему если я обращусь к p[10] - то всё будет нормально и выведится c.

unsafe
{
   string str = "hello";
   fixed(char* p = str)
   {
      p[10] = 'c';
      Console.WriteLine(p[10]); //c
   }
}

Ответы (1 шт):

Автор решения: aepot

p[10] - это адрес p + 20 байт (каждый элемент char* = 2 байта), это не индекс в массиве, не путайте.

Вот смотрите

int a = ~0;
byte* ptr = (byte*)&a;
byte x = ptr[3];
Console.WriteLine(x); // 255

Здесь вообще нет массива.

В лучшем случае при попытке читать или писать область памяти за пределами индекса, вы попадете на невыделенную текущему приложению память и получите исключение AccessViolationException: Attempted to read or write protected memory..

Если еще раз повезёт, вы попадете в свободную область памяти, не выделенную под хранение данных, но выделенную вашему приложению, тогда при создании очередной переменной данные в этой области могут быть перезаписаны, и то что вы туда положили - потеряно.

А вот если не повезет, вы просто повредите данные в других переменных или вообще сломаете экземпляр другого класса, например сейчас вы повредили данные, а приложение упадет через минуту совсем в другом месте по какой-то непонятной причине.

Поэтому, код небезопасный, вы можете творить что угодно, но это так же означает, что ответственность за целостность данных лежит не на компиляторе, а на вас лично.

Кстати, как вам такое?

string text = "hello";
fixed (char* ptr = text)
{
    int* iPtr = (int*)ptr;
    Console.WriteLine(iPtr[-1]); // 5
}

Да, это та самая длина строки text.Length. Уж отрицательных то индексов вы точно не видели. iPtr[-1] здесь адрес начала данных строки -4 байта, потому что int - это 4 байта.

Другими словами, запись адреса памяти ptr[i] - это краткий эквивалент записи *(ptr + i).

→ Ссылка