Если я попытаюсь отобразить длину массива в C++ с помощью функции sizeof
, она правильно отобразит результат, который в данном случае равен 8.
int main()
{
int array_enteros[]={'9','8','7','6','5','4','3','2'};
int longitud=sizeof(array_enteros)/sizeof(*array_enteros);
cout<<longitud<<endl;
return 0;
}
Что мне не нравится, так это то, что слово нужно вводить array_enteros
дважды, чтобы узнать длину, а для этого лучше было бы получить его через функцию.
int obtener_longitud_array(int* array_enteros)
{
return sizeof(array_enteros)/sizeof(*array_enteros);
}
int main()
{
int array_caracteres_enteros[]={'9','8','7','6','5','4','3','2'};
int longitud=obtener_longitud_array(array_caracteres_enteros);
cout<<longitud<<endl;
return 0;
}
В этом случае он возвращает 1, что является другим значением.
Не будет ли проблем в параметрах функции?
Проблема.
Проблема с вашей функцией
obtener_longitud_array
заключается в том, что вы теряете информацию о размере при передаче параметраarray_enteros
(плюс вы можете вычислить размер только целочисленных массивов).Объяснение.
C++ — это строго статически типизированный язык , это означает, что вы не можете изменять типы во
object
время выполнения, и все имеет конкретный тип (без подстановочных знаков, таких как .net ) .Но иногда C++ создает ощущение динамической типизации, потому что в нем есть неявные преобразования типов. Одним из таких неявных преобразований является преобразование массива в указатель в соответствии со стандартом C++ (перевод и выделение мое):
Аранжировка
N
T
будет:Где
T
будет любой тип и любоеN
значение.Неизвестное исправление расширения
T
будет:где
T
будет любой тип, и это тип массива, который вы используете в своем примере.При передаче массива
array_enteros
в функциюobtener_longitud_array
массив проходит вышеуказанное преобразование ( §4.2 ) и теряет свой первоначальный тип. Исходный тип массива содержит размер.Размер как часть шрифта.
Массив
N
T
или массив с неизвестным расширениемT
содержит размер как часть своего типа:Вот почему размер можно определить с помощью перегрузок функций:
Таким образом, ваша функция
obtener_longitud_array
может быть шаблоном, который получает размер массива следующим образом:Или вы можете обобщить его для нецелочисленных типов , как это сделал Dolmens . Но вместо того, чтобы изобретать велосипед, я бы использовал стандартную утилиту
std::extent
заголовка<type_traits>
библиотеки :Проблема в том, что функция получает не массив, а указатель, который имеет размер 1, указатели работают как массивы, но это не одно и то же.
Вы можете использовать макрос для решения этой проблемы
а затем используйте GetSize, как если бы это была функция
Поскольку вы работаете на C++, вы можете использовать способ ведения дел C++ : использовать
template
.1. С++ 11,
constexpr
:Компилируется без проблем с
2. С++ 98, без
constexpr
:Единственное, что меняется, это именно удаление этого ключевого слова.
Компилируется без проблем с
Тестовый код:
Действительно для C++98 и выше:
Результат:
Как видите, он различает исправления и не исправления . В первом случае возвращается количество элементов (независимо от того, указано ли это при объявлении переменной или опущено). Во втором возвращается
0
.Почему 2 версии?
Первое
template
не является строго необходимым. Это делается для того, чтобы избежать ошибок, если вы используете его для переменных , которые не являются массивами . Он использует особенность языка SFINAE : при попытке создать экземпляр шаблона и параметры не совпадают , он не выдает ошибку, а продолжает искать другие версии того ,template
который соответствует.В нашем тестовом коде, если мы опустим первую версию шаблона
Мой g++ выдает следующее:
Однако с обеими версиями компилятор пробует и то, и другое , и, в зависимости от случая, он добьется успеха с одним или другим. Именно эти попытки позволяют нам различать обычные переменные и массивы .
Другой способ сделать это, используя С++ 11 и
template std::remove_all_extents< T >
:Что, в очень вольном переводе с моей стороны, звучит так:
T
он имеет видtipo[]...
(с любым числом измерений, obtenemos el tipo base
T`.T
это не формаtipo[]...
, мы все равно получаем типT
.Это можно использовать для получения размера любой переменной, независимо от того, является ли она массивом : если это так, мы можем получить размер ее базового типа; если это не так, мы все равно получаем размер базового типа. Поэтому в любом случае нам достаточно разделить размер переменной на
typedef type
полученный изtemplate
:Показывает следующее: