Avatar ·

Как найти длину массива в C++? Проблема с sizeof и указателями

Всем привет! Я начинающий C++ разработчик и столкнулся с очень странной проблемой. Мне нужно узнать, сколько элементов в массиве, но мои попытки проваливаются. Я пишу так: ```cpp int arr[] = {10, 20, 30, 40, 50}; int size = sizeof(arr) / sizeof(arr[0]); cout << "Длина массива: " << size; // Выводит 5 — всё верно ``` Но когда я пытаюсь сделать то же самое внутри функции, передав массив как параметр, то получаю ерунду: ```cpp void printArrayLength(int arr[]) { int size = sizeof(arr) / sizeof(arr[0]); cout << "Длина массива: " << size; // Выводит 1 или 2, но не 5! } int main() { int myArray[] = {10, 20, 30, 40, 50}; printArrayLength(myArray); return 0; } ``` Почему так происходит? sizeof(arr) внутри функции даёт не размер всего массива, а что-то другое. Я читал про указатели, но не до конца понимаю, как это связано. Есть ли надёжный способ узнать длину массива в C++, который будет работать везде? Или мне нужно всегда передавать размер отдельно? Буду благодарен за подробное объяснение с примерами. <<>>

Почему ваш код не работает?

Проблема в том, что в C++ массивы при передаче в функцию распадаются (decay) в указатели. Когда вы пишете:

void printArrayLength(int arr[])

Компилятор на самом деле видит это как:

void printArrayLength(int* arr)

То есть arr — это уже не массив, а указатель на первый элемент. sizeof(arr) возвращает размер указателя (обычно 4 или 8 байт в зависимости от архитектуры), а не размер всего массива. Поэтому sizeof(arr) / sizeof(arr[0]) даёт 1 или 2, но не 5.

Надёжные способы узнать длину массива

Вот несколько проверенных подходов:

  • Передавать размер отдельным параметром — классический C-стиль
  • Использовать шаблоны — современный C++
  • Использовать std::array или std::vector — рекомендуемый подход

Способ 1: Передавать размер отдельно

void printArrayLength(int arr[], int size) {
    cout << "Длина массива: " << size;
}

int main() {
    int myArray[] = {10, 20, 30, 40, 50};
    int size = sizeof(myArray) / sizeof(myArray[0]);
    printArrayLength(myArray, size);
    return 0;
}

Это простой, но подверженный ошибкам способ — легко забыть передать правильный размер.

Способ 2: Шаблонная функция (C++11 и новее)

template <size_t N>
void printArrayLength(int (&arr)[N]) {
    cout << "Длина массива: " << N;
}

int main() {
    int myArray[] = {10, 20, 30, 40, 50};
    printArrayLength(myArray); // Выведет 5
    return 0;
}

Здесь мы передаём массив по ссылке, сохраняя его размер. Компилятор сам выводит N. Недостаток: функция работает только с массивами фиксированного размера, а не с указателями.

Способ 3: Использовать std::size (C++17)

#include <iostream>
#include <array>

int main() {
    int myArray[] = {10, 20, 30, 40, 50};
    cout << "Длина массива: " << std::size(myArray); // Выведет 5
    return 0;
}

std::size — это безопасная обёртка, которая работает и с обычными массивами, и с контейнерами STL.

Способ 4: Использовать std::array (рекомендуется)

#include <iostream>
#include <array>

void printArrayLength(const std::array<int, 5>& arr) {
    cout << "Длина массива: " << arr.size(); // Выведет 5
}

int main() {
    std::array<int, 5> myArray = {10, 20, 30, 40, 50};
    printArrayLength(myArray);
    return 0;
}

std::array не теряет информацию о размере и предоставляет удобный метод .size(). Для динамических массивов используйте std::vector.

Итог

Запомните главное правило: в C++ массивы и указатели — не одно и то же, хотя они тесно связаны. Никогда не используйте sizeof на массиве, переданном в функцию. Вместо этого:

  • Для статических массивов — используйте std::size или шаблоны
  • Для современного кода — используйте std::array или std::vector
  • Для обратной совместимости — передавайте размер отдельно
<<>>

Альтернативный подход: макросы (C-style, с осторожностью)

В старом коде иногда встречается макрос для определения размера массива:

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

int myArray[] = {1, 2, 3, 4, 5};
int size = ARRAY_SIZE(myArray); // Работает, пока arr — массив, а не указатель

Этот макрос опасен тем, что он не выдаст ошибку, если передать указатель — просто вернёт неверный результат. В современном C++ лучше использовать std::size или шаблоны.

Для динамических массивов

Если вы работаете с динамической памятью (new[]), то размер хранить нужно вручную. Никакой sizeof тут не поможет:

int* arr = new int[10];
// Размер (10) нужно запомнить отдельно
delete[] arr;

Поэтому для динамических массивов всегда используйте std::vector — он сам хранит размер и безопасно управляет памятью:

std::vector<int> vec = {1, 2, 3, 4, 5};
cout << vec.size(); // Выведет 5

Это избавит вас от головной боли с sizeof и утечками памяти.