如何找到数组的长度?


539

有没有办法找到一个数组有多少个值?检测我是否已经到达数组末尾也可以。


22
数组从哪里来?通常,采用数组的函数也采用length参数来处理此问题。
迈克尔·迈尔斯

2
好吧,我正在制作一个“疯狂的图书馆”程序,该程序具有一个数组,其中包含所有文本以及用户必须填写的名词/动词的位置。我想使用一个函数来运行整个数组,用用户输入的文本替换“ [名词]”和“ [动词]”值。
Maxpm 2010年


5
请注意,C语言中的数组不是对象或结构。因此,默认情况下,它们没有长度参数存储在任何地方。如果要使用它们作为C ++中的对象,请尽可能使用C ++对象std :: vector或C ++ 11的std :: array。如果必须使用指针,则始终将数组的长度作为第二个参数传递给与其一起使用的每个函数。
Pihhan 2013年

如果您使用的是C ++ 20,那么我也为此添加了答案。由于这里有很多答案,因此很容易错过。
gprathour

Answers:


511

如果您的意思是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);

在C ++中,如果您想要这种行为,则应该使用容器类。大概吧std::vector


86
如果您将数组传递给其他函数并尝试在其中执行它,也将不起作用:)
San Jacinto 2010年

23
@San Jacinto:否,无论您使用的是什么函数,它都可以工作(在array上)。但是,将可变长度的数组作为参数传递给函数是不可能的(它会衰减为指针)-但是如果您传递一个数组中的数组,然后按预期工作。
eq-

1
@OliverCharlesworth还可以,如果您按值将数组传递给另一个函数并在那里尝试过,那将无法正常工作,对吗?问题是为什么
A_Matar

5
@A_Matar-您不能在C或C ++中按值传递数组。
奥利弗·查尔斯沃思

1
@yusha-他们是同一回事。
奥利弗查尔斯沃思

142

就像其他人说的那样,您可以使用,sizeof(arr)/sizeof(*arr)但这将为不是数组的指针类型提供错误的答案。

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

这具有无法针对非数组类型进行编译的好特性(Visual Studio _countof可以做到这一点)。这constexpr使得它成为一个编译时表达式,因此它在宏上没有任何缺点(至少我不知道)。

您还可以考虑使用std::arrayC ++ 11,它可以在没有本地C数组开销的情况下公开其长度。

C ++ 17具有std::size()<iterator>其中做同样的和适用于STL容器太(感谢报头@乔恩Ç)。


3
@yau是您编写对数组引用的方法请参见此答案。我的版本看起来有些不同,因为由于未使用参数,因此省略了参数的名称,只需要其类型。一个名字就是T(arg&)[N]
Motti

1
谢谢Motti!剩下的参数名称对我来说已经很清楚了。但是令人难以置信的是,我以前从未使用过引用/指针来数组。而且将来可能不会,因为这样的阵列正在逐渐消失。
yau


1
如果使用C ++ 11不是std :: extent更好的解决方案?cn.cppreference.com/w/cpp/types/extent
Isaac Pascual

2
我不熟悉@IsaacPascual extent,现在来看它有两个特征,这些特征使其比上面的功能(对于本用例)有用。(1)指针返回零(而不是编译错误)。(2)它需要一个类型参数,因此要检查变量,您必须做decltype
Motti

86

这样做sizeof( myArray )将为您提供分配给该数组的字节总数。然后,可以通过除以数组中一个元素的大小来找出数组中的元素数:sizeof( myArray[0] )


3
这是一个非常简单易用的解决方案,可以克服似乎已久的问题。

4
对于指针持有的C ++“新”数组不起作用。您可以获取指针的大小(4个字节),或者如果取消引用它的第一个元素的大小。
DragonLord

1
@DragonLord是的,尽管使用关键字new声明数组大小的人在运行时已经知道数组的大小,因此在这种情况下无需使用sizeof运算符来查找数组的大小。我确定你知道。这只是为了任何不这样做的人的利益。
Martyn Shutt 2015年

@surega它不会崩溃
CITBL

60

尽管这是一个老问题,但值得更新C ++ 17的答案。标准库中现在有模板化函数std::size(),该函数返回std容器或C样式数组中的元素数。例如:

#include <iterator>

uint32_t data[] = {10, 20, 30, 40};
auto dataSize = std::size(data);
// dataSize == 4

58

有没有办法找到一个数组有多少个值?

是!

尝试 sizeof(array)/sizeof(array[0])

检测我是否已经到达数组末尾也可以。

除非您的数组是字符数组(即字符串),否则我看不到任何方法。

PS:在C ++中始终使用std::vector。有几个内置功能和扩展功能。


这不适用于可变的单个数组大小
Don Larynx 2014年

4
向量为+1。很少有理由再使用老式C ++数组。除非数组的大小永远不会改变,否则即使如此,您也应该使用数组容器类。最好使用容器类(例如vector)进行动态数组存储。使用容器类的优点远远超过了必须管理自己的内存的缺点。
马丁·舒特

@MartynShutt当您像在gamedev中那样受缓存限制时,有时就无法使用向量。
塔拉

30

std::vector有一个size()返回向量元素数量的方法。

(是的,这是嘲讽的答案)


10
也许是面颊上的舌头,但这几乎肯定是正确的方法。
杰里·科芬

你为什么说它的舌头在脸颊上?对我(C ++新手)来说,这似乎是正确的答案。
dbliss

6
@dbliss这很容易,因为OP询问了数组的长度,并等价告诉他们如何获取向量的长度,这在C ++中是不同的。但是,它在更深层次上是正确的,因为如果需要在运行时获取长度,向量是更好的选择
poolie

您也可以使用std :: list或其他我相信的容器。
BuvinJ

1
这个答案特别重要的是,您可以使用数组文字初始化向量或列表。
BuvinJ

26
#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;
}

10
我相信这仅适用于堆栈上的局部变量。
DragonLord

这是最好的答案。@DragonLord,它也适用于成员var。参见cpp.sh/92xvv
Shital Shah

24

从C ++ 11开始,引入了一些新模板来帮助减少处理数组长度时的麻烦。所有这些都在header中定义<type_traits>

  • std::rank<T>::value

    如果T为数组类型,则提供等于数组维数的成员常量值。对于任何其他类型,值均为0。

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

    如果T为数组类型,则提供成员常量值,该值等于N数组第th维上的元素数,如果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类型,否则类型为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;
}

通过链接可以找到更多有关如何使用它们的示例。


18

还有TR1 / C ++ 11 / C ++ 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[3] = {0, 1, 2};

您应该使用数组类和数组模板。尝试:

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

因此,现在,如果您想查找数组的长度,您所要做的就是在数组类中使用size函数。

Name_of_Array.size();

那应该返回数组中元素的长度。


6

在C ++中,使用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;
}

实际上,数组类还有很多其他功能,可以让我们将数组用作标准容器。
对C ++ std :: array类的参考1对std :: array类的
参考2参考中
的示例很有帮助。


2
不错 我看到你有很多技能;而且...很棒的方法。我认为自己也应该针对此类著名问题写出更多答案;-)
GhostCat

5

这是一个古老而又传奇的问题,已经有许多惊人的答案了。但是随着时间的流逝,语言中增加了新功能,因此我们需要根据可用的新功能继续进行更新。

我只是注意到尚未有人提到C ++ 20。所以想写答案。

C ++ 20

在C ++ 20中,标准库中添加了一种新的更好的方法,用于查找数组的长度,即std:ssize()。此函数返回signed value

#include <iostream>

int main() {
    int arr[] = {1, 2, 3};
    std::cout << std::ssize(arr);
    return 0;
}

C ++ 17

在C ++ 17中(当时)有一种更好的方法来std::size()定义iterator

#include <iostream>
#include <iterator> // required for std::size

int main(){
    int arr[] = {1, 2, 3};
    std::cout << "Size is " << std::size(arr);
    return 0;
}

PS此方法也适用vector

许多其他答案中已经提到了这种传统方法。

#include <iostream>

int main() {
    int array[] = { 1, 2, 3 };
    std::cout << sizeof(array) / sizeof(array[0]);
    return 0;
}

仅供参考,如果您想知道为什么将数组传递给另一个函数时这种方法不起作用。原因是,

在C ++中,数组不按值传递,而是传递指向数组的指针。由于在某些情况下,传递整个阵列可能是昂贵的操作。您可以通过将数组传递给某个函数并对该数组进行一些更改,然后再次在main中打印该数组来进行测试。您将获得更新的结果。

就像您已经知道的那样,该sizeof()函数提供字节数,因此在其他函数中,它将返回为指针分配的字节数,而不是整个数组。所以这种方法行不通。

但是,我敢肯定,根据您的要求,您可以找到一种不错的方法。

编码愉快。


4

您有很多选择可用于获取C数组大小。

int myArray [] = {0,1,2,3,4,5,7};

1) sizeof(<array>) / sizeof(<type>):

std::cout << "Size:" << sizeof(myArray) / sizeof(int) << std::endl;

2) sizeof(<array>) / sizeof(*<array>):

std::cout << "Size:" << sizeof(myArray) / sizeof(*myArray) << std::endl;

3) sizeof(<array>) / sizeof(<array>[<element>]):

std::cout << "Size:" << sizeof(myArray) / sizeof(myArray[0]) << std::endl;

3

这是一个实现的ArraySize,从谷歌的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可能确实是一个数组,在这种情况下,除法结果是数组中元素的数量。否则,arr不可能是数组,并且我们会生成一个编译器错误以防止代码被编译。

由于bool的大小是实现定义的,因此我们需要将!(sizeof(a)&sizeof(*(a)))强制转换为size_t,以确保最终结果的类型为size_t。

这个宏不是完美的,因为它错误地接受了某些指针,即指针大小可以被指针大小整除。由于我们所有的代码都必须经过一个32位编译器(指针为4个字节),这意味着(正确地)拒绝指向大小为3或大于4的所有类型的指针。


带有如下所示的整数数组:int nombres[5] = { 9, 3 };此函数返回5而不是2
安瓦尔

GOOGLE_ARRAYSIZE(new int8_t)返回8我的测试环境,而不是引发错误。强制转换的部分似乎很多余,更不用说尖叫的C宏了。sizeof(a) / sizeof(*a)可以作为传统解决方案使用。

3

对于C ++ / CX(在Visual Studio中使用C ++编写例如UWP应用程序时),我们只需使用size()函数就可以找到数组中的值数。

源代码:

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

如果您coutsize_of_array输出将是:

>>> 4

3

sizeof(array_name)给出整个数组的大小,并sizeof(int)给出每个数组元素的数据类型的大小。

因此,将整个数组的大小除以数组单个元素的大小即可得出数组的长度

 int array_name[] = {1, 2, 3, 4, 5, 6};
 int length = sizeof(array_name)/sizeof(int);

尽管此代码段可以解决问题,但并未说明原因或答案。请附上代码说明,因为这确实有助于提高您的帖子质量。请记住,您将来会为读者回答问题,而那些人可能不知道您提出代码建议的原因
Balagurunathan Marimuthu

3

回答

int number_of_elements = sizeof(array)/sizeof(array[0])

说明

由于编译器会为每种数据类型预留一个特定大小的内存块,而数组只是其中的一组,因此您只需将数组的大小除以数据类型的大小即可。如果我有一个由30个字符串组成的数组,那么我的系统会为该数组的每个元素(字符串)留出24个字节。在30个元素上,总共有720个字节。720/24 == 30个元素。小型而紧凑的算法是:

int number_of_elements = sizeof(array)/sizeof(array[0]) 等于

number_of_elements = 720/24

请注意,即使它是自定义数据类型,也无需知道数组是什么数据类型。


无需在2019年这个陈旧的和容易出错的做法stackoverflow.com/a/59109106/560648而且它只是一个现有的答案愚弄。
Lightness Races in Orbit

但是,它是简单,雄辩,快速,需求低,平台独立的,并且不需要包含向量或指针。就其他答案而言,似乎只有一个答案使用相同的算法,而且没有一个答案像我的答案那样对问题的潜在机理进行解释。我谨此建议,它不是很容易出错,而是相当可靠。
鲍勃·沃纳

1

只是一个想法,但只是决定创建一个计数器变量并将数组大小存储在位置[0]。我删除了函数中的大部分代码,但退出循环后会看到,prime [0]被分配了最终值'a'。我尝试使用矢量,但VS Express 2013不太喜欢。还要注意,“ a”从1开始以避免覆盖[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;
}

1

一个使用泛型的好的解决方案:

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

然后只需调用arraysize(_Array);即可获取数组的长度。

资源


@bobbogo可与inline或constexpr一起使用,也许您已关闭inline或它是可选的?ideone.com/VxogJ4
QuentinUK '19

@QentinUK constexpr是修复程序。inline不是。constexpr虽然很现代。您确定测试程序没有使用另一个新功能,即可以声明其长度由变量指定的本地数组吗?尝试使用两个全局数组。
bobbogo

1

对于旧的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;
}

这是正确的答案。在C ++版本之间具有
很高的可移植性

1

我在这里提供了一个棘手的解决方案:

您始终可以存储length在第一个元素中:

// malloc/new

arr[0] = length;
arr++;

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

free(--arr); 

成本是您--arr调用时必须free


2
仅当arr类型与兼容int且数组的长度不超过该类型的最大值时,该方法才有效。例如,使用此技巧,Pascal字符串实际上是字节数组。Pascal中字符串的最大长度为255个字符。
Palec

我想可以在每个数组的开头保留8个字节,如果要存储对象,可以使用无符号长。我认为向量可能更容易。但是对于嵌入式系统而言,绝对是一个好的解决方案。
aj.toulan

1

您可以通过以下步骤找到数组的长度:

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

简化为(&arr)[1]-arr;
QuentinUK


0

避免与sizeof一起使用类型,因为sizeof(array)/sizeof(char)如果更改数组的类型,突然会损坏。

在Visual Studio中,等价于sizeof(array)/sizeof(*array)。您只需键入_countof(array)


0

我个人建议(如果由于某种原因而无法使用专用功能)首先将数组类型兼容性扩展到通常使用的范围之外(如果存储的值≥0:

unsigned int x[] -> int x[]

而不是使数组1元素比需要的大。对于最后一个元素,您可以放置​​扩展类型说明符中包含的某种类型,但是通常不会使用,例如,使用前面的示例,最后一个元素将为-1。这使您(通过使用for循环)可以找到数组的最后一个元素。


0

您最终会找到此结果的最常见原因之一是,因为您想要将数组传递给函数,而不必为其大小传递另一个参数。您通常还希望数组大小是动态的。该数组可能包含对象,而不是基元,并且对象可能很复杂,因此size_of()是计算计数的不安全选项。

正如其他人所建议的那样,请考虑使用std :: vector或list等代替原始数组。但是,在旧的编译器上,仅通过简单的操作仍然无法获得最终的解决方案,因为填充容器需要一堆难看的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) );

这样,您可以在一条简单的代码行中生成动态大小的对象集合并将其传递给函数!


-4

假设您在页面顶部声明了一个全局数组

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

要找出数组中(在c ++中)有多少个元素,请输入以下代码:

sizeof(global) / 4;

sizeof(NAME_OF_ARRAY)/ 4将为您返回给定数组名称的元素数。


8
sizeof(int)与平台有关。无法保证它将是4(尽管这是最常见的情况)
胜利者

比你多。
miksiii 2014年

魔术数字!
Lightness Races in Orbit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.