Когда функция имеет параметр массива определенного размера, почему она заменяется указателем?

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

#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?
  • Что говорит стандарт?
  • Почему существует строгая безопасность типа С++?

Ответ 1

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

void foo ( char a[100] );

Будет настроен параметр как указатель, и он станет следующим:

void foo ( char * a );

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

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

С++ '03 8.3.5/3:

... Тип функции определяется с использованием следующих правил. Тип каждого параметра определяется из его собственного decl-specifier-seq и declarator. После определения типа каждого параметра любой параметр типа "массив T" или "возвращающая функцию T" настраивается как "указатель на T" или "указатель на функцию возврата T" соответственно....

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

Проверьте правильность "правого левого" правила в google; Я нашел одно описание здесь.

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

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

Начните с идентификатора 'a'

'a' является

Переместитесь вправо - мы найдем ), чтобы мы обратном направлении искали (. Когда мы двигаемся влево, мы проходим &

'a' является ссылкой

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

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

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

'a' - ссылка на массив из 100 символов

Ответ 2

Да. В C и С++ вы не можете передавать массивы в функции. Это так, как есть.

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

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

template< std::size_t N >
void f(char (&arr)[N])
{
  std::cout << sizeof(arr) << '\n';
}

Ответ 3

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

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