Вопрос по c++, function-parameter, arrays, standards, sizeof – Когда функция имеет параметр массива определенного размера, почему она заменяется указателем?

62

Учитывая следующую программу,

#include <iostream>

using namespace std;

void foo( char a[100] )
{
    cout << "foo() " << sizeof( a ) << endl;
}

int main()
{
    char bar[100] = { 0 };
    cout << "main() " << sizeof( bar ) << endl;
    foo( bar );
    return 0;
}

выходы

main() 100
foo() 4
Почему массив передается как указатель на первый элемент?Это наследие от C?Что говорит стандарт?Почему строгая безопасность типов в C ++ упала?
Какой строгий тип безопасности? Кто пообещал строгий тип безопасности? В C ++ такого нет. n.m.
Я всегда использую std :: array в этих случаях, предотвращает возникновение подобных проблем и работает с алгоритмами std paulm
TL; DR для ответов ниже: массивы становятся указателями при передаче в функцию, поэтому, когда вы проверяете их размер, все, что вы получаете, это размер указателя. Если вы работаете только с C, все, что я могу предложить, - это предварительно рассчитать любой размер, который вы пытаетесь получить из массива, в качестве другого параметра. Super Cat

Ваш Ответ

3   ответа
13

ть.

В любом случае, почему вы делаете простые массивы? Вы смотрели наboost/std::tr1::array/std::array или жеstd::vector?

Обратите внимание, что вы можете передать ссылку на массив произвольной длины в функциюшаблон, С верхней части моей головы:

template< std::size_t N >
void f(char (&arr)[N])
{
  std::cout << sizeof(arr) << '\n';
}
Но вы можете перейти в «ссылку на массив». Richard Corden
Теперь есть std :: array. Trevor Hickey
Передача по ссылке на массив не ограничивается «шаблонами функций». Вы можете передать массив по ссылке на не шаблонные функции. Преимущество использования шаблона функции заключается в том, что вы можете вывести индекс массива, что позволяет вам вызывать функцию для массивов разных размеров. Richard Corden
Или простоstd::cout << N; :) Lightness Races in Orbit
@CsTamas, да, правила для передачи массивов и объектов различны в C. Структуры фактически копируются по значению при передаче в качестве параметра. Массивы обрабатываются как указатель на их первый элемент. (Массивы и указатели в C очень взаимосвязаны. Они не одно и то же, но в целях передачи параметров они идентичны) Tyler McHenry
0

которое используется для статических массивов и указателей на функции -распад, Рассмотрим следующий код:

int intArray[] = {1, 3, 5, 7, 11}; // static array of 5 ints
//...
void f(int a[]) {
  // ...
}
// ...
f(intArray); // only pointer to the first array element is passed
int length = sizeof intArray/sizeof(int); // calculate intArray elements quantity (equals 5)
int ptrToIntSize = sizeof(*intArray); // calculate int * size on your system
А также? Это в лучшем случае косвенно указывает начто случается. ОП спрашивалПочему язык настроен таким образом. Кроме того, «статический массив» - это запутанный термин, когда то, что вы действительно имеете в виду, выделяется динамически; технически массив, который вы показали, имеетextern связь, а неstatic, И я не уверен, какие указатели функций здесь имеют отношение к чему-либо? underscore_d
75

Да, он унаследован от C. Функция:

void foo ( char a[100] );

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

void foo ( char * a );

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

void foo ( char (&a)[100] );

C ++ '03 8.3.5 / 3:

... Тип функции определяется по следующим правилам. Тип каждого параметра определяется его собственным decl-specier-seq и декларатором. После определения типа каждого параметра любой параметр типа «массив из T» или «функция, возвращающая T» настраивается на «указатель на T» или «указатель на функцию, возвращающую T», соответственно ....

Чтобы объяснить синтаксис:

Проверьте для "правого левого" правила в Google; Я нашел одно описание этогоВот.

Это будет применяться к этому примеру примерно следующим образом:

void foo (char (&a)[100]);

Начать с идентификатора «а»

«а» это

Двигайтесь вправо - мы находим) поэтому мы в обратном направлении ищем(, Когда мы движемся влево, мы проходим&

«а» является ссылкой

После& мы достигаем открытия( поэтому мы снова поворачиваемся и смотрим прямо. Теперь мы видим[100]

«а» является ссылкой на массив из 100

И мы снова меняем направление, пока не достигнемchar:

«а» является ссылкой на массив из 100 символов

Последний имеет недостаток, заключающийся в жестком соединении размера массива с сигнатурой функции. Шаблон функции может избежать этого. sbi
Просто придирка: параметр функции не затухает до указателя. этоотрегулированный на указатель. Имя массива, используемое как функцияаргумент Можнораспад на указатель, если параметр функции является указателем. juanchopanza
Вероятно, стоит упомянуть, что использование std :: vector аккуратно обойдёт все проблемы, связанные с передачей массивов. markh44
Браво за объяснение правила, так как ссылка теперь на 404. gsamaras
Это сводится к тому, что простые параметры массива в C / C ++ - выдумка - они действительно указатели. Параметров массива следует избегать в максимально возможной степени - они действительно просто запутывают вопросы. Michael Burr

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