【问题标题】:Is there any way to output the actual array in c++有没有办法在 C++ 中输出实际的数组
【发布时间】:2013-06-22 07:34:31
【问题描述】:

所以,我开始使用 C++,具有半充足的 python 背景。在 python 中,你可以像这样创建一个列表/数组:

x = [1, 2, 3, 4, 5, 6, 7, 8, 9]

然后,要打印包含方括号的列表,您只需:

print x

这会显示这个:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

我如何在 C++ 中做同样的事情,以优雅/干净的方式打印括号和元素?注意我不想要数组的元素,我想要整个数组,像这样:

{1, 2, 3, 4, 5, 6, 7, 8, 9}

当我使用此代码尝试打印数组时,会发生这种情况:

输入:

#include <iostream>
using namespace std;


int main()
{
    int anArray[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    cout << anArray << endl;

}

输出是数组存储在内存中的位置(我认为是这样,如果我错了,请纠正我):

0x28fedc

作为旁注,我不知道如何创建具有许多不同数据类型的数组,例如整数、字符串等,所以如果有人能启发我,那就太好了! 感谢您回答我辛辛苦苦地提出的明显/愚蠢的问题!

【问题讨论】:

  • 请注意:C 和 C++ 是不同的语言。 C 习惯用法在 C++ 中通常有更好的选择。因此,虽然了解 C 是件好事,但在学习 C++ 之前学习它并不是必不可少的(但一旦你掌握了 C++ 的良好水平,它可能会非常有用)。
  • 请记住,有很多人的声誉和 Linus 一样高,他们在用 C++ 编写出色的应用程序方面非常成功,但似乎没有类似的Torvalds 提到的问题。无论我对那个特定的人有多么尊重,我都不会太重视一个人的固执己见,断章取意。
  • @raxman 那么你对任何 C++ 问题的标准答案是使用 C 代替吗?很多人使用 C++ 并喜欢它。继续前进。
  • 可能想看看Boost Explore
  • @raxman:在没有特别关心 C++ 构造的情况下,他仍然可能关心类型安全之类的事情,这是printf 严重失败的领域。

标签: c++


【解决方案1】:

您可以编写一个简单的辅助函数来允许您将数组流式传输到输出流(包括但不限于std::cout):

#include <iostream>
// print an array to an output stream
// prints to std::cout by default
template <typename T, std::size_t N>
void print_array(const T(&a)[N], std::ostream& o = std::cout)
{
  o << "{";
  for (std::size_t i = 0; i < N-1; ++i)
  {
    o << a[i] << ", ";
  }
  o << a[N-1] << "}\n";
}

函数模板用于在编译时推断数组的类型和大小。你可以这样使用它:

#include <fstream>
int main()
{
  int a[] = {1,2,3,4,5};
  print_array(a); // prints {1, 2, 3, 4, 5} to stdout

  std::string sa[] = {"hello", "world"};
  print_array(sa, std::cerr); // prints {hello, world} to stderr

  std::ofstream output("array.txt");
  print_array(a, output); // prints {1, 2, 3, 4, 5} to file array.txt
}

这个解决方案可以简单地推广到处理范围和标准库容器。有关更通用的方法,请参阅here

至于旁注,你不能在 C++ 中做到这一点。数组只能保存一种类型的对象。

【讨论】:

  • 如果数组为空则失败(尝试访问a[-1])。
  • @edA-qamort-ora-y size 0 数组在标准 C++ 中是不允许的,所以这不是问题。
  • @raxman 您有权发表您的意见。当然,我一点也不同意。你现在有了一个可以写入任何输出流的类型安全函数。
  • 我喜欢它,但我想知道std::begin/end 是否可以处理它(因为您在模板中捕获了数组大小。
  • 您可以通过传递迭代器来避免数组按引用传递的丑陋:print_joined(", ", begin(arr), end(arr))
【解决方案2】:

受到 juanchopanza 和 Raxman 答案的启发,我决定做一个真正的 IO 操纵器,其语法如下:

const char* arr[] = { "hello", "bye" };
std::cout 
    << "Woot, I can has " << print(arr)
    << " and even " << print(std::vector<int> { 1,2,3,42 }, ":") << "!\n";

打印

Woot, I can has { hello, bye } and even { 1:2:3:42 }!

注意

  • 它像往常一样使用operator&lt;&lt; 与链式输出流无缝协作
  • 它是完全通用的(支持任何可流式类型的容器)
  • 它甚至允许传递分隔符(例如)
  • 使用更多模板参数,它可以变得非常通用,以便与 ostream、wostream 等一起使用。
  • 有趣:由于分隔符也可以是任何可流式传输的“事物”,您甚至可以...使用数组作为分隔符:

    std::cout << "or bizarrely: " << print(arr, print(arr)) << "\n";
    

    导致相当奇怪的示例输出:

    or bizarrely: { hello{ hello, bye }bye }
    

    仍然展示了无缝连接到 IO 流中的强大功能,如果你问我的话。

我相信在 C++ 中它不会比这更无缝。当然还有一些实现要做,但是正如您所看到的,您可以利用完整的通用性,因此您可以立即完成任何可流式类型的容器:

#include <iostream>
#include <vector>

namespace manips
{
    template <typename Cont, typename Delim=const char*>
    struct PrintManip { 
        PrintManip(Cont const& v, Delim d = ", ") : _v(v), _d(std::move(d)) { }

        Cont const& _v;
        Delim _d;

        friend std::ostream& operator<<(std::ostream& os, PrintManip const& manip) {
            using namespace std;
            auto f = begin(manip._v), l(end(manip._v)); 

            os << "{ ";
            while (f != l)
                if ((os << *f) && (++f != l))
                    os << manip._d;
            return os << " }";
        }
    };

    template <typename T, typename Delim=const char*> 
    manips::PrintManip<T, Delim> print(T const& deduce, Delim delim = ", ") { 
        return { deduce, std::move(delim) }; 
    }
}

using manips::print;

int main()
{
    const char* arr[] = { "hello", "bye" };
    std::cout 
        << "Woot, I can has " << print(arr)
        << " and even: " << print(std::vector<int> { 1,2,3,42 }, ':') << "!\n"
        << "or bizarrely: " << print(arr, print(arr)) << "\n";
}

http://ideone.com/E4G9Fp

观看直播

【讨论】:

  • @raxman 我注意到您的答案已被删除。对此我很抱歉。我仍然从你的回答中得到灵感,写下我自己的看法^。干杯
  • 我删除了它。我不喜欢所有的节制。有人选择性地删除了我的许多 cmets。这太过分和偏颇了。很高兴我的回答启发了你。我有最好的答案。
【解决方案3】:
for(int i=0;i<9;i++)
cout << anArray[i] << endl;

啊,带括号就可以了(只是数组的数组打印逻辑,你以后可以让它更通用)

  cout<<'{';
    for(int i=0;i<8;i++)
           cout << anArray[i] <<','; 
    cout<<anArray[8]<<'}';

对于 python 用户和 c++ 爱好者,有 std::vector 。

这里是如何打印矢量的逻辑 //使用 [] 运算符的解决方案

if(anVector.size()>=1){
     std::cout<<"{";
      for(int i=0;i<anVector.size()-1;i++){
            std::cout<<anVector[i]<<',' ; 

      }
    std::cout<<anVector[anVector.size()-1]<<'}' ; 
}

//用迭代器解决

  std::vector<int>::iterator it =anVector.begin();
       if(it!=anVector.end()){ 
            std::cout << '{'<<*it;
            ++it;
            for (; it != anVector.end(); ++it){
               std::cout<<','<< *it ; 
            }
            std::cout << '}';
        }

还要检查 C++ 11 std::vector 。在新的标准初始化和其他更优雅的事情中

【讨论】:

  • 感谢 QWR 的及时回答,但这不是我想要的。我想要包括括号。
  • @user2511129 请注意,任何需要您手动设置元素数量而不是从数组中获取元素的解决方案都非常脆弱。它也不能重复使用。你不会在 python 中做这种事情,你也不应该在 C++ 中做。
  • @juanchopanza 我很欣赏你的通用解决方案并投了赞成票。甚至建议作为公认的答案。请参阅上述问题的 cmets。我的回答对用户来说很简单。我相信他需要的只是提示。对于一般情况,他可以自己完成工作。
  • 我的解决方案以及 paxdiablo 的解决方案仅适用于静态大小的数组,因为没有可移植的方法来获取动态分配的数组的大小。由于 OP 的示例具有静态大小的数组,我认为提供通用解决方案以最大限度地减少用户错误的范围是有好处的。
  • 是的,但您需要知道length。您不能从指向动态分配数组的指针中推断出它。因此,存在错误的余地。在编译时甚至在运行时都无法知道array 是否确实有length 元素。
【解决方案4】:

可能最简单的方法可以很好地打印一个数组(假设它的长度大于零)是这样的:

std::cout << "{" << anArray[0];
for (int i = 1; i < sizeof (anArray) / sizeof (*anArray); i++)
    std::cout << ", " << array[i];
std::cout << "}";

如果您希望能够打印 less 而不是完整数组,则需要一种方法来指定长度(可能为零,因此您应该处理这种情况:

if (length == 0)
    std::cout << "{}";
else {
    std::cout << "{" << anArray[0];
    for (int i = 1; i < length; i++)
        std::cout << ", " << array[i];
    std::cout << "}";
}

可能还有其他变体,例如在给定的起点打印而不是元素零,但我不会在这里讨论。可以说,这只是对循环和if 条件的小修改。

当然,如果您想以简单的方式使用std::cout &lt;&lt; myvariable;,您可以考虑将整个事物包装在一个类中并为其提供自己的operator&lt;&lt;——这将是一种更加面向对象的方式做事。

【讨论】:

    【解决方案5】:

    如果您不太关心逗号作为分隔符,您也可以使用输出迭代器

    #include <iostream>
    #include <iterator>
    #include <algorithm>
    
    ...
    
    int anArray[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    std::cout << "{ ";
    std::copy(anArray, anArray + 9, std::ostream_iterator<int>(std::cout, " "));
    std::cout << "}" << std::endl;
    

    【讨论】:

    • 有些事情告诉我这不是很方便。通过不将其包装成可重用的东西,您实际上是在回避所有使这变得不那么微不足道的问题。哦,还有你也回避的尾随分隔符问题:/(我知道你知道后者)
    【解决方案6】:

    实现这一点的另一个想法是定义一个宏来将 c 数组转换为 std::vector 和一个模板函数来输出 std::vector,如下所示:

    #include <vector>
    #include <iostream>
    
    // convert an array (e.g. int32_t x[20]) into an std::vector
    #define ARRAY_TO_STD_VECTOR(VAR, TYPE) std::vector<TYPE>(VAR, VAR + sizeof(VAR)/sizeof(TYPE))
    
    // output of std::vector<T>
    namespace std {
      template<typename T>
      std::ostream& operator<<(std::ostream& p, const std::vector<T>& v)
      {
        p << "{";
        for (size_t i = 0; i < v.size(); ++i)
        {
          p << v[i];
          if (i < (v.size() - 1)) p << ", ";
        }
        p << "}";
        return p;
      }
    }
    

    有了这个,你可以像这样输出你的数组:

    int main()
    {
        int anArray[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        cout << ARRAY_TO_STD_VECTOR(anArray, int) << endl;
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-12-16
      • 2012-12-14
      • 2012-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      相关资源
      最近更新 更多