Создайте указатель на двухмерную антенную решетку

Если вы не читали справочную страницу, вы не настоящий программист.

110
задан Bo Persson 4 December 2012 в 12:32
поделиться

5 ответов

Здесь вы хотите создать указатель на первый элемент массива

uint8_t (*matrix_ptr)[20] = l_matrix;

С typedef это выглядит чище

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

Тогда вы снова можете наслаждаться жизнью :)

matrix_ptr[0][1] = ...;

Остерегайтесь указатель / массив мира в C, вокруг этого много путаницы.


Edit

Рассмотрение некоторых других ответов здесь, потому что поля комментариев слишком короткие, чтобы их там можно было делать. Было предложено несколько альтернатив, но не было показано, как они себя ведут. Вот как они это делают

uint8_t (*matrix_ptr)[][20] = l_matrix;

. Если вы исправите ошибку и добавите оператор адресации и , как в следующем фрагменте

uint8_t (*matrix_ptr)[][20] = &l_matrix;

, то он создаст указатель на неполный тип массива элементов типа массив из 20 uint8_t. Поскольку указатель указывает на массив массивов, вы должны получить к нему доступ с помощью

(*matrix_ptr)[0][1] = ...;

И поскольку это указатель на неполный массив, вы не можете использовать ярлык

matrix_ptr[0][0][1] = ...;

, потому что для индексирования требуется, чтобы был известен размер типа элемента (индексирование подразумевает добавление целого числа к указателю, поэтому оно не будет работать с неполными типами). Обратите внимание, что это работает только в C , потому что T [] и T [N] являются совместимыми типами. В C ++ нет концепции совместимых типов , поэтому он отклоняет этот код, потому что T [] и T [10] - разные типы.


Следующая альтернатива вообще не работает, потому что тип элемента массива, когда вы рассматриваете его как одномерный массив, равен не uint8_t , а uint8_t [20]

uint8_t *matrix_ptr = l_matrix; // fail

Следующее является хорошей альтернативой.

uint8_t (*matrix_ptr)[10][20] = &l_matrix;

Вы получаете доступ к нему с помощью

(*matrix_ptr)[0][1] = ...;
matrix_ptr[0][0][1] = ...; // also possible now

. Его преимущество состоит в том, что он сохраняет размер внешнего измерения. Таким образом, вы можете применить к нему sizeof

sizeof (*matrix_ptr) == sizeof(uint8_t) * 10 * 20

Есть еще один ответ, который использует тот факт, что элементы в массиве хранятся непрерывно

uint8_t *matrix_ptr = l_matrix[0];

Теперь это формально позволяет вам получить доступ только к элементам первого элемента из двух размерный массив. То есть выполняется следующее условие

matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid

matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior

. Вы заметите, что оно, вероятно, работает до 10 * 20-1 , но если вы включите анализ псевдонимов и другие агрессивные оптимизации, некоторый компилятор может сделать предположение, которое может сломать этот код. Сказав это, я никогда не сталкивался с компилятором, который не работает на нем (но опять же, я не использовал эту технику в реальном коде), и даже в C FAQ есть эта техника (с предупреждением о ее UB'ness ), и если вы не можете изменить тип массива, это последний вариант, который вас спасет :)

это формально позволяет вам получить доступ только к элементам первого элемента двумерного массива. То есть выполняется следующее условие

matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid

matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior

. Вы заметите, что оно, вероятно, работает до 10 * 20-1 , но если вы включите анализ псевдонимов и другие агрессивные оптимизации, некоторый компилятор может сделать предположение, которое может сломать этот код. Сказав это, я никогда не сталкивался с компилятором, который не работает на нем (но опять же, я не использовал эту технику в реальном коде), и даже в C FAQ есть эта техника (с предупреждением о ее UB'ness ), и если вы не можете изменить тип массива, это последний вариант, который вас спасет :)

это формально позволяет вам получить доступ только к элементам первого элемента двумерного массива. То есть выполняется следующее условие

matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid

matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior

. Вы заметите, что оно, вероятно, работает до 10 * 20-1 , но если вы включите анализ псевдонимов и другие агрессивные оптимизации, некоторый компилятор может сделать предположение, которое может сломать этот код. Сказав это, я никогда не сталкивался с компилятором, который не работает на нем (но опять же, я не использовал эту технику в реальном коде), и даже в C FAQ есть эта техника (с предупреждением о ее UB'ness ), и если вы не можете изменить тип массива, это последний вариант, который вас спасет :)

но если вы включите анализ псевдонимов и другие агрессивные оптимизации, какой-нибудь компилятор может сделать предположение, которое может нарушить этот код. Сказав это, я никогда не сталкивался с компилятором, который не работает на нем (но опять же, я не использовал эту технику в реальном коде), и даже в C FAQ есть эта техника (с предупреждением о ее UB'ness ), и если вы не можете изменить тип массива, это последний вариант, который вас спасет :)

но если вы включите анализ псевдонимов и другие агрессивные оптимизации, какой-нибудь компилятор может сделать предположение, которое может нарушить этот код. Сказав это, я никогда не сталкивался с компилятором, который не работает на нем (но опять же, я не использовал эту технику в реальном коде), и даже в C FAQ есть эта техника (с предупреждением о ее UB'ness ), и если вы не можете изменить тип массива, это последний вариант, который вас спасет :)

129
ответ дан 24 November 2019 в 03:15
поделиться

Добрый день,

В объявлении

static uint8_t l_matrix[10][20];

выделено хранилище для 10 строк по 20 ячеек unit8_t, т.е. 200 ячеек размером uint8_t, где каждый элемент определяется путем вычисления 20 x строка + столбец.

Значит,

uint8_t (*matrix_ptr)[20] = l_matrix;

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

Редактировать: Если подумать об этом немного подробнее, разве имя массива по определению не является указателем? То есть имя массива является синонимом местоположения первого элемента, то есть l_matrix [0] [0]?

Edit2: Как упоминалось другими, пространство для комментариев слишком мало для дальнейшее обсуждение. В любом случае:

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

не предоставляет никакого выделения памяти для рассматриваемого массива.

Как упоминалось выше и как определено стандартом, в заявлении:

static uint8_t l_matrix[10][20];

выделено 200 последовательных местоположений типа uint8_t.

] Обращение к l_matrix с использованием операторов формы:

(*l_matrix + (20 * rowno) + colno)

даст вам содержимое colno'th элемента, найденного в строке rowno.

Все манипуляции с указателем автоматически учитывают размер объекта, на который он указывает. - K&R Раздел 5.4, стр.103

Это также имеет место, если при хранении объекта под рукой задействовано какое-либо заполнение или сдвиг выравнивания байтов. Компилятор автоматически подстраивается под них. По определению стандарта C ANSI.

HTH

ура,

5
ответ дан 24 November 2019 в 03:15
поделиться

Вы всегда можете избежать возни с компилятором, объявив массив как линейный и выполнив (row , col) для самостоятельного вычисления индекса массива.

static uint8_t l_matrix[200];

void test(int row, int col, uint8_t val)

{

   uint8_t* matrix_ptr = l_matrix;
   matrix_ptr [col+y*row] = val; // to assign a value

}

это то, что компилятор сделал бы в любом случае.

4
ответ дан 24 November 2019 в 03:15
поделиться

Вы можете сделать это следующим образом:

uint8_t (*matrix_ptr)[10][20] = &l_matrix;
1
ответ дан 24 November 2019 в 03:15
поделиться

Вам нужен указатель на первый элемент, поэтому;

static uint8_t l_matrix[10][20];

void test(){
   uint8_t *matrix_ptr = l_matrix[0]; //wrong idea 
}
1
ответ дан 24 November 2019 в 03:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: