0

I have completed an assignment, but Xcode is giving me a warning about the syntax of my for loop, and I'm not sure how to change it. I am new to programming. I am taking a course.

The assignment is to create two char arrays. One for month names, the other for total days in each month, then print both arrays combined sequentially (Jan 31 Feb 28 etc).

This is what I came up with:

f()
{
    std::string months[] = { "January", "February", "March" };
    std::string days[] = { "31", "28", "31" };

    stringstream ss;

    for (auto i = 0, j = 0; i < 3, j < 3; ++i, ++j)

    {
        ss << months[i] << " " << days[j] << " ";
    }

}

The compiler doesn't like the middle part of the for statement, the test to stop. The message I get says "Expression result unused".

I confess I'm mostly mimicking the samples I've seen from class, but we've never done a loop that evaluates two arrays. I tried a range for loop, but I can't get that to work at all.

8
  • 4
    If i and j never diverge, why have two variables? i < 3, j < 3 is not a valid expression. Commented Feb 18, 2015 at 18:08
  • you are meant to have nested loops Commented Feb 18, 2015 at 18:09
  • 1
    FYI: Comma operator Commented Feb 18, 2015 at 18:09
  • @tadman, It is valid, hence the warning not being an error. Commented Feb 18, 2015 at 18:10
  • 1
    @chris Technically, it's not required to be an error, diagnostics are implementation-defined. He's just plain wrong in general that it's not a valid expression. Commented Feb 18, 2015 at 18:33

4 Answers 4

6

Why would you use two indices? Just write a regular loop:

    for (int i = 0; i < 3; ++i) {
        ss << months[i] << " " << days[i] << " ";
    }
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, I see that now. You're absolutely right. Thank you very much.
4
stringstream ss;

Replace with std::ostringstream ss;.

for (auto i = 0, j = 0; i < 3, j < 3; ++i, ++j)
{
    ss << months[i] << " " << days[j] << " ";
}

In i < 3, j < 3, the comma operator is used. As http://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator says:

In a comma expression E1, E2, the expression E1 is evaluated, its return value is discarded, and its side effects are completed before evaluation of the expression E2 begins [...]. The return type and value category of the comma operator are exactly the return type and the value category of the second operand, E2.

In other words, the i < 3 part is completely ignored (it does not have any side effects, either), and your code is equivalent to for (auto i = 0, j = 0; j < 3; ++i, ++j).

Here is a simpler example to show this behaviour:

#include <iostream>

int main()
{
    int i = 0;
    std::cout << (i != 0, i == 0);
}

This prints 1, because only the i == 0 is considered.

To me, the question is: What exactly do you want to do? Do you want to print both arrays? In that case, you do not need two different index variables at all:

for (auto i = 0; i < 3; ++i)
{
    ss << months[i] << " " << days[i] << " ";
}

There is still room for improvement, though. For example, you may want to assert that both arrays have the same size before iterating them, and you may want to get rid of the magic number 3 in the loop.

4 Comments

Wow, that's an impressive answer. Thank you so much for explaining it to me. I've seen the same thing before in something else I'd written, but didn't know why it was happening. Now I know.
Is there a way to do this with a ranged based for loop?
@TimElhajj: Not any reasonable one, because here you need to iterate two different ranges at the same time, and a range-based for loop is used to iterate one range.
@TimElhajj: I'd like to add that this question (iterating two ranges at once) will become moot once you do what's really needed here, namely creating a class that has two members, one for name and one for days, and then create a collection of that class. Something like class Month { /* ... */ std::string name; int days; } to be used in std::vector<Month>.
2

Change this:

i < 3, j < 3

to this:

i < 3 && j < 3

1 Comment

That is very interesting. you're absolutely right that it works, but it's not as clear to me why. I think it's a temporary writable reference?
1

Use a single index, and use a single array while you're at it:

void f()
{
    struct
    {
        std::string month;
        std::string days;
    } calendar[] = {
        { "January",  "31" },
        { "February", "28" },
        { "March",    "31" }
    };

    for(auto i=0; i<ARRAY_SIZE(calendar); ++i)
    {
        ss << calendar[i].month << " " << caledar[i].days << " ";
    }
}

4 Comments

Looks extremely C-ish to me.
ha, this is the next part of the question, and it was already answered here: stackoverflow.com/questions/6810656/… Thank you!
@abelenky Do I need to include a library to get that ARRAY_SIZE to run? I can use i < sizeof(calendar)/sizeof(calendar[0]). I am just curious about ARRAY_SIZE. Thank you!
ARRAY_SIZE varies depending on platform/compiler. Or it may be _countof(calendar). Do some google depending on your particular platform/compiler to find the right answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.