9

So, I'm beginning C++, with a semi-adequate background of python. In python, you make a list/array like this:

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

Then, to print the list, with the square brackets included, all you do is:

print x

That would display this:

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

How would I do the exact same thing in c++, print the brackets and the elements, in an elegant/clean fashion? NOTE I don't want just the elements of the array, I want the whole array, like this:

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

When I use this code to try to print the array, this happens:

input:

#include <iostream>
using namespace std;


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

}

The output is where in memory the array is stored in (I think this is so, correct me if I'm wrong):

0x28fedc

As a sidenote, I don't know how to create an array with many different data types, such as integers, strings, and so on, so if someone can enlighten me, that'd be great! Thanks for answering my painstakingly obvious/noobish questions!

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
user2511129
  • 101
  • 1
  • 1
  • 3
  • with many different data types . do u mean tuple ? in c u can do it with struct . or there is tuple http://www.cplusplus.com/reference/tuple/tuple/ – qwr Jun 22 '13 at 07:45
  • I have edited my early answer to show a solution that works for a more general case: fixed size arrays of all sizes and containing elements that can be printed. – juanchopanza Jun 22 '13 at 08:01
  • strange .this question still not got accepted answer ..juanchopanza and paxdiable +1 – qwr Jun 22 '13 at 08:15
  • 8
    Beware though: C and C++ are different languages. C idioms often have better alternatives in C++. So while it is good to know C, it is not indispensable to learn it before learning C++ (but it could be quite useful once you get to a good level in C++). – juanchopanza Jun 22 '13 at 13:10
  • 4
    Bear in mind that there are plenty of people out there with reputations as high as Linus' who have been very successful in writing excellent applications in C++, and don't seem to have had the same kind of problems Torvalds refers to. I wouldn't give much weight to one man's opinionated rant, taken out of context, no matter how much respect I have for that particular individual. – juanchopanza Jun 22 '13 at 13:50
  • 11
    @raxman so is your standard answer to any C++ question to use C instead? A lot of people use C++ and like it. Move on. – juanchopanza Jun 22 '13 at 16:39
  • 3
    Might want to look at [Boost Explore](http://svn.boost.org/svn/boost/sandbox/explore/). – Jerry Coffin Jun 24 '13 at 06:08
  • 5
    @raxman: Without particularly caring about C++ only constructs, he still might care about things like type safety, an area where `printf` fails badly. – Jerry Coffin Jun 24 '13 at 06:09
  • @JerryCoffin Nice. I didn't know about that – sehe Jun 24 '13 at 07:27
  • @raxman: `there is a reason Guido van Rossum wrote python in C and not C++` -> Likewise, there is a reason that GCC currently converts to a C++ implementation. There is also a reason why I've chosen to shoot longbows instead of recurve ones. And there's a reason why that dog outside chose to fart there instead of somewhere else. Actually, there are reasons for everything. – Sebastian Mach Jun 24 '13 at 12:34
  • 2
    @raxman: Yes, there is a reason Guido wrote CPython in C instead of C++. Probably more than one reason. [Been discussed before](http://programmers.stackexchange.com/q/20988/902). I stand by my answer there though: the primary reason is that in 1988-1989, C++ wasn't even close to being a viable alternative. – Jerry Coffin Jun 24 '13 at 14:54
  • 2
    nobody seems to have said this directly yet - in general use std::vector instead of arrays (and all the other std:: thingies like map, list etc) – pm100 Jun 24 '13 at 22:07
  • Actually, I said that, my answer (which I deleted) ran over vectors, lists, arrays, ... I never liked the accepted answer because it only worked on static arrays. –  Jun 25 '13 at 13:24

6 Answers6

14

You can write a simple helper function to allow you to stream the array to an output stream (including but not limited to 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";
}

where a function template is used in order to deduce both the type and size of the array at compile time. You can use it like this:

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

This solution can be trivially generalized to deal with ranges and standard library containers. For even more general approaches, see here.

As for the side note, you cannot do that in C++. An array can only hold objects of one type.

Community
  • 1
  • 1
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 2
    This fails if the array is empty (tries to access `a[-1]`). – edA-qa mort-ora-y Jun 22 '13 at 14:33
  • 1
    @edA-qamort-ora-y size 0 arrays are not allowed in standard C++, so this is a non-issue. – juanchopanza Jun 22 '13 at 16:34
  • 3
    @raxman you are entitled to your opinion. Of course, I don't agree at all. You now have a type safe function that can write to any output stream. – juanchopanza Jun 22 '13 at 16:36
  • 1
    I like it, but I wonder if `std::begin/end` would work on it (since you capture the array size in template. – Bartek Banachewicz Jun 24 '13 at 07:31
  • @BartekBanachewicz `std::begin` and `std::end` should work fine. Since I am first iterating up to the N-1th element, I thought (arbitrarily) it would be easier to understand the code using `N` explicitly (plus I was too lazy to go into the whole "this might not work if your compiler does not support C++11..."). – juanchopanza Jun 24 '13 at 07:35
  • 2
    You could do without the uglyness of array-by-ref passing by passing iterators instead: `print_joined(", ", begin(arr), end(arr))` – sehe Jun 24 '13 at 10:51
  • @not-sehe or hurr proper range durr, which is arguably easier to template. – Bartek Banachewicz Jun 24 '13 at 12:32
  • @not-sehe I figured OP would like something that looks like python's `print x` statement, or python3's `print(x)`. Ideally I would overload the function for different types, and use a two-iterator implementation under the hood. But I provided a link with a good solution to the printing containers in C++ problem, and I didn't want to repeat much of what can be found there. I also wasn't expecting this post to garner so much attention :-) – juanchopanza Jun 24 '13 at 12:34
  • @juanchopanza I agree. That's why I have elected to show how to implement a 'proper' IO-manipulator style device :) http://stackoverflow.com/a/17285792/2378523 – sehe Jun 24 '13 at 21:52
  • @not-sehe: But it's not ugly! – Lightness Races in Orbit Jun 24 '13 at 22:25
7

Inspired by the answers of juanchopanza and Raxman I decided to do a real IO manipulator, which leads to a syntax like:

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

printing

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

Note

  • it works seamlessly with chained output streaming using operator<< as usual
  • it is fully generic (supporting any container of streamable types)
  • it even allows to pass a delimiter (as an example)
  • with a little more template arguments it could be made so generic as to work with ostream, wostream etc.
  • fun: Since the delimiter can be any streamable 'thing' as well, you could even... use an array as the delimiter:

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

    resulting in the rather weird sample output:

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

    Still demonstrates the power of hooking seamlessly into IO streams, if you ask me.

I believe it will not get much more seamless than this, in C++. Of course there is some implementing to do, but as you can see you can leverage full genericity, so you're at once done for any container of streamable types:

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

See it live at http://ideone.com/E4G9Fp

sehe
  • 374,641
  • 47
  • 450
  • 633
  • @raxman I noticed your answer got deleted. I'm sorry about that. I still got inspiration from your answer to write my own take ^ on this. Cheers – sehe Jun 24 '13 at 22:21
  • I deleted it. I did not like all the moderation that was done. Someone was selectively deleting many of my comments. It was far too excessive and biased. I'm glad my answer inspired you. I had the best answer. –  Jun 25 '13 at 13:14
2
for(int i=0;i<9;i++)
cout << anArray[i] << endl;

ahh ok with brackets it be such (simply array print logic for your arrays , u can make it more general in future)

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

For python users and c++ lovers there is std::vector .

here how it be print logic for vector //solution with [] operator

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]<<'}' ; 
}

//solution with iterator

  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 << '}';
        }

Also check C++ 11 std::vector . In new standart initializing and other things more elegant

qwr
  • 3,660
  • 17
  • 29
  • Thanks QWR for the prompt answer, but this is not what I want. I want the brackets included. – user2511129 Jun 22 '13 at 07:39
  • @user2511129 note that any solution that requires you to manually set the number of elements, instead of obtaining them from the array, is quite fragile. It is also not re-usable. You wouldn't do this kind of thing in python, and you shouldn't do it in C++ either. – juanchopanza Jun 23 '13 at 06:30
  • @juanchopanza i appreciate your general solution and voted up . even suggested as an accepted answer . see comments on question above. my answer was simlple for the user . i believe he needed just hint . he could do function by himself for general case . – qwr Jun 23 '13 at 07:57
  • I just wanted to be sure OP understood that. If they are coming from python, they might except a nice exception for an out of bound access, but C and C++ offer no such niceties. – juanchopanza Jun 23 '13 at 08:02
  • @QWR don't worry about it, your answer is OK. If you want, you can edit it to add a warning about the size of the array. – juanchopanza Jun 23 '13 at 08:15
  • @raxman thx raxman .I know i wrote general print logic that shows how it can be achieved and it was for OP. i mentioned paxdiablo juanchopanza solutions for future viewers . – qwr Jun 23 '13 at 12:54
  • 1
    My solution, as well as paxdiablo's, only work for statically sized arrays because there is no portable way to obtain the size of a dynamically allocated array. Since OP's example has statically sized arrays, I think there is merit in providing general solutions that minimise the scope for user error. – juanchopanza Jun 23 '13 at 13:22
  • @juanchopanza for paxdiablo's solution you can write function void print(int* array ,int length) .(note that one dimensional array decay to pointer ) – qwr Jun 23 '13 at 13:30
  • 1
    Yes, but you need to know `length`. You cannot deduce it from the pointer to the dynamically allocated array. So, there is scope for error. There is no way to know at compile time, or even at runtime, whether `array` indeed has `length` elements. – juanchopanza Jun 23 '13 at 13:32
1

Probably the easiest way to get an array printed nicely (assuming it has a length greater than zero) is with something like:

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

If you wish to be able to print less than the full array, you'll need a way to specify the length (which may be zero so you should handle that case:

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

There may be other variations of that such as printing at a given starting point rather than element zero but I won't go into that here. Suffice to say, it's just a small modification to the loop and if condition.

Of course, if you want to do it the simple way, with std::cout << myvariable;, you can consider wrapping the whole thing in a class and providing your own operator<< for it - that would be a more object-oriented way of doing things.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

If you don't care too much about having the comma as a separator, you could also use output iterators.

#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;
damix911
  • 4,165
  • 1
  • 29
  • 44
  • Something tells me that's not very convenient. By not wrapping it up into something reusable, you're actually sidestepping all the issues that make this less trivial. Oh, and then there it the trailing delimiter issue that you also sidestepped :/ (I know you are aware of the latter) – sehe Jun 24 '13 at 22:23
0

Another idea to achieve this, is to define a macro to convert c-arrays to std::vector and a template function to output a std::vector, like this:

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

Having this, you can output your array like this:

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

}
Roland
  • 1
  • 2