System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control) .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); aProp.SetValue(ListView1, true, null);
Ian имеет еще некоторую информацию об использовании этого на терминальном сервере.
В большинстве случаев выражение типа массива будет неявно преобразовано из "N-элементного массива T "to" указатель на T, и его значение будет установлено так, чтобы указывать на первый элемент массива. Исключение из этого правила - когда массив является операндом &
или sizeof
, или если массив является строковым литералом, используемым для инициализации другого массива в объявлении.
Итак, как все это связано с вашим кодом?
В строке
scanf("%d", &a);
вы применяете к массиву оператор &
. Это подавляет неявное преобразование из «массива T» в «указатель на T» и возвращает значение типа «указатель на массив T» или T (*) [N]
(отсюда ваше первое предупреждение ). Теперь оказывается, что значение указателя на массив и значение указателя на первый элемент массива совпадают, просто они имеют разные типы. Предположим, что a
находится по адресу 0x0001000:
expression type value note
---------- ---- ----- ----
a int * 0x0001000 implicitly converted to pointer
&a int (*)[N] 0x0001000
&a[0] int * 0x0001000
Вот почему ваш первый вызов scanf ()
«работает»; ты' при передаче значения правого указателя , но компилятор жалуется, потому что тип выражения не соответствует тому, что ожидает функция. Если бы вы написали
scanf("%d", a);
, вы бы не получали никаких предупреждений, так как тип a
будет принят как int *
, что и есть scanf ()
] ожидает. Обратите внимание, что это идентично вызову
scanf("%d", &a[0]);
. Что касается b
...
Вы явно объявляете b
как указатель на int и назначаете ему блок памяти. Когда вы применяете к нему оператор и
, вы получаете адрес переменной b
с типом int **
(отсюда второй предупреждение), а не адрес, на который указывает b
.
expression type value note
---------- ---- ----- ----
b int * 0x0040000 value contained in b
&b int ** 0x0001000 address of b
В этом случае вы просто передаете неразмеченный b
:
scanf("%d", b);
Это нормально ...
Во-первых, scanf требует указателя. "a" и "b" уже являются указателями! Итак:
/* 1 */
scanf("%d", a);
printf("%d\n", a[0]);
/* 2 */
scanf("%d", b);
printf("%d\n", b[0]);
Будет работать.
Обычно / * 1 * / не должно работать. Но gcc преобразует "& a" в "a", потому что "& a" не имеет никакого смысла.
printf("&a = %p\n", &a);
printf("a = %p\n", a);
printf("&b = %p\n", &b);
printf("b = %p\n", b);
&a = 0x7ffff6be67d0
a = 0x7ffff6be67d0
&b = 0x7ffff6be67c8
b = 0xb0b010
Вы не можете принять адрес a. Но b - это «обычная переменная» указателя типа, и поэтому вы можете взять ее адрес с помощью «& b».
On / * 2 * / вы помещаете значение, введенное пользователем, в b и, таким образом, * b (или b [0]) произойдет сбой, если пользователь не введет действительный адрес читаемой памяти.
В вашем случае происходит то, что вы передаете обе переменные a и b с оператором & в функцию scanf. Этот оператор «запрашивает» адрес памяти переменной и передает этот адрес функции scanf. Но поскольку обе ваши переменные являются указателями, они действительно имеют адрес памяти, поэтому, когда вы передаете & a или & b, вы передаете память указателя, а не адрес памяти, который он содержит.
Пример:
int x;
int *ptr;
x = 10;
предположим, что адрес памяти x равен 1000. Вы сохраняете число 10 по адресу памяти 1000. Теперь вы делаете следующее:
ptr = &x;
Вы сохраняете адрес 1000 в указателе. Но 1000, помимо адреса, представляет собой само число, поэтому указателю, как и x, по-прежнему нужен адрес памяти для хранения этой информации. Предположим, что ячейка памяти указателя - 1004. Теперь посмотрим на пример:
*ptr == 10; //x content
ptr == 1000 //x memory address
&ptr == 1004 // ptr memory address.
Итак, если вы хотите передать сканированию переменную x, но используя указатель, вам нужно передать сохраненный в ней адрес x
scanf("%d", ptr);
Просто чтобы проиллюстрировать другой пример указателей и векторов
int main
{
int vet[5];
int *ptr;
ptr = vet;
for(int i = 0; i < 5; ++i)
{
scanf("%d", (ptr+i) );
}
}
Здесь вы можете прочитать вектор с помощью указателя. Также, используя арифметику указателей, вы можете перебирать адреса памяти вектора.
Массив a помещается в стек, адрес первого элемента совпадает с адресом a. & a [0] и & a - это тот же адрес
Массив b выделяется с помощью malloc, адрес хранилища находится в куче, тогда как адрес указателя b находится в стеке. & b [0] - это не тот же адрес, что и & b .
Вот почему первый scanf и printf работают, а второй нет.
C-FAQ объясняет это в гораздо подробнее.
В первом сканировании вы передаете ссылку на массив. В массивах C указатели на блок памяти выделенного типа, в вашем случае int *
и выражение типа a [0]
преобразуется в * (a + 0 )
(что, кстати, приводит к забавному варианту 0 [a]
, который будет фактически компилироваться.) Этот массив размещается в стеке. Второй массив размещается в куче, а стек содержит переменную-указатель на этот массив.
В обоих случаях вы передаете указатель не на первую запись массива, а на массив и указатель на массив соответственно.
Ваш первый scanf перезаписывает массив, поскольку он размещен в стеке, ваше значение попадает (по счастливой случайности) в массив.
Второй scanf перезаписывает указатель на массив, тем самым изменяя указатель на адрес памяти, который, вероятно, не существует в вашем сегменте данных. Это приводит к ошибке выполнения.