gedamial Ответов: 2

Является ли массив указателей указателем на указатель в C++?


Привет.

Когда я пишу эти функции:

void f(float* p[3])
{
	cout << "ARRAY OF [3] POINTER TO FLOAT" << endl;
}

void f(float** p)
{
	cout << "POINTER TO POINTER" << endl;
}


Компилятор жалуется: void f (float*[]) уже имеет тело

Что происходит?

Что я уже пробовал:

void f(float* p[3])
{
	cout << "ARRAY OF [3] POINTER TO FLOAT" << endl;
}

void f(float** p)
{
	cout << "POINTER TO POINTER" << endl;
}

int main()
{
   float pos[3] {1.3f, 4.3f, 5.3f};

   f(&pos);  // error: can't convert float(*)[3] to float**
}

Philippe Mori

Хотя полезно знать этот материал, следует предпочесть использовать контейнеры STL (std::vector...) и избегать низкоуровневых материалов C, чтобы сделать код более надежным.

2 Ответов

Рейтинг:
2

User 59241

Указатели - Учебники По C++ [^]

Это объявляет массив поплавков.

float pos[3] {1.3f, 4.3f, 5.3f};


Нигде у вас нет массива указателей на поплавки, которые были бы объявлены таким образом:
float *pos[3];


Так что с тем что вы объявили вы можете иметь:
void f(float p[3])

ОПЕРАЦИОННАЯ
void f(float* p)

Не оба.


gedamial

Короче говоря, массив указателей и указатель на указатель - это одно и то же?

Philippe Mori

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

Рейтинг:
15

Philippe Mori

Как вы можете видеть, ваши первые 2 функции объявляют одну и ту же функцию. Это было бы похоже на:

void g(float p[3]) { /* ... */ }

против
void g(float *p) { /* ... */ }

Вы можете вызвать любую из этих функций (предполагая, что только одна объявлена и определена) следующим образом:
float pos[3] {1.3f, 4.3f, 5.3f};
g(pos);


Таким образом, если вы хотите вызвать свои функции так, как они объявлены, вам придется сделать это следующим образом:
float *arrayOfPointers[3] = { &pos[0], &pos[1], &pos[2] };
f(arrayOfPointers);


С другой стороны, если вы хотите вызвать функцию, как в вашем коде, то вам нужно изменить объявление следующим образом:
void f(float (*p)[3]) { /* ... */ }

Таким образом, вы объявляете указатель на массив. Вместо этого вы можете использовать typedef.
Кстати, если вы используете это объявление, размер массива должен совпадать, так как он будет частью объявления.

В этот момент Вы также можете заметить, что ваше исходное сообщение об ошибке показывает вам синтаксис указателя на массив из 3 поплавков...

Бонус
В C++ вы также можете использовать ссылки. Я предпочитаю это, так как нам не нужно брать адрес массива на вызывающем сайте, и это также позволит вам гарантировать, что только массив из 3 элементов может быть передан функции.
void h(float (&p)[3]) { /* ... */ }
h(pos);


Обновление
Массив указателей будет иметь вид:
float f1 = 1.1f, f2 = 2.2f, f3 = 3.3f;
float *arrayOfPointers[] = { &f1, &f2, &f3 };

Представление памяти будет выглядеть следующим образом:
[ &f1 | &f2 | &f3 ]

Поскольку массив эквивалентен указателю, то float ** объявит указатель на первый элемент, который является указателем на float.

Указатель на массив float будет иметь вид:
float arrayOfFloats[] = { 1.11f, 2.22f, 3.33f };
float (*pointerToAnArrayOfFloats)[] = &arrayOfFloats;

Представление памяти будет выглядеть следующим образом:
& [ f1 | f2 | f3 ]


Дополнительные ссылки
Эквивалентны ли указатели и массивы в языке Си? - сайт Эли Бендерского[^]
Существует хорошее графическое представление, которое поможет вам понять разницу.

C указатель на указатель, указатель на функции, массив указателей, объясненный примерами[^]


[no name]

Очень точный.

Philippe Mori

Да, оригинальной информации должно было хватить...

gedamial

Мы знаем, что void f (float p[3]) компилятор оценивает это как void f(float* p)

Почему не компилятор оценить недействительными Ф(тип float (*р)[3]) аннулировать Ф(флоат** п) ?

Philippe Mori

Вам лучше ознакомиться с документацией по синтаксису C++. По сути, вы должны прочитать объявление назад, и функция () сделает указатель применимым ко всему объявлению (переменная p) вместо float *.

gedamial

Я знаю, что.

Я имею в виду, что если float(*p)[3] является указателем на массив, а массив распадается на указатель, то float** должен быть тем же самым!

Philippe Mori

Нет. Массив указателей на float бы распадается на поплавок**.

Смотрите мой обновленный ответ.

gedamial

Очень точный обновленный ответ.

Но указатель на массив, из которого вы нарисовали графическое представление... Я имею в виду, что указатель на массив указывает на первый элемент этого массива, переданный по адресу, верно?

Так что в основном это указатель на float (to f1)