Я видел эту часть кода C# в одной из статей MSDN:
using System; class Test
{
public static unsafe void Main()
{
int* fib = stackalloc int[100];
int* p = fib;
*p++ = *p++ = 1;
for (int i=2; i<100; ++i, ++p)
*p = p[-1] + p[-2];
for (int i=0; i<10; ++i)
Console.WriteLine (fib[i]);
}
}
Я довольно плохо знаком с указателями. Я понимаю большую часть этого кода, но было бы замечательно, если кто-то может помочь мне понять эту строку в вышеупомянутом коде более подробно:
*p++ = *p++ = 1
Это просто ленивый (другие бы сказали идиоматический) способ записи
*p++ = 1;
*p++ = *p++;
или, возможно, лучше понять:
*p=1;
p++;
*p=1;
p++;
В приведенном выше коде вы генерируете 100 чисел в ряду Фибоначчи.
в строке * p ++ = * p ++ = 1, вы инициализируете первые 2 числа равными 1. т.е. заполнение числа 1 в местах, указанных указателем.
Изначально указатель указывает на 0. Когда вы выполняете * p ++, это означает, что указатель должен быть перемещен вперед на одно место от того места, на которое он указывает.
Таким образом, в этом случае значение в позиции 1 присваивается значению в позиции 2, которому присваивается значение «1». т.е. * p ++ = * p ++ = 1
Это означает, что в 0 и 1 позициях выделенной памяти значения установлены в 1.
Для более ясного понимания: p* указывает на некоторый адрес памяти, пусть это будет start
, прямо на другой адрес памяти, который равен start + sizeof(int)*100
, пусть это будет en
d.
В этом примере в 1 были установлены элементы по адресу start
и start + sizeof(int)
. Пост-инкремент (*p++
) означает, что сначала используется p*
, а затем он увеличивается на значение sizeof(int)
, второй *p++
означает, что теперь мы используем *p + sizeof(int)
, а затем он увеличивается еще раз и мы имеем *p + sizeof(int)*2
.
Вам нужно разбить вещи на части:
* p ++
Это делает две вещи: разыменование p и пост-инкремент. Т.е. показать, что находится по адресу p
сейчас (или присвоить ему) и после увеличить его (до следующей ячейки памяти).
Таким образом, два из них позволяют назначать начальную и вторую ячейки памяти (оставляя p
со ссылкой на третью).
C # позволяет назначать цепочки: a = b = 2
присваивает 2 обоим a
и b
.
NB не пробуйте это в C или C ++, изменяя одно и то же ( p
) более одного раза в одном выражении undefined. Но C # это определяет.
В C# *p++ = *p++ = 1;
эквивалентно:
*p++ = 1;
*p++ = 1;
Таким образом, первые 2 элемента массива (на которые первоначально указывал p
) инициализируются 1, а p остается указывать на третий элемент (элемент 2, используя нулевую нотацию).
В качестве отступления отметим, что аналогичное выражение в C/C++ имело бы неопределенное поведение, поскольку указатель p
модифицируется более одного раза без промежуточной "точки следования". Однако в C# выражение оценивается вполне определенным образом.
Первые три числа fib равны 0, 1, 1, и именно это делает код. (Ноль здесь пропущен)
Более понятно было бы написать:
*p++=1; // second fib
*p++=1; // third fib.