Вопрос по c, arrays – Создать указатель на двумерный массив

105

Мне нужен указатель на статический 2-мерный массив. Как это сделать?

static uint8_t l_matrix[10][20];

void test(){
   uint8_t **matrix_ptr = l_matrix; //wrong idea 
}

Я получаю все виды ошибок, таких как:

  • warning: assignment from incompatible pointer type
  • subscripted value is neither array nor pointer
  • error: invalid use of flexible array member
@ JohannesSchaub-litb Этого больше не существует. (Как мне посмотреть снова ...? Яknow Пользователи с низким уровнем репутации могут просматривать его, но я забыл, как ...) Mateen Ulhaq
Читатьstackoverflow.com/questions/423823/… это может помочь вам Johannes Schaub - litb
@muntoo: вот его копия:gist.github.com/sharth/ede13c0502d5dd8d45bd Bill Lynch

Ваш Ответ

10   ответов
0

Основной синтаксис инициализирующего указателя, который указывает на многомерный массив:

type (*pointer)[ 1st dimension size ][2nd dimension size ][..]=&array_name

Основной синтаксис для его вызова

(*pointer_name)[ 1st index][2nd index][...]

Вот пример

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
   char balance[5][100] = { {"Subham"},{"Messi"} };//The multidimentional array...

   char (*p)[5][100]=&balance;//Pointer initialization...

   printf("%s\n",(*p)[0]);//Calling...
   printf("%s\n",(*p)[1]);//Calling...

  return 0;
}

Выход:

Subham
Messi

Это сделал это ...

4

Вы всегда можете избежать возни с компилятором, объявив массив как линейный и выполнив (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

}

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

Вы можете сделать это так:

uint8_t (*matrix_ptr)[10][20] = &l_matrix;
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Dill
Error: User Rate Limit Exceeded
1

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

static uint8_t l_matrix[10][20];

void test(){
   uint8_t *matrix_ptr = l_matrix[0]; //wrong idea 
}
5

G & APOS; день,

Декларация

static uint8_t l_matrix[10][20];

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

Так не

uint8_t (*matrix_ptr)[20] = l_matrix;

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

Edit: Подумав об этом немного дальше, не является ли имя массива по определению указателем? То есть имя массива является синонимом местоположения первого элемента, т.е. 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, найденного в строке rowno.

All pointer manipulations automatically take into account the size of the object pointed to. - K&R Section 5.4, p.103

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

НТН

веселит,

Error: User Rate Limit Exceeded
5

В C99 (поддерживается clang и gcc) существует неясный синтаксис для передачи многомерных массивов в функции по ссылке:

int l_matrix[10][20];

void test(int matrix_ptr[static 10][20]) {
}

int main(void) {
    test(l_matrix);
}

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

К сожалению, это не исправляетsizeof() и компиляторы, кажется, еще не используют эту информацию, поэтому она остается любопытной.

Error: User Rate Limit Exceededby referenceError: User Rate Limit Exceeded
Error: User Rate Limit ExceededstaticError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededstatic 10Error: User Rate Limit Exceededat leastError: User Rate Limit Exceeded
0

Вы также можете добавить смещение, если хотите использовать отрицательные индексы:

uint8_t l_matrix[10][20];
uint8_t (*matrix_ptr)[20] = l_matrix+5;
matrix_ptr[-4][1]=7;

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

uint8_t (*matrix_ptr)[20] = (uint8_t (*)[20]) l_matrix;
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededcError: User Rate Limit Exceeded
7

В

int *ptr= l_matrix[0];

вы можете получить доступ как

*p
*(p+1)
*(p+2)

ведь 2-мерные массивы также сохраняются как 1-й.

21

кfully понимаешь это, тыmust понять следующие понятия:

Arrays are not pointers!

Прежде всего (и это было достаточно проповедано),arrays are not pointers, Вместо этого в большинстве случаев они «разлагаются». на адрес их первого элемента, который может быть назначен указателю:

int a[] = {1, 2, 3};

int *p = a; // p now points to a[0]

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



Multidimensional arrays

Многомерные массивы - это всего лишь способ «разделить»; память таким образом, что компилятор / машина может понять и работать.

Например,int a[4][3][5] = массив, содержащий 4 * 3 * 5 (60) «кусков»; целочисленной памяти.

Преимущество перед использованиемint a[4][3][5] против равниныint b[60] является то, что они теперь разделены на части (Проще работать с их «кусками», при необходимости), и теперь программа может выполнять связанную проверку.

По факту,int a[4][3][5] хранитсяexactly лайкint b[60] в памяти -only отличие состоит в том, что программа теперь управляет им так, как будто они разделяют сущности определенных размеров (в частности, четыре группы из трех групп по пять).

Имейте в виду: обаint a[4][3][5] а такжеint b[60] одинаковы в памяти, и единственное отличие состоит в том, как они обрабатываются приложением / компилятором

{
  {1, 2, 3, 4, 5}
  {6, 7, 8, 9, 10}
  {11, 12, 13, 14, 15}
}
{
  {16, 17, 18, 19, 20}
  {21, 22, 23, 24, 25}
  {26, 27, 28, 29, 30}
}
{
  {31, 32, 33, 34, 35}
  {36, 37, 38, 39, 40}
  {41, 42, 43, 44, 45}
}
{
  {46, 47, 48, 49, 50}
  {51, 52, 53, 54, 55}
  {56, 57, 58, 59, 60}
}

Отсюда ясно видно, что каждый «раздел» это просто массив, который программа отслеживает.



Syntax

Сейчас,arrays are syntactically different from pointers, В частности, это означаетthe compiler/machine will treat them differently. Это может показаться легким, но взгляните на это:

int a[3][3];

printf("%p %p", a, a[0]);

Приведенный выше пример печатает один и тот же адрес памяти дважды, например так:

0x7eb5a3b4 0x7eb5a3b4

However, only one can be assigned to a pointer so directly:

int *p1 = a[0]; // RIGHT !

int *p2 = a; // WRONG !

Why can't a be assigned to a pointer but a[0] can?

Это просто является следствием многомерных массивов, и я объясню, почему:

На уровне & apos;a«мы все еще видим, что у нас есть другое« измерение »; с нетерпением жду. На уровне & apos;a[0]«Однако мы уже находимся в верхнем измерении, поэтому, что касается программы, мы просто смотрим на обычный массив.

Вы можете спросить:

Why does it matter if the array is multidimensional in regards to making a pointer for it?

Лучше всего так думать:

«Распад»; из многомерного массива это не просто адрес, ноan address with partition data (AKA все еще понимает, что лежащие в его основе данные сделаны из других массивов), который состоит из границ, установленных массивом за пределами первого измерения.

Этот «раздел» логика не может существовать в указателе, если мы не укажем ее:

int a[4][5][95][8];

int (*p)[5][95][8];

p = a; // p = *a[0] // p = a+0

В противном случае значение свойств сортировки массива теряется.

Также обратите внимание на использование круглых скобок*p: int (*p)[5][95][8] Это означает, что мы делаем указатель с этими границами, а не массив указателей с этими границами:int *p[5][95][8]



Conclusion

Давайте рассмотрим:

  • Arrays decay to addresses if they have no other purpose in the used context
  • Multidimensional arrays are just arrays of arrays - Hence, the 'decayed' address will carry the burden of "I have sub dimensions"
  • Dimension data cannot exist in a pointer unless you give it to it.

Вкратце: многомерные массивы распадаются на адреса, которые несут способность понимать их содержание.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededint *p1 = &(a[0]); // RIGHT !Error: User Rate Limit Exceededint *p1 = a;
Error: User Rate Limit Exceeded
126

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

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] = ...;

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


Edit

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

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

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

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

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

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

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

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

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


Следующая альтернатива вообще не работает, потому что тип элемента массива, когда вы рассматриваете его как одномерный массив, этоnot 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, но если вы добавите анализ псевдонимов и другие агрессивные оптимизации, какой-то компилятор может сделать предположение, что он может нарушить этот код. Сказав это, я никогда не сталкивался с компилятором, который не работает на нем (но, опять же, я не использовал эту технику в реальном коде), и даже в FAQ по C есть эта техника (с предупреждением о его UB). ), и если вы не можете изменить тип массива, это последний вариант, чтобы спасти вас :)

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededuint8_t *d[20]Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

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