Подтвердить что ты не робот

Указатель на массив С++

Что делает следующий код?

int g[] = {9,8};
int (*j) = g;

По моему мнению, он создает указатель на массив из 2 целых чисел. Но тогда почему это работает:

int x = j[0];

и это не работает:

int x = (*j)[0];
4b9b3361

Ответ 1

Скобки в вашем примере являются излишними. Указателю не важно, присутствует ли массив - он знает только, что он указывает на int

  int g[] = {9,8};
  int (*j) = g;

также можно переписать как

  int g[] = {9,8};
  int *j = g;

который также можно было бы переписать как

  int g[] = {9,8};
  int *j = &g[0];

указатель на массив будет выглядеть как

  int g[] = {9,8};
  int (*j)[2] = &g;

  //Dereference 'j' and access array element zero
  int n = (*j)[0];

Там хорошо читайте на объявлениях указателей (и как их набросать) по этой ссылке здесь: http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

Ответ 2

int g[] = {9,8};

Это объявляет объект типа int [2] и инициализирует его элементы {9,8}

int (*j) = g;

Это объявляет объект типа int * и инициализирует его указателем на первый элемент g.

Тот факт, что второе объявление инициализирует j чем-то другим, отличным от g, довольно странно. C и С++ просто имеют эти странные правила о массивах, и это один из них. Здесь выражение g неявно преобразуется из lvalue, относящегося к объекту g, в r-значение типа int*, которое указывает на первый элемент g.

Это преобразование происходит в нескольких местах. На самом деле это происходит, когда вы делаете g[0]. Оператор индекса массива фактически не работает на массивах, только на указателях. Таким образом, оператор int x = j[0]; работает, потому что g[0] выполняет то же самое неявное преобразование, которое было выполнено при инициализации j.

Указатель на массив объявляется следующим образом

int (*k)[2];

и вы точно знаете, как это будет использоваться

int x = (*k)[0];

(обратите внимание, как "объявление следует использовать" , т.е. синтаксис объявления переменной типа имитирует синтаксис для использования переменной этого типа.)

Однако обычно не используется указатель на массив. Вся цель специальных правил вокруг массивов заключается в том, что вы можете использовать указатель на элемент массива, как если бы это был массив. Так что идиоматическому C вообще не важно, что массивы и указатели - это не одно и то же, и правила не позволяют вам делать что-либо полезное непосредственно с массивами. (например, вы не можете скопировать массив вроде: int g[2] = {1,2}; int h[2]; h = g;)


Примеры:

void foo(int c[10]); // looks like we're taking an array by value.
// Wrong, the parameter type is 'adjusted' to be int*

int bar[3] = {1,2};
foo(bar); // compile error due to wrong types (int[3] vs. int[10])?
// No, compiles fine but you'll probably get undefined behavior at runtime

// if you want type checking, you can pass arrays by reference (or just use std::array):
void foo2(int (&c)[10]); // paramater type isn't 'adjusted'
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10]

int baz()[10]; // returning an array by value?
// No, return types are prohibited from being an array.

int g[2] = {1,2};
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax
h = g; // copying an array? No, assigning to arrays is prohibited

Поскольку массивы настолько несовместимы с другими типами на C и С++, вы должны просто избегать их. С++ имеет std::array, что намного более согласованно, и вы должны использовать его, когда вам нужны массивы статического размера. Если вам нужны массивы с динамическим размером, ваш первый вариант - std::vector.

Ответ 3

j[0]; разделяет указатель на int, поэтому его тип int.

(*j)[0] не имеет типа. *j разделяет указатель на int, поэтому он возвращает int, а (*j)[0] пытается разыменовать int. Это похоже на попытку int x = 8; x[0];.