Как я надежно получаю размер массива C-стиля? Метод, часто рекомендуемый, кажется, для использования sizeof
, но это не работает в foo
функция, где x
передается в:
#include
void foo(int x[]) {
std::cerr << (sizeof(x) / sizeof(int)); // 2
}
int main(){
int x[] = {1,2,3,4,5};
std::cerr << (sizeof(x) / sizeof(int)); // 5
foo(x);
return 0;
}
Ответы на этот вопрос рекомендуют sizeof
но они не говорят что это (по-видимому?) не работает, если Вы раздаете массив. Так, я должен использовать сигнальную метку вместо этого? (Я не думаю пользователи о моем foo
функции можно всегда доверять для помещения сигнальной метки в конец. Конечно, я мог использовать std::vector
, но затем я не получаю хороший краткий синтаксис {1,2,3,4,5}
.)
Параметры массива C в C на самом деле просто указатели, поэтому sizeof ()
не будет работать . Вам нужно либо передать размер в качестве другого параметра, либо использовать дозор - в зависимости от того, что больше подходит для вашего дизайна.
Некоторые другие параметры:
Другая информация:
для C ++ вместо передачи необработанного указателя на массив вы можете захотеть, чтобы параметр использовал что-то, что обертывает массив в шаблоне класса, который отслеживает размер массива и предоставляет методы для безопасного копирования данных в массив. Что-то вроде шаблона array_proxy STLSoft или Boost :: array может помочь. Раньше я использовал шаблон array_proxy
для хорошего эффекта. Внутри функции, использующей параметр, вы получаете операции, похожие на std :: vector
, но вызывающий функцию может использовать простой массив C. Здесь нет копирования массива - шаблон array_proxy
почти автоматически заботится об упаковке указателя массива и размера массива.
макрос для использования в C для определения количества элементов в массиве (когда может помочь sizeof (), т. Е. Вы имеете дело не с простым указателем): Есть ли стандартная функция в C, который вернет длину массива?
Как насчет этого? ..
template <int N>
void foo(int (&x)[N]) {
std::cerr << N;
}
c не предоставляет встроенной поддержки для этого. Когда массив передается за пределы объявленной области видимости, его размер теряется.
Вы можете передавать размер вместе с массивом. Вы даже можете объединить их в структуру, если всегда хотите сохранить размер, хотя при этом у вас будут некоторые накладные расходы на буккипинг.
Общая идиома , упомянутая в документации GNU Libstdc ++, - это функция lengthof
:
template<typename T, unsigned int sz>
inline unsigned int lengthof(T (&)[sz]) { return sz; }
Вы можете использовать ее как
int x[] = {1,2,3,4,5};
std::cerr << lengthof(x) << std::endl;
Предупреждение: это будет работать, только если массив не распался на указатель .
Тип выражения массива будет неявно преобразован от «N-элементного массива T» до «указателя на T», и его значение будет адресом первого элемента в массиве, если только выражение массива не является операндом либо sizeof
, либо address- of ( &
), или если выражение массива является строковым литералом, используемым для инициализации другого массива в объявлении. Короче говоря, вы не можете передать массив функции как массив ; функция получает значение указателя, а не значение массива.
Вы должны передать размер массива как отдельный параметр.
Поскольку вы используете C ++, используйте векторы (или какой-либо другой подходящий контейнер STL) вместо массивов в стиле C. Да, вы теряете удобный сокращенный синтаксис, но компромисс того стоит. Шутки в сторону.
Вам необходимо передать размер вместе с массивом, как это делается во многих библиотечных функциях, например strncpy ()
, strncmp ()
и т. Д. Извините, это просто способ, которым это работает в C :-).
В качестве альтернативы вы можете развернуть свою собственную структуру, например:
struct array {
int* data;
int size;
};
, и передать ее по вашему коду.
Конечно, вы все еще можете использовать std :: list
или std :: vector
, если хотите быть более ориентированными на C ++.
Вы можете либо передать размер, либо использовать дозорный, либо, что еще лучше, использовать std :: vector. Несмотря на то, что в std :: vector отсутствуют списки инициализаторов, все же легко создать вектор с набором элементов (хотя и не так хорошо)
static const int arr[] = {1,2,3,4,5};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
Класс std :: vector также значительно усложняет возможность ошибок, что стоит своего веса. в золоте. Еще один бонус заключается в том, что с ним должен быть знаком весь C ++, и большинство приложений C ++ должны использовать std :: vector, а не необработанный массив C.
Вкратце: C ++ 0x добавляет Списки инициализаторов
std::vector<int> v = {1, 2, 3, 4};
Вы также можете использовать Boost.Assign , чтобы сделать то же самое, хотя синтаксис немного более запутан.
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);
или
std::vector<int> v;
v += 1, 2, 3, 4;