Как мне найти длину массива?

434

Есть ли способ узнать, сколько значений имеет массив? Обнаружение того, достигло ли я конца массива, также будет работать.

  • 17
    Откуда поступает массив? Обычно функции, которые принимают массивы, также принимают параметр длины для решения этой проблемы.
  • 0
    Что ж, я делаю программу «безумных либ», в которой есть массив со всем текстом, а также расположение существительных / глаголов, которые пользователь должен заполнить. Я хотел бы использовать функцию для запуска через весь массив, заменив значения «[существительное]» и «[глагол» »текстом, введенным пользователем.
Показать ещё 2 комментария
Теги:
arrays

24 ответа

402
Лучший ответ

Если вы имеете в виду массив C-стиля, вы можете сделать что-то вроде:

int a[7];
std::cout << "Length of array = " << (sizeof(a)/sizeof(*a)) << std::endl;

Это не работает с указателями, т.е. он не будет работать для одного из следующих действий:

int *p = new int[7];
std::cout << "Length of array = " << (sizeof(p)/sizeof(*p)) << std::endl;

или

void func(int *p)
{
    std::cout << "Length of array = " << (sizeof(p)/sizeof(*p)) << std::endl;
}

int a[7];
func(a);

В С++, если вы хотите такого поведения, то вы должны использовать контейнерный класс; вероятно std::vector.

  • 76
    Это также не работает, если вы передаете массив другой функции и попытаетесь сделать это там :)
  • 2
    @ Сан Хасинто: Действительно; ответ обновлен ...
Показать ещё 21 комментарий
117

Как уже говорилось, вы можете использовать sizeof(arr)/sizeof(*arr) но это даст вам неправильный ответ для типов указателей, которые не являются массивами.

template<class T, size_t N>
constexpr size_t size(T (&)[N]) { return N; }

Это имеет приятное свойство не компилироваться для типов не массивов (Visual Studio имеет _countof которая делает это). constexpr делает это выражение времени компиляции, поэтому у него нет недостатков по сравнению с макросом (по крайней мере, ни одного из них я не знаю).

Вы также можете рассмотреть возможность использования std::array из С++ 11, который показывает его длину без издержек над собственным массивом C.

С++ 17 имеет std::size() в заголовке <iterator> который делает то же самое и работает также для контейнеров STL (благодаря @Jon C).

  • 0
    Я получаю две ошибки при компиляции (я даже не пытаюсь его использовать): ошибка C2265: '<Unknown>': недопустимая ссылка на массив нулевого размера C2266: '<Unknown>': ссылка на не константный ограниченный массив недопустим
  • 0
    @jimifiki Можете ли вы предоставить ссылку IDEone или пример кода, чтобы я мог видеть? Либо так, либо вы можете задать вопрос по SO, так как этот код хорошо известен ( пример )
Показать ещё 10 комментариев
73

Выполнение sizeof( myArray ) даст вам общее количество байтов, выделенных для этого массива. Затем вы можете узнать количество элементов в массиве, разделив на размер одного элемента в массиве: sizeof( myArray[0] )

  • 3
    Это очень простое и легкое решение для преодоления проблемы, которая кажется извечной.
  • 2
    Не работает для C ++ «новых» массивов, удерживаемых указателем. Вы получите размер указателя (4 байта) или размер его первого элемента, если вы разыменуете его.
Показать ещё 3 комментария
51

Есть ли способ узнать, сколько значений имеет массив?

Да!

Попробуйте sizeof(array)/sizeof(array[0])

Обнаружение того, достигло ли я конца массива, также будет работать.

Я не вижу никакого способа для этого, если ваш массив не является массивом символов (например, строка).

P.S: В С++ всегда используйте std::vector. Существует несколько встроенных функций и расширенная функциональность.

  • 0
    Это не будет работать для переменных отдельных размеров массива
  • 3
    +1 для векторов. Существует очень мало веских аргументов в пользу использования массивов старого стиля C ++. Если размер массива никогда не изменится, но даже тогда вы должны вместо этого использовать класс контейнера массива. Для хранения динамических массивов лучше использовать контейнерный класс, например vector. Преимущества использования контейнерных классов намного перевешивают недостатки управления собственной памятью.
35

Хотя это старый вопрос, стоит обновить ответ на С++ 17. В стандартной библиотеке теперь есть шаблонная функция std::size(), которая возвращает количество элементов как в контейнере std, так и в массиве в стиле C. Например:

#include <iterator>

uint32_t data[] = {10, 20, 30, 40};
auto dataSize = std::size(data);
// dataSize == 4
25
#include <iostream>

int main ()
{
    using namespace std;
    int arr[] = {2, 7, 1, 111};
    auto array_length = end(arr) - begin(arr);
    cout << "Length of array: " << array_length << endl;
}
  • 9
    Я считаю, что это работает только для локальных переменных, которые находятся в стеке.
  • 0
    Это лучший ответ. @DragonLord, это работает и для членов группы. Смотрите cpp.sh/92xvv .
23

std::vector имеет метод size(), который возвращает количество элементов в векторе.

(Да, это ответ в ответ)

  • 10
    Это может быть язык в щеке, но это почти наверняка правильный подход.
  • 0
    почему вы говорите, что это язык в щеке? мне (новичку в C ++) это кажется правильным ответом.
Показать ещё 3 комментария
21

Так как С++ 11, некоторые новые шаблоны вводятся, чтобы помочь уменьшить боль при работе с длиной массива. Все они определены в заголовке <type_traits>.

  • std::rank<T>::value

    Если T является типом массива, он предоставляет значение константы элемента, равное количеству измерений массива. Для любого другого типа значение равно 0.

  • std::extent<T, N>::value

    Если T является типом массива, он предоставляет значение константы элемента, равное количеству элементов в N -м измерении массива, если N находится в [0, std::rank<T>::value). Для любого другого типа или если T - это массив неизвестных границ по его первому размеру, а N - 0, значение равно 0.

  • std::remove_extent<T>::type

    Если T - это массив некоторого типа X, он предоставляет тип typedef-члена, равный X, в противном случае тип T. Обратите внимание, что если T - многомерный массив, удаляется только первое измерение.

  • std::remove_all_extents<T>::type

    Если T является многомерным массивом какого-либо типа X, он предоставляет тип typedef-члена, равный X, иначе type is T.

Чтобы получить длину по любому размеру многомерного массива, decltype можно использовать для объединения с std::extent. Например:

#include <iostream>
#include <type_traits> // std::remove_extent std::remove_all_extents std::rank std::extent

template<class T, size_t N>
constexpr size_t length(T(&)[N]) { return N; }

template<class T, size_t N>
constexpr size_t length2(T(&arr)[N]) { return sizeof(arr) / sizeof(*arr); }

int main()
{
    int a[5][4][3]{{{1,2,3}, {4,5,6}}, { }, {{7,8,9}}};

    // New way
    constexpr auto l1 = std::extent<decltype(a)>::value;     // 5
    constexpr auto l2 = std::extent<decltype(a), 1>::value;  // 4
    constexpr auto l3 = std::extent<decltype(a), 2>::value;  // 3
    constexpr auto l4 = std::extent<decltype(a), 3>::value;  // 0

    // Mixed way
    constexpr auto la = length(a);
    //constexpr auto lpa = length(*a);  // compile error
    //auto lpa = length(*a);  // get at runtime
    std::remove_extent<decltype(a)>::type pa;  // get at compile time
    //std::remove_reference<decltype(*a)>::type pa;  // same as above
    constexpr auto lpa = length(pa);
    std::cout << la << ' ' << lpa << '\n';

    // Old way
    constexpr auto la2 = sizeof(a) / sizeof(*a);
    constexpr auto lpa2 = sizeof(*a) / sizeof(**a);
    std::cout << la2 << ' ' << lpa2 << '\n';

    return 0;
}

BTY, чтобы получить общее количество элементов в многомерном массиве:

constexpr auto l = sizeof(a) / sizeof(std::remove_all_extents<decltype(a)>::type);

Или поместите его в шаблон функции:

#include <iostream>
#include <type_traits>
    

template<class T>
constexpr size_t len(T &a)
{
    return sizeof(a) / sizeof(typename std::remove_all_extents<T>::type);
}

int main()
{
    int a[5][4][3]{{{1,2,3}, {4,5,6}}, { }, {{7,8,9}}};
    constexpr auto ttt = len(a);
    int i;
    std::cout << ttt << ' ' << len(i) << '\n';
    
    return 0;
}

Дополнительные примеры того, как их использовать, можно найти, следуя ссылкам.

  • 0
    это правильный ответ в C ++ 11
17

Также есть путь TR1/С++ 11/С++ 17 (см. Live on Coliru):

const std::string s[3] = { "1"s, "2"s, "3"s };
constexpr auto n       = std::extent<   decltype(s) >::value; // From <type_traits>
constexpr auto n2      = std::extent_v< decltype(s) >;        // C++17 shorthand

const auto     a    = std::array{ "1"s, "2"s, "3"s };   // C++17 class template arg deduction -- http://en.cppreference.com/w/cpp/language/class_template_argument_deduction
constexpr auto size = std::tuple_size_v< decltype(a) >;

std::cout << n << " " << n2 << " " << size << "\n"; // Prints 3 3 3
9

Вместо использования встроенной функции массива aka:

 int x[2] = {0,1,2};

вы должны использовать класс массива и шаблон массива. Попробуйте:

#include <array>
array<type_of_the_array, number_of_elements_in_the_array> Name_of_Array = {};

Итак, теперь, если вы хотите найти длину массива, все, что вам нужно, использовать функцию размера в классе массива.

Name_of_Array.size();

и это должно возвращать длину элементов в массиве.

6

В С++, используя класс std:: array для объявления массива, можно легко найти размер массива, а также последний элемент.

#include<iostream>
#include<array>
int main()
{
    std::array<int,3> arr;

    //To find the size of the array
    std::cout<<arr.size()<<std::endl;

    //Accessing the last element
    auto it=arr.end();
    std::cout<<arr.back()<<"\t"<<arr[arr.size()-1]<<"\t"<<*(--it);

    return 0;
}

На самом деле класс массива имеет множество других функций, которые позволяют использовать массив стандартным контейнером.
Ссылка 1 на С++ std:: класс массива
Ссылка 2 на класс std:: array
Примеры в ссылках полезны.

  • 2
    Ницца; Я вижу, у тебя много навыков; и ... отличный подход. Я думаю, что должен написать больше ответов на такие знаменитые вопросы и сам ;-)
3

Для C++/CX (при написании, например, приложений UWP с использованием C++ в Visual Studio) мы можем найти количество значений в массиве, просто используя функцию size().

Исходный код:

string myArray[] = { "Example1", "Example2", "Example3", "Example4" };
int size_of_array=size(myArray);

Если вы cout на size_of_array выход будет:

>>> 4
3

Вот одна реализация ArraySize из Google Protobuf.

#define GOOGLE_ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

// test codes...
char* ptr[] = { "you", "are", "here" };
int testarr[] = {1, 2, 3, 4};
cout << GOOGLE_ARRAYSIZE(testarr) << endl;
cout << GOOGLE_ARRAYSIZE(ptr) << endl;

ARRAYSIZE (arr) работает, проверяя sizeof (arr) (количество байтов в  массив) и sizeof (* (arr)) (количество байтов в одном массиве  элемент). Если первое делится последним, возможно, arr  на самом деле массив, и в этом случае результатом деления является # of  элементов в массиве. В противном случае arr не может быть массивом,  и мы генерируем ошибку компилятора, чтобы предотвратить  компилирование.

Поскольку размер bool определяется реализацией, нам нужно  ! (sizeof (a) и sizeof (* (a))) до size_t, чтобы обеспечить окончательный  результат имеет тип size_t.

Этот макрос не идеален, поскольку он ошибочно принимает определенные  указатели, а именно, где размер указателя делится на указателя  размер. Поскольку весь наш код должен пройти через 32-битный компилятор,  где указатель равен 4 байтам, это означает, что все указатели относятся к типу,  размер 3 или больше, чем 4 (будет отклонен).

  • 0
    с массивом целых чисел, подобным следующему: int nombres[5] = { 9, 3 }; эта функция возвращает 5 вместо 2 .
  • 0
    GOOGLE_ARRAYSIZE(new int8_t) возвращает 8 в моем тестовом env, вместо того, чтобы GOOGLE_ARRAYSIZE(new int8_t) ошибку. Литая часть кажется избыточной, не говоря уже о кричащем макросе C. sizeof(a) / sizeof(*a) работает как устаревшее решение.
2
 length = sizeof(array_name)/sizeof(int);
  • 0
    Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода, так как это действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код
1

Я предлагаю хитрое решение здесь:

Вы всегда можете сохранить length в первом элементе:

// malloc/new

arr[0] = length;
arr++;

// do anything. 
int len = *(arr-1);

free(--arr); 

Стоимость вы должны --arr когда вызываете free

  • 2
    Это работает только тогда, когда arr имеет тип, совместимый с int и массив не длиннее максимального значения типа. Например, строки Pascal на самом деле являются байтовыми массивами, использующими этот трюк; максимальная длина строки в Паскале составляет 255 символов.
  • 0
    Я предполагаю, что можно зарезервировать, скажем, 8 байтов в начале каждого массива и использовать длинную без знака, если они хотят хранить объекты. Я думаю, что вектор, вероятно, проще. Но определенно хорошее решение для встраиваемых систем.
1

Хорошее решение, использующее дженерики:

template <typename T,unsigned S>
inline unsigned arraysize(const T (&v)[S]) { return S; }

Затем просто вызовите arraysize(_Array);, чтобы получить длину массива.

Источник

  • 0
    В этом случае не работает: int a[arraysize(b)];
  • 0
    @bobbogo Работает со встроенным или constexpr, может быть, у вас отключен встроенный или это необязательно? ideone.com/VxogJ4
Показать ещё 1 комментарий
0

Просто вы можете использовать этот фрагмент:

#include <iostream>
#include <string>
#include <array>

using namespace std;

int main()
{

  array<int,3> values;
  cout << "No. elements in valuea array: " << values.size() << " elements." << endl;
  cout << "sizeof(myints): " << sizeof(values) << endl;

}

и вот ссылка: http://www.cplusplus.com/reference/array/array/size/

0

Вы можете найти длину массива следующим образом:

int  arr[] = {1, 2, 3, 4, 5, 6}; 
int size = *(&arr + 1) - arr; 
cout << "Number of elements in arr[] is "<< size; 
return 0;
0

Я лично предложил бы (если вы не можете работать со специализированными функциями по какой-либо причине), чтобы сначала расширить совместимость типов массивов с тем, что вы обычно использовали бы в нем (если вы сохраняли значения ≥ 0:

unsigned int x[] -> int x[]

чем вы сделаете элемент массива 1 больше, чем вам нужно. Для последнего элемента вы бы поместили некоторый тип, который включен в расширенный спецификатор типа, но который вы обычно не используете, например. используя предыдущий пример, последний элемент будет равен -1. Это позволяет вам (используя цикл for) найти последний элемент массива.

0

Избегайте использования типа вместе с sizeof, поскольку sizeof(array)/sizeof(char), внезапно становится поврежденным, если вы изменяете тип массива.

В визуальной студии у вас есть эквивалентный if sizeof(array)/sizeof(*array). Вы можете просто набрать _countof(array)

0

Для старого компилятора g++ вы можете сделать это

template <class T, size_t N>
char (&helper(T (&)[N]))[N];

#define arraysize(array) (sizeof(helper(array)))

int main() {
    int a[10];
    std::cout << arraysize(a) << std::endl;
    return 0;
}
  • 0
    Это правильный ответ. Очень переносимый среди версий C ++, не работает с указателями, плюс ответ доступен во время компиляции
0

Одна из наиболее распространенных причин, по которой вы в конечном итоге это ищете, - это то, что вы хотите передать массив функции, и не должны передавать другой аргумент для этого размера. Вам также в целом понравится, чтобы размер массива был динамическим. Этот массив может содержать объекты, а не примитивы, а объекты могут быть сложными, так что size_of() является небезопасным вариантом для вычисления счетчика.

Как предложили другие, рассмотрите возможность использования std::vector или списка и т.д. вместо примитивного массива. Однако для старых компиляторов у вас все равно не будет окончательного решения, которое вы, вероятно, захотите, просто сделав это, потому что для заполнения контейнера требуется куча уродливых строк push_back(). Если вы похожи на меня, вам нужно однолинейное решение с анонимными объектами.

Если вы идете с контейнером STL, альтернативным примитивному массиву, это сообщение SO может быть полезно вам для способов его инициализации: Каков самый простой способ инициализировать std::vector с помощью жестко закодированных элементов?

Здесь используется метод, который я использую для этого, который будет работать повсеместно через компиляторы и платформы:

Создайте структуру или класс как контейнер для вашей коллекции объектов. Определите функцию перегрузки оператора для <

class MyObject;

struct MyObjectList
{
    std::list<MyObject> objects;
    MyObjectList& operator<<( const MyObject o )
    { 
        objects.push_back( o );
        return *this; 
    }
};

Вы можете создавать функции, которые берут вашу структуру в качестве параметра, например:

someFunc( MyObjectList &objects );

Затем вы можете вызвать эту функцию, например:

someFunc( MyObjectList() << MyObject(1) <<  MyObject(2) <<  MyObject(3) );

Таким образом, вы можете создавать и передавать набор объектов с динамическим размером в функцию в одной чистой строке!

0

Просто подумал, но просто решил создать переменную счетчика и сохранить размер массива в позиции [0]. Я удалил большую часть кода, который у меня был в функции, но вы увидите после выхода из цикла, prime [0] получает окончательное значение "a". Я пробовал использовать векторы, но VS Express 2013 не очень понравился. Также обратите внимание, что "a" начинается с одного, чтобы избежать перезаписи [0], и он инициализировался в начале, чтобы избежать ошибок. Я не эксперт, просто подумал, что поделюсь.

int prime[] = {0};
int primes(int x, int y){
    using namespace std; int a = 1;
    for (int i = x; i <= y; i++){prime[a] = i; a++; }
    prime[0] = a; return 0;
}
-4

Допустим, у вас есть глобальный массив, объявленный в верхней части страницы

int global[] = { 1, 2, 3, 4 };

Чтобы узнать, сколько элементов существует (в С++) в массиве, введите следующий код:

sizeof(global) / 4;

sizeof (NAME_OF_ARRAY)/4 вернет вам количество элементов для данного имени массива.

  • 6
    sizeof (int) зависит от платформы. Нет гарантии, что это будет 4 (хотя это самый распространенный случай)
  • 0
    Чем тебе для сложения.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню