Что такое `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], и оценивает его для пользователя