【问题标题】:Using sizeof() in an initialized, unknown size array - C++在初始化的、未知大小的数组中使用 sizeof() - C++
【发布时间】:2014-10-27 01:12:54
【问题描述】:

我是 C++ 编程新手,我正在尝试获取数组的大小。谁能解释我为什么会这样?我尝试在 runnable.com 中运行代码,结果显示相同。

我确定这不是正确的做法。如果可能的话,你能建议任何简单的方法来获取这种数组的大小吗?

#include <iostream>

using namespace std;

int main ()
{
  int set1[] = {1, 9, 3, 50, 31, 65};
  int set234[] = {3, 5, 5};

  cout << sizeof(set1) << endl;
  cout << sizeof(set234) << endl;

  cout << "When sizeof() return value is divided by 4"<< endl;
  cout << sizeof(set1) / 4 << endl; 
  cout << sizeof(set234) / 4 << endl;

  return 0;
}

****************************************************************
Output:
24
12
When sizeof() return value is divided by 4
6
3
****************************************************************

**编辑:感谢您的回复。 飞走了:D

【问题讨论】:

  • sizeof(arr) / sizeof(arr[0])
  • @NOWA 什么不清楚?
  • 标准答案是sizeof(foo) / sizeof(foo[0])

标签: c++ arrays types sizeof


【解决方案1】:

数组的大小等于其所有元素的大小之和。在您的示例中,您处理 int 类型的数组,那么系统中的 sizeof( int ) 似乎等于 4,因此,由于第一个数组有 6 个元素,因此其大小等于 6 * sizeof( int ),即 24。第二个数组等于3 * sizeof( int ),即12。 例如,如果您系统中的 sizeof( int ) 等于 8,那么第一个数组的大小将等于 48 ( 6 * sizeof* int ) ),第二个数组的大小将等于 24 ( 3 *大小(整数))。

因此,例如,如果您想知道数组中有多少个元素,您可以按以下方式计算

sizeof( YouArray ) / sizeof( YourArray[0] )

sizeof( YouArray ) / sizeof( ElementType )

【讨论】:

  • +1 或sizeof(YourArray)/sizeof(*YourArray),以及所有这些(可能毫无帮助),当YourArray 是一个简单的指针而不是真正的本机数组时编译。如果一个人的工具链提供了使用std:array&lt;&gt; 的更多燃料。
  • @NOWA 这个解决方案有点危险,好像YouArray 实际上是一个指针或带有重载[] 的东西,它返回虚假信息而没有警告。
  • @Yakk 在这种情况下,您可以使用标准类 std::extent
【解决方案2】:

sizeof 返回字节数,而不是元素数。大多数情况下,您应该避免使用数组;使用std::vectorstd::array,两者都提供了一种简单的方法来获取元素的数量。

【讨论】:

    【解决方案3】:

    sizeof 以字节为单位返回数组的大小,而不是元素。看起来您在 32 位系统(或 LP64,意味着只有 long 和指针是 64 位,但 int 仍然是 32)上运行,所以整数数组中的每个元素都是 4 个字节。在您的 set1 中,即 6 个元素,即 6x4=24 字节。

    要获取元素的大小,请执行 sizeof(set1)/sizeof(set1[0])。但是,这不适用于您在编译时列出了元素的数组。但是,如果您只有一个 int*,则 sizeof 运算符将返回指针的大小。

    【讨论】:

    • 我在 64 位系统中运行。多谢,伙计。这有帮助。
    • 哦是的,呃,可能是 LP64,这意味着 long 和指针是 64 位的。整数仍然是 32 位的。更新答案以解决此问题。
    【解决方案4】:

    sizeof() 以字节为单位为您提供总大小。例如,如果 int 为 4,并且数组中有 6 个元素。它将返回 4*6=24 作为答案。因此,以下代码将为您提供数组的大小。

    #include <iostream>
    
    using namespace std;
    
    int main ()
    {
      int set1[] = {1, 9, 3, 50, 31, 65};
      int set234[] = {3, 5, 5};
    
      cout << (sizeof(set1))/4 << endl;
      cout << (sizeof(set234))/4 << endl;
    
    
      return 0;
    }
    

    你也可以用这个:

    #include <iostream>
    #include <array>
    
    int main ()
    {
      array<int,5> a;
      cout << "size is" << a.size();
    return 0;
    }
    

    【讨论】:

    • 不要使用像 4 这样的幻数。它们不会在每个平台上都有效。
    • @bolov 说了什么。要获取元素的大小,请改为使用 sizeof(set1[0])。
    • 谢谢,伙计。这有帮助:)
    • ……怎么……怎么……int a[] =然后a.size()……怎么
    • 这是C++,写之前至少测试一下
    【解决方案5】:

    要获取分配在堆栈上的数组中的元素计数,通常的技术是获取整个数组的总大小(以字节为单位),然后将其除以大小,单个数组项的字节数:

    <item count> = <total array size in bytes> / <single array item size in bytes>
    

    但是,这个公式只能应用于在堆栈上分配的数组,不能应用于在堆上动态分配的数组(例如使用new[]):在后一种情况下,您需要将数组项计数作为单独的信息。

    Microsoft Visual C++ 提供了一个方便的 _countof() 宏,它会为您执行上述计算,并且如果参数是 指针安全地会中断编译过程,例如到一个动态分配的数组(因为在这种情况下,上面的公式给出了不正确的结果,即指针的大小 - 它是固定的,例如 32 位系统上的 4 个字节,并且与指向的数组大小无关 - 除以第一个指向的项目的大小)。

    好像是there is an equivalent safe ARRAY_SIZE() macro for Linux

    【讨论】:

      【解决方案6】:
      #include <cstddef>
      
      template<class T, std::size_t N>
      std::size_t length_of( T(&)[N] ) {
        return N;
      }
      

      是解决您问题的模板。

      C++11 中更工业化的版本是:

      #include <array>
      
      template<class T, std::size_t N>
      constexpr std::size_t size( T(&)[N] ) {
        return N;
      }
      template<class T, std::size_t N>
      constexpr std::size_t size( std::array<T,N> const& ) {
        return N;
      }
      template<class C,class=void>
      struct has_size : std::false_type {};
      template<class>using void_t=void;
      template<class C, void_t< decltype( std::declval<C&>().size() ) > >
      struct has_size : std::true_type {};
      
      template<bool b, class T=void>using enable_if_t=typename std::enable_if<b,T>::type;
      
      template<class C, class=enable_if_t< has_size<C>::value, bool[1] >>
      constexpr std::size_t size( C const& c ) {
        return c.size();
      }
      
      template<class C, class=enable_if_t< !has_size<C>::value, bool[2] >>
      constexpr std::size_t size( C const& c ) {
        using std::begin; using std::end;
        return end(c)-begin(c);
      }
      

      这可能太过分了。请注意,缺少大小的容器中的非随机访问迭代器可能无法编译(因为 - 通常未定义),这是有目的的(我们不想意外地做 O(n) 工作) .

      【讨论】:

      • 我只称它为大小。另一种版本(适用于所有容器,而不仅仅是 C 样式数组)是使用 return std::end( array ) - std::begin( array );(其中 array 是您的参数的名称)。为什么标准提供了std::beginstd::end 而没有提供std::size 打败了我。
      • @JamesKanze 添加了令人生畏的工业强度版本。在有size 时使用begin/end 也是一个坏主意,恕我直言,因为它可能效率低得多和/或不起作用(参见std::unordered_map,它有一个size() 但没有@ 987654334@ 在它的迭代器上)上面的std::array 版本可能是多余的,因为我认为.size() 对于array 已经是constexpr
      • 你是对的,当然,如果容器有size,那就是你应该使用的。但我真正的问题仍然是:为什么它不在标准中?正如您的代码所指出的那样,工业强度版本并非微不足道,而且它确实是标准应该提供的东西。
      • @jameskanze 一,你没有把它放在那里。对于两个人来说,这将是更容易的后期概念。对于三个,它是否应该在没有 size 且没有随机访问迭代器的容器上工作?这意味着它很慢。它应该如何失败?早期的?它应该躲避类型还是使用特征来失败?我们应该有慢尺寸和快尺寸吗?
      • 我也没有输入std::beginstd::end;我确实经常发帖说任何使用 C++ 的人都应该将它们放在他们的工具包中(但我也为size 这样做了)。其余的,拥有size 是 STL 兼容容器的标准要求:对于不支持迭代器的用户定义容器,std::begin 会发生什么? (我不确定,但我认为基本规则是函数为 C 样式数组重载,否则转发到容器上的相应函数。如果函数不存在,它将无法编译。)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 2013-10-20
      • 2014-04-21
      相关资源
      最近更新 更多