Trouble with game.display.print() and string array

Hello,
I want to print a string array with the game.display.print() method.

int displayMenu(string menuItems[])
{
    game.display.setColor(graphic_palette[6]);

    int fontPositionY = 25;

    for (int i = 0; i < sizeof(menuItems); i++)
    {
        game.display.setCursor(30, fontPositionY);
        game.display.print(menuItems[i]);

        fontPositionY += 20;
    }

    return 0;
}

But it doesn’t work. Thanks in advance!

1 Like

You’ve got several problems here.


Firstly you might need to use std::string instead of just string.
string comes from the C++ standard library, in the string header.


Secondly, try:

game.display.print(menuItems[i].c_str());

I don’t think Pokitto::Display::print accepts a std::string, I think you have to use a const char * and c_str() is how you get one of those from a std::string.

If your strings are constant, I’d suggest you use const char * instead. std::strings are useful but they’re also a bit ‘heavier’.


Lastly, I’m going to have to explain the inconvinient truth about passing arrays to functions.

When an array is passed to a function, it is no longer an array, it becomes a pointer to the first element of the array. This is because of the rules of C that C++ inherited. As such, sizeof(menuItems) will give you the size of a pointer, not the size of your array.

The common solution to this is to pass the size separately.

So eseentially your function would become int displayMenu(std::string menuItems[], std::size_t size) (I’ll explain the size_t thing in a moment).
You would call it like this:

displayMenu(menuItems, sizeof(menuItems) / sizeof(menuItems[0]));

I know what you’re thinking - “That’s going to be tedious”.
There’s a way to make it less tedious.
There is a way to make it less tedious, but if I show you that way, I most likely won’t be able to explain it to you.
Not because I don’t know how it works, but because it relies on one of the most advanced features of C++ - templates.


Some other tips:

It looks like your return value isn’t doing anything, so you could mark your function void and not bother with a return value.

And when indexing an array, you should use std::size_t instead of int. std::size_t is unsigned (as opposed to int which is signed) and it’s guaranteed to be large enough to express the size of any array on any platform. It’s also the type given out by sizeof expressions.


What your code probably should look like (untested).

void displayMenu(std::string menuItems[], std::size_t size)
{
    game.display.setColor(graphic_palette[6]);

    int fontPositionY = 25;

    for (std::size_t i = 0; i < size; i++)
    {
        game.display.setCursor(30, fontPositionY);
        game.display.print(menuItems[i].c_str());

        fontPositionY += 20;
    }
}
1 Like

we are listening…

@Pharap Thanks for the detailed explenation! :slight_smile:
I‘m also programming in C# and there you just can use the Array.Length property. Sadly there isn‘t anything like that in C++. :confused:

1 Like

Oh yay, that’s what I learnt before C++.
The two go well together.

Actually there is, but there’s a catch.

If you’re on EmBitz and you have C++11 there’s std::array, which has a size() function. The downside is that because of the way it’s defined the size is part of the type so you’d still need template magic.

There’s no dynamically sized array type (though you can make one).
The closest you can get to a dynamically sized array is std::vector, which acts closer to a C# System.Collections.List<T>.
Dynamic allocation should generally be avoided where possible, but it might make things easier for you though, so you may want to try using std::vector for the sake of simplicity.

Well, if you’re sure:

// The function as before
void displayMenu(std::string menuItems[], std::size_t size)
{
    game.display.setColor(graphic_palette[6]);

    int fontPositionY = 25;

    for (std::size_t i = 0; i < size; i++)
    {
        game.display.setCursor(30, fontPositionY);
        game.display.print(menuItems[i].c_str());

        fontPositionY += 20;
    }
}

// Template magic
template< size_t size >
void displayMenu(std::string (&menuItems)[size])
{
  displayMenu(menuItems, size);
}

And then you can just:

displayMenu(menuItems);

(Anyone who is used to a functional language might recognise this as a kind of pattern matching done at compile time with a little bit of type inference thrown in for simplicity.)

2 Likes

it’s seems like cheating, but really awesome. Thanks to show this.

1 Like

It’s better than cheating, it’s template magic

That doesn’t even begin to scratch the surface of the power of templates.
(If you want to see some true wizardry, have a peek here and here, or here.)

1 Like