Что такое `int * userMask [3] [4]` указывает?
Я модифицирую некоторый код и наткнулся на объявление, в котором у меня возникли проблемы с пониманием:
int *userMask[3][4] = {0};
Что именно это указывает? Является ли это матрицей, где каждый элемент является указателем? Или это указывает на матрицу размера [3] [4]?
Спасибо
Я думаю, мой вопрос в том, как userMask[2][maskElement][user]
может работать, когда он объявлен как int
. Разве userMask не должен был int[]
для этого работать правильно? Я не должен понимать это правильно...
На стороне примечания, спасибо за ваше предложение о cdecl Robert. Однако кто-нибудь знает, как использовать его в командной строке XP? Все, что я могу получить, это синтаксическая ошибка: (
Ответы
Ответ 1
Короткий ответ
Данный userMask объявлен как
int *userMask[3][4];
то userMask
имеет тип int*[3][4]
. Это 2-й массив указателей на int. Размер внешнего измерения равен 3, размер внутреннего измерения равен 4. Действительно, это не что иное, как 3-элементный массив 1d, тип элемента которого представляет собой еще один 4-элементный массив 1d, тип элемента которого int*
.
Описанные шаги
Итак, если вы делаете
userMask[2][maskElement][user]
то по существу с первыми двумя индексами вы выберете конкретный указатель из 2d-массива:
int * p = userMask[2][maskElement];
тогда вы выбираете int, смещенную от этого указателя, делая
p[user]
теперь этот код находится в userMask[2][maskElement][user]
.
Действительный код C
Чтобы сделать это шаг за шагом с действующим кодом c (не беспокойтесь, если вы еще не все поняли в следующем):
int * userMask[3][4] = { { 0 } };
int ** pa = userMask[2]; /* int*[4] becomes int** implicitly */
int * pi = pa[maskElement];
int i = pi[user];
assert(i == userMask[2][maskElement][user]);
Разница между массивами и указателями
Итак, я думаю, что я покажу вам что-то важное. Вышеприведенный массив не содержит указателей на массивы. Давайте посмотрим, как они отличаются друг от друга, чего не ждут многие программисты c:
int array[5][4][3];
/* int[4][3] implicitly converts to int(*)[3] (pointer to first element) */
int (*parray)[3] = array[0];
int ** pint = (int**) array[0]; /* wrong!! */
Теперь, что произойдет, если мы сделаем parray[1]
и pint[1]
? Первый будет продвигать параграф на sizeof(int[3])
bytes (3 * sizeof(int)
), второй будет продвигаться только с помощью sizeof( int* )
байтов. Так что, в то время как первый дает вам правильный массив array[0][1]
, второй даст вам ( char * )array[0] + sizeof( int* )
, который где-то мы этого действительно не хотим. Но захват неправильного смещения - это не все. Поскольку он не знает, что доступ к массиву, он попытается интерпретировать то, что находится на pint[1]
, как int*
. Скажем, что ваш массив был инициализирован с помощью 0x00
. Затем он будет делать следующий шаг индекса, основанный на адресе 0x00 (например, Doing pint[1][0]
). Oh noes - полностью поведение undefined! Поэтому очень важно подчеркнуть разницу.
Заключение
Это было больше, чем вы просили, но я думаю, что очень важно знать эти детали. Особенно, если вы хотите передать 2d массивы в функции, тогда это знание действительно полезно.
Ответ 2
Это двумерный массив, где каждый элемент является указателем на int
, и все указатели инициализируются нулем.
В вашем контроле вы показываете, что массив используется следующим образом:
if(userMask[2][maskElement][user] && blah)
result = true;
В этом случае каждый элемент в userMask
должен фактически указывать на массив из int
s. (An int*
может указывать на один int
или массив int
s). Чтобы определить это, проверьте код, который присваивает значения userMask
. Например, можно написать:
int userArray[2] = { 10, 20 };
userMask[0][0] = userArray; // userMask[0][0] points to the
// first element of userArray.
Затем следующий код индексируется в userArray
:
int value = userMask[0][0][1]; // sets value = userArray[1], giving 20.
Ответ 3
int *userMask[3][4] = {0};
- это двумерный массив, в котором каждый элемент является указателем на int. Кроме того, все члены инициализируются нулевыми указателями.
int (*userMask)[3][4];
будет указателем на двумерный массив int. Скобки в C связывают более жесткие, чем *, поэтому скобки необходимы для создания указателя на массив.
cdecl
- простая утилита, которую вы можете загрузить, чтобы объяснить сложные объявления:
cdecl> explain int *userMask[3][4]
declare userMask as array 3 of array 4 of pointer to int
Он также может делать обратное:
cdecl> declare userMask as pointer to array 3 of array 4 of int
int (*userMask)[3][4]
Ответ 4
Примените правило наизнанку.
int *userMask[3][4] = {0};
Начиная с внутренней части декларации,
userMask
- это имя
userMask[3]
выделяет пространство для (является вектором) 3 из них
userMask[3][4]
выделяет пространство для 4 userMask[3]
's
int *
сообщает нам, что элементы userMask
являются указателями типа int
а затем = {0}
является инициализатором, где все элементы 0
. Итак,
int *userMask[3][4] = {0};
представляет собой массив 3x4 int *, инициализированный 0.
Ответ 5
if(userMask[2][maskElement][user] && blah)
result = true;
Вторая часть здесь состоит в том, что в C нет массивов; существует только арифметика указателя. По определению p[i]
всегда эквивалентно *(p+i)
, поэтому
userMask[2][maskElement][user]
эквивалентно
*((userMask[2][maskElement])+user)
Код где-то назначает вектор (я бы поставил деньги с malloc (3c) или аналогичный вызов) на указатель в этом массиве; теперь ваш, если говорит
IF пользовательский элемент вектора в userMask [2] [maskElement] отличен от нуля
THEN IF blah не равен нулю (из-за && короткого замыкания, вторая конъюнкция не получает оценку, если первая конъюнкция равна 0)
THEN установить result = true.
Ответ 6
Это матрица, в которой каждый элемент является указателем.
Если бы он указывал на матрицу размера [3] [4], код был бы
int userMask[3][4]={0};
Ответ 7
Я думаю, что оператор обращается к третьей строке массива usermask, затем обращается к указателю maskElement'th в этой строке, и поскольку это указатель int, он может указывать на начало массива int (мыслить строки символов), который, как я предполагаю, он делает, и этот массив субиндексирован пользователем.
Ответ 8
userMask[2]
имеет тип int*[]
,
userMask[2][maskElement]
имеет тип int*
,
и поэтому userMask[2][maskElement][user]
имеет тип int
.
Объявление
int *userMask[3][4] = {0};
является сокращением для
int *userMask[3][4] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
где каждый из нулей неявно преобразован в (int*)0
.
Ответ 9
это поможет, если вы прочтете это следующим образом:
type variablename[array_spec];
в этом случае: int * usermask [3] [4];
поэтому его матрица из int *.
теперь, так как c не различает указатель и массивы, вы можете использовать индексирование массива на указателях.
int* i;
int the_int_behind_i = *(i+1);
int also_the_int_behind_i = i[1];
Это нужно, чтобы я указывал на область, где несколько ints выстроились друг за другом, конечно, как массив.
Обратите внимание, что оператор индекса [], используемый в последних примерах, выглядит как array_spec в первом, но эти два совершенно разные.
Итак: userMask [2] [maskElement] [пользователь]
выбирает указатель usermask, хранящийся в [2] [maskElement], и оценивает его для пользователя