Search

6.12a — For-each loops

In lesson 6.3 -- Arrays and loops, we showed examples where we used a for loop to iterate through each element of an array.

For example:

While for loops provide a convenient and flexible way to iterate through an array, they are also easy to mess up and prone to off-by-one errors.

C++11 introduces a new type of loop called a for-each loop (also called a range-based for loop) that provides a simpler and safer method for cases where we want to iterate through every element in an array (or other list-type structure).

For-each loops

The for-each statement has a syntax that looks like this:

for (element_declaration : array)
   statement;

When this statement is encountered, the loop will iterate through each element in array, assigning the value of the current array element to the variable declared in element_declaration. For best results, element_declaration should have the same type as the array elements, otherwise type conversion will occur.

Let’s take a look at a simple example that uses a for-each loop to print all of the elements in an array named fibonacci:

This prints:

0 1 1 2 3 5 8 13 21 34 55 89

Let’s take a closer look at how this works. First, the for loop executes, and variable number is set to the value of the first element, which has value 0. The program executes the statement, which prints 0. Then the for loop executes again, and number is set to the value of the second element, which has value 1. The statement executes again, which prints 1. The for loop continues to iterate through each of the numbers in turn, executing the statement for each one, until there are no elements left in the array to iterate over. At that point, the loop terminates, and the program continues execution (returning 0 to the operating system).

Note that variable number is not an array index. It’s assigned the value of the array element for the current loop iteration.

For each loops and the auto keyword

Because element_declaration should have the same type as the array elements, this is an ideal case in which to use the auto keyword, and let C++ deduce the type of the array elements for us.

Here’s the above example, using auto:

For-each loops and references

In the for-each examples above, our element declarations are declared by value:

This means each array element iterated over will be copied into variable element. Copying array elements can be expensive, and most of the time we really just want to refer to the original element. Fortunately, we can use references for this:

In the above example, element will be a reference to the currently iterated array element, avoiding having to make a copy. Also any changes to element will affect the array being iterated over, something not possible if element is a normal variable.

And, of course, it’s a good idea to make your element const if you’re intending to use it in a read-only fashion:

Rule: Use references or const references for your element declaration in for-each loops for performance reasons.

Rewriting the max scores example using a for-each loop

Here’s the example at the top of the lesson rewritten using a for each loop:

Note that in this example, we no longer have to manually subscript the array. We can access the array element directly through variable score.

For-each loops and non-arrays

For-each loops don’t only work with fixed arrays, they work with many kinds of list-like structures, such as vectors (e.g. std::vector), linked lists, trees, and maps. We haven’t covered any of these yet, so don’t worry if you don’t know what these are. Just remember that for each loops provide a flexible and generic way to iterate through more than just arrays.

For-each doesn’t work with pointers to an array

In order to iterate through the array, for-each needs to know how big the array is, which means knowing the array size. Because arrays that have decayed into a pointer do not know their size, for-each loops will not work with them!

Similarly, dynamic arrays won’t work with for-each loops for the same reason.

Can I get the index of the current element?

For-each loops do not provide a direct way to get the array index of the current element. This is because many of the structures that for-each loops can be used with (such as linked lists) are not directly indexable!

Conclusion

For-each loops provide a superior syntax for iterating through an array when we need to access all of the array elements in forwards sequential order. It should be preferred over the standard for loop in the cases where it can be used. To prevent making copies of each element, the element declaration should ideally be a reference.

Note that because for each was added in C++11, it won’t work with compilers that don’t have support for C++11.

Quiz

This one should be easy.

1) Declare a fixed array with the following names: Alex, Betty, Caroline, Dave, Emily, Fred, Greg, and Holly. Ask the user to enter a name. Use a for each loop to see if the name the user entered is in the array.

Sample output:

Enter a name: Betty
Betty was found.
Enter a name: Megatron
Megatron was not found.

Hint: Use std::string as your array type.

1) Show Solution

6.13 -- Void pointers
Index
6.12 -- Member selection with pointers and references

178 comments to 6.12a — For-each loops

  • I have a question in "For-each loops and references" Section
    Statement "for (auto &element: array)"
    i understand that no copying of the array element is being made now, but this reference variable is still getting a copy of the address of the new element with every iteration (if &element acts like a const pointer).
    should this be a comparable expensive copy also of the address or compiler treat reference differently in this case ?

    • Hi Michael!

      The answer to this question will vary across compilers. Ideally, the reference should be treated as an alias, not as a pointer.

      > comparable expensive copy
      It depends on the type you're iterating over. For standard types (those of size 2^n bytes, n<4), a copy of the data should be equally, or very close to equally, expensive as a copy of the address. Other types should always be passed by reference or pointer.

  • I did it and it seems to work.

    Ok, I may have gone a bit OTT on the comments but at least it shows where each stage is at...

    • Hi Nigel!

      In the future, you can use @std::find from <algorithm> to avoid having to write a loop every time.

      References
      std::find - http://www.cplusplus.com/reference/algorithm/find/

      • Thank you nascardriver but as the whole tutorial was about using the for each loop that was how I approached it (and we haven't covered @std::find yet). However, it is interesting in that it doesn't then need the bool{} comparison.

        • That's why I said "In the future". @std::find isn't covered on learncpp and Alex doesn't mention the @std functions in quiz solutions, so I'm doing it in comments.
          @std::find returns the element it found, or the end of the array if no element has been found.

  • Hector

    First of,Thanks Alex for making this site and thanks nascardriver for answering people doubts on such regular basis...
    So,I juist wanna know how can I set -std=c++14 as default?
    I am working on ubuntu16.04 and this what i use for compiling...

    • Hi Hector!

      The easiest solution is probably setting an alias

      in ~/.profile

      After logging out and back in you can use

      Also, you're still using g++5, which doesn't support many of the features introduced after C++14. It might be worth upgrading.

      • Hector

        Yes sir, i'm still suing g++ 5.4.0 . I tried googling on how to upgrade it.This is what i found out. g++ can't be individually upgraded(as g++ is a package within gcc) so I downloaded gcc 7.3.0.
        For instructions on how to install it there were two ways mentioned.
        1)./install.sh
        2)./configure
        make
        sudo make install
        There were some other sources which also suggested adding a repository and then going for it(that's the option I didn't choose).
        Now my problem is that it what if after installing newer gcc7.3.0 the older also remains and what if I want to remove older?some sources say removing the original version is bad.
        Moreover what will be the default version that will be used?

        I know this question has nothing to do with c++ but i'm askingthis coz this all came up when i tried using for each loops and auto with my older version.I have also posted this question on askubuntu.org.
        But i trust u better and will take yopur word for it.
        Please guide.

        • > gcc 7.3.0
          gcc 8.2 is already released

          > adding a repository
          This is the better option in my optinion, because you will get updates for gcc when you update your packages, plus you don't have to worry about the problem you're describing. I can't help you with your old version, new version problem, because I've never built gcc from source, I'm using my package manager.

  • Hector

    Sorry ,don't bother...Solved it...The problem was -std=c++11

  • mce1

    Hi Alex,

    when I compile the first example of a ranged-based for loop on this page (the one with

    ) I get two warnings:

    main.cpp|6|warning: range-based ‘for’ loops only available with -std=c++11 or -std=gnu++11|
    main.cpp|7|warning: ‘number’ is used uninitialized in this function [-Wuninitialized]|

    When I ignore these warnings and run the program, it keeps printing numbers to screen indefinitely.

    When, instead, I write

    and do not declare number before that at all everything works fine.

    Is that something to worry about? Can you explain the different behaviour on my system from yours?

    I'm using Code:Block with ubuntu 16.04.

    Cheers,

    mce1

    • Hi mce!

      I don't know why the second code is working. The first warning is important though, you need to tell your compiler to use a newer version of C++ to have access to for-each-loops.
      I don't know where compiler settings are located in codeblocks, you'll have to look that up. When you found them, tell the compiler to use the newest version available by adding

  • Idda

    hi Alex,
    I was trying to use for-each loop to print values of dynamic array;
    but on compiling it showed following error(on DEV C++):    [Error] 'begin' was not declared in this scope
    can you suggest why it is showing the error,and can you suggest me solution?

    • Quoting the lesson: "For-each doesn’t work with pointers to an array"
      @num is a pointer to an array.

      Notes:
      * Line 5, 8, 9: Initialize your variables with uniform initialization
      * Line 9: Use ++loopvar
      * Line 16, 17: Can be done in one line
      * @main: Missing return statement.

  • kam

    Thank you for good discussion.

  • DecSco

    I think this part of the solution

    is a good opportunity for the ? operator:

  • Peter Baum

    I didn't understand why

    "Rule: Use references or const references for your element declaration in for-each loops for performance reasons."

    was phrased this way.  I suggest

    Rule: If possible, use references and/or const references for your element declaration in for-each loops for performance reasons.

    • Alex

      I'm not understanding why you think adding "if possible" is desired. What case are you thinking of where you might not want to, or it might not be possible?

      • Peter Baum

        It might not be possible because its use might change a value so it isn't a const or it might be a reference whose use would change the original and you don't want that effect.

        • Alex

          I see. I think the difference is in the way we're parsing that sentence. The intended way to read the sentence is "Use references or use const references (as appropriate) ..."

          Using a const reference would be appropriate when you want to ensure the referenced value isn't modified.

          • Peter Baum

            What I find hard about writing is that sometimes what seems obvious to me is interpreted differently by the reader.  That is why having work edited is so critical.  Overall you do a good job, but writing well is hard.

            • Alex

              For sure, and that's part of the reason I value user feedback so much. It's challenging to get something understandable, precise, and correct all simultaneously. 🙂

  • Peter Baum

    Problems I had with the given solution:

    1. The sample output suggested to me that the user should be able to enter more than one name before the program exits.

    2. Given 1, we need a way to exit, for example if the user simply hits the enter key.

    3. We should allow spaces in names.

    4. I don't like code that makes things overly complex just to avoid the (dreaded) goto statement.

    with that in mind, here is a possible solution:

    • nascardriver

      Hi Peter!

      > We should allow spaces in names
      Good point

      • Peter Baum

        Hi nascardriver!
        Thanks so much for going over the suggested solution in such detail.  Although I don’t agree with some of your suggestions, it is always helpful for me to hear what other people think and always helpful to have such discussions aired in a comment section.
        With respect to your specific suggestions:

        ***Regarding - Initializing every variable even if the compiler initializes it and even though it is obvious that its first use is to set a legitimate value to it –***

        The problem with trying to make this a rule is that you would then have to figure out a value that would then be detected if the variable was used inappropriately.  If you can’t find such a value, you have not gained anything.  It might not be a problem for some variables, for example, with a pointer, you might be able to use NULLPTR.  I wouldn’t know what to do for some other variables.

        Now variables have a data structure associated with them, so a compiler or run-time system should be able to detect use without initialization.  For systems that do this, then we should not set the variable to a value, because then you bypass this safeguard.

        There is another disadvantage of prematurely setting a value to a variable.  When someone reads the code, they have to wonder about the possible reason for the particular value.  Even if the information is in a comment, that takes time to read and think about.

        ***Regarding - Never use goto –***

        I think it is helpful to understand how this rule came about.  Some programmers (some claim “mere academics”), who primarily programmed a certain class of algorithm, saw, in some instances, some very confusing “spaghetti” code that led to errors that were hard to debug.  They were not wrong with respect to that experience.  However, to derive a rule from this experience and suggest others follow it blindly is quite another matter.  In fact, for some algorithms, such as those that utilize state machines, it makes absolutely no sense to follow this rule.  

        I also think it is a disservice to students not to show legitimate use of the goto, and I think this is exactly why this example should be highlighted as an example of good coding practice.

        (continued in next post; system doesn't like long posts)

      • Peter Baum

        (continued from previous)
        ***regarding – Don’t use ADL unless you have to ***
        I don’t know if this is a good idea here or not.  I just learned about ADL myself and thought it a good idea to share with other people.  Perhaps you can provide an example of a situation where, as you suggest, one has to use that feature.

        ***regarding – Returning from inside loops can be confusing.***
        I don’t understand what is confusing about its use in this instance.

        ***regarding – use of conditional operator for output ***
        It is a nice idea, especially if you already have the bool around.  There are many perfectly fine solutions to almost any programming problem, each with their own set of advantages and disadvantages.

        *** In general ***
        You don’t become a good programmer by blindly following a set of rules.  Instead, you become a good programmer by learning to think for yourself and adapting your style to the problem at hand.  I tend toward the “give me the tool, not the rule” approach.  However, I actually am interested in rules.  Rules are great at pointing you in a direction where you then try to understand the why involved.  That lets you use the rules appropriately.

        Again, thank you for taking the time to comment on the code.  The work you have done on this site is a great asset and I appreciate it very much.

        • Alex

          Good discussion. In your sample code, because label "more" is at the top of the loop, you're better off using a continue statement than a goto. A coder will understand exactly what continue does at a glance. With a goto, you then have to scan the code to see where the endpoint is (could be at the top, bottom, middle, etc...). In general, I find goto can almost always be avoided without adding code complexity. If it can't, then your function may be too complex. If it isn't, then you've probably found a legitimate use case for goto. They do exist (especially if you're not using exceptions).

          I agree that early returns are not something to be avoided. Personally, I like them because they make code simpler (if you use a break or goto just to route the path of execution to the single return at the bottom, you're making your code more complicated because now the developer has to realize this is your intent and then figure out that all the other bits of code between here and there aren't executing in that case).

          • Peter Baum

            The problem with continue in this example is that if this replaces the goto, the statement about not finding the name is output right after the statement about finding the name.  That is not the desired behavior.

            • Alex

              Not true. Continue jumps back to the beginning of the loop, which will skip over the statement about not finding the name. This is something you can validate by trying it yourself.

              (edit: My mistake)

              • Peter Baum

                Because I did try it out and got the effect I described, it must be that we are talking about different code.  Also, if all that is needed is to replace the goto with a continue, then why wasn't this done in the example?

                • Alex

                  I see, my mistake. I sure messed that one up.

                  In the code you wrote, I probably would have made the inner loop a separate function. Gotos are most useful when you're trying to jump >1 loop -- but you can essentially avoid that by not having >1 loop in a given function.

              • nascardriver

                There's a nested loop

        • nascardriver

          > I don’t agree with some of your suggestions
          That's fine. I'm by no means an expert and tomorrow I might think differently about things I say today.

          Uninitialized variables
          > you would then have to figure out a value that would then be detected if the variable was used inappropriately.
          The detection of uninitialized variables isn't the issue, that's up to the compiler. The problem is that your program will be non-deterministic, that is, it behaves in a different way every time it's executed. This makes debugging a real pain. On the other hand, with initialized variables, you'll get the exact same behavior every time. It might take you longer to find out that there's a problem (The variable that's not assigned the correct value), but once you've noticed it you can find it a fraction of the time you'd need to find an uninitialized variable.

          > I wouldn’t know what to do for some other variables
          0, "" or simply empty curly brackets to make clear that you're leaving initialization up to the default constructor.

          > Now variables have a data structure associated with them, so a compiler or run-time system should be able to detect use without initialization.  For systems that do this, then we should not set the variable to a value, because then you bypass this safeguard.
          That's true, but you shouldn't expect that everyone who's using (or developing) your code uses a compiler with this functionality.

          > When someone reads the code, they have to wonder about the possible reason for the particular value.
          I think recognizing the default values I mentioned above shouldn't be hard enough to make someone wonder why they were used, but I get your point.

          When declaring a variable you're either already able to initialize it to the correct value or you're going to pass it to a function for it to be assigned a value.
          In the first case there's no reason to not initialize it and in the second you shouldn't rely on the function you're calling to be able to handle uninitialized variables. You might know that this function doesn't use the value, but code should be written in a way that allows a reader not familiar to this function to be able to tell that there's nothing wrong.

          I understand your point of view and won't tell you to initialize all your variables in future submissions (Unless it could lead to problems).

          Goto
          About replacing your 'goto' with a 'continue', it's not that easy, simply because you're inside a nested loop and there's no single-line solution to break all loops. The easiest way to break multiple loops is indeed 'goto', but in the majority of cases the control flow of code that uses 'goto' is harder to understand than code that does the same without the use of 'goto'. Blindly following the "no goto" rule (or any other) isn't the smartest thing to do, but it's not a rule that was made up by a single person, it's a rule that was created by multiple people, each on their own, and there's a reason for that.

          ADL
          > Perhaps you can provide an example of a situation where [...] one has to use that feature

          operator<<(const std::ostream &, const std::string &) is declared in the 'std' namespace but there's no way for us to explicitly state this when using the operator.

          Returning from inside loops
          > I don’t understand what is confusing about its use in this instance.
          I looked at the end of @main, there was no 'return', I was confused.

          General (Rules)
          Some rules are just there to make your code easier and more reliable, but some other rules should be followed, because C++ is a language that allows you to do certain things that are rarely what the programmer desired.

          > The work you have done on this site is a great asset and I appreciate it very much.
          Thanks

          • Peter Baum

            Hi Nascardriver:

            Here are some further thoughts.

            ***” The detection of uninitialized variables isn't the issue, that's up to the compiler.  The problem is that your program will be non-deterministic…”***

            1. If the compiler (and run-time system) detects uninitialized variables, then the problem is detected before any damage can be done, so one can’t properly call the program non-deterministic.

            2. If the compiler automatically initializes the variable, which you thought was the case in the program under discussion (“std::string initializes itself”), then the program we are talking about is deterministic.

            3. Just a note: The problem of uninitialized variables is not always a problem if modern compilers are used.  Under Visual Studio Community 2017, in the following program the uninitialized variable is detected and the program won’t compile:

            Sometimes it is a problem, but you almost have to put a little effort into it to make it happen.  The following does output from an uninitialized location:

            4. I agree that non-deterministic programs can be problematic and generally something to be avoided.

            5. Suppose the compiler does put in a default value.  For example, we might write

            and then suppose the variable is used before being given a proper value.  On my compiler, the default value given is 0.   I’m not sure about the probability of finding an error in this case as opposed to obtaining a random number at run time.  With a default value of 0 , it is often likely to execute without an obvious, immediate error, even though its use with that value may not be the intent.  To consider probabilities, we would have to compare this with the use of random numbers, including say, a large, random, negative number.

            6. You could initial a variable with a value that you thought would be easy to detect if used before it was given a proper value.  Depending upon the exact situation, it might be hard to determine such a value, which is why I said “…I wouldn’t know what to do for some other variables.”

            7. The above leads me back to the idea that if you want proper protection from this kind of error, then the compiler and run-time system needs to keep track of uninitialized variables.  There would be a time penalty to pay for this but I believe I have seen the ability to turn this checking on and off.  Thus, you could have it on during testing and off otherwise.

            Note that if you use this better method of detecting unintentionally uninitialized variables, then you should NOT follow the rule of initializing them yourself or letting the compiler initialize them with some default value.

            ***> Now variables have a data structure associated with them, so a compiler or run-time system should be able to detect use without initialization.  For systems that do this, then we should not set the variable to a value, because then you bypass this safeguard.
            That's true, but you shouldn't expect that everyone who's using (or developing) your code uses a compiler with this functionality.***

            I’m not sure where this leads us.  The approach I’m suggesting would be no problem for me or programmers using the same or similar compilers.  Are you suggesting that instead I program in a style that is less than ideal for me and programmers with similar compilers and do so in the hope that it might be marginally safer when using some other unknown compiler?

            *** Goto ***
            1. Although not appropriate here, it would probably be helpful to talk about the structure this rule imposes on algorithms and the kinds of algorithms for which it is and is not appropriate.

            2. There might be another way to create a “solution” half-way between these two approaches by being able to make BREAK apply to specific nested looping structures.  I’ve never seen this done, perhaps because the goto already solves this kind of problem in a more general way.

            3. Regarding “…it's a rule that was created by multiple people, each on their own, and there's a reason for that.” – I have a number of problems with this statement.
                a. The issue shouldn’t be framed in terms of an absolute rule, but rather, the more nuanced “when is each technique appropriate?”
                b. The issue shouldn’t be decided by an appeal to authority.
                c. The issue shouldn’t be decided as a popularity contest.

            4. One thing that we haven’t talked about is the tradeoff between execution speed and memory.  Perhaps one of the reasons I like the goto is that I am often concerned about execution speed.  Again, we tend to do things depending upon the kind of algorithms we are most interested in or most familiar with.

            ***ADL***
            ***> Perhaps you can provide an example of a situation where [...] one has to use that feature

            operator<<(const std::ostream &, const std::string &) is declared in the 'std' namespace but there's no way for us to explicitly state this when using the operator.***

            I’m not sure I understood what you are saying.  Can’t you write

            ?

            ***I looked at the end of @main, there was no 'return', I was confused.***

            1) The end of an infinite loop wouldn’t have a return following it because that code could never execute (unless labeled for use with a goto.)
            2) The return at the end of @main is optional, although in that case (with my compiler)  the return code defaults to 0.
            3) When I see main or any other function without a return, I simple know that it either exists elsewhere or some kind of default behavior is at play.  That doesn’t sound confusing to me.

            Some of these issues are complicated, so it is wonderful to have someone who is willing to think about them with me and share their thoughts on the matter.  I learn a great deal in the process.  Thank you.

            • nascardriver

              > for me or programmers using the same or similar compilers
              Write your code in a way that produces the same program no matter which compiler is used (You can assume a C++ version though). You're free to use compiler features, but don't use compiler-specific language extensions (Like a default return value for @main).

              > Perhaps one of the reasons I like the goto is that I am often concerned about execution speed
              g++ produces the same output for goto and a temporary so there's no tradeoff, at least with g++.

              >

              You're just casting @str to an @std::string, but it already is an @std::string so this has no effect. I'm talking about the operator itself, you can't do things like this or similar

              > The end of an infinite loop wouldn’t have a return following it because that code could never execute
              True, but knowing that it's an infinite loop requires me to look at your loop to determine if the function returns.

              > When I see main or any other function without a return, I simple know that it either exists elsewhere or some kind of default behavior is at play.
              Or someone forgot a return statement.

              Sorry I'm not answering all your points, I have a feeling this is going to turn into a discussion about coding preferences. If you know what you're doing do so.

              • Peter Baum

                Regarding:
                ***Perhaps one of the reasons I like the goto is that I am often concerned about execution speed
                g++ produces the same output for goto and a temporary so there's no tradeoff, at least with g++.***

                I find it very hard to believe that this would always be the case.

                • nascardriver

                  It's true for breaking multiple loops, which is the only use of 'goto' I'm willing to accept. I couldn't find information about this in the g++ documentation, but if it's working on a small scale I don't see a reason for it to stop working on a larger scale, it's the same code again and again.

                • Peter Baum

                  One of the problems here is that very few people look at the actual code generated by compilers.  If they did, they would be horrified.  I say this while understanding and accepting the fact that compilers have to try to convert code in a very general way (for the most part) or else, as a practical matter, things get way too complex.

                  Another problem is that compilers can only create code from information in the source code. For speed optimized code there is a very close relationship between the chosen algorithm and the available machine language.  That is what is sacrificed by using a high level language.  That link is essentially broken. I say "essentially" because although compiler writers take this into account with respect to the algorithms they use, the link to the algorithms of the programmers they serve is broken.

                  We saw this issue in the given solution, which then used the Boolean in the conditional ?: operator as part of cout output.  Once you have a Boolean, it starts to get used in ways that change the algorithm.

  • Gabi

    "For-each doesn’t work with pointers to an array
    In order to iterate through the array, for-each needs to know how big the array is, which means knowing the array size. Because arrays that have decayed into a pointer do not know their size, for-each loops will not work with them!"

    ?

  • Louis

    Hi Alex! Just wondering if this code would be considered good style to output whether the name was found or not:

    instead of:

    • nascardriver

      Hi Louis!

      Using strings like that usually isn't a good thing. I'd stay with the bool and use a conditional operator to keep the entire string in one line.

      Alex's solution is probably the best, because it allows easy implementation of localization (translation).

  • blange

    Hello there learn-cpp-team,
    first of all great job, please keep it up!
    I have a suggestion for the site's index.
    Please add an entry like "range-based for loop"
    that points to this site. You are mentioning
    this synonym for a "For-each loops" in the text,
    but it cannot be found in the index.

    Thank you!
    Benjamin

  • Swati

    • nascardriver

      Hi Swati!

      Line 4: Don't use 'using namespace' (Lesson 4.3c)
      Line 8: Initialize your variables (Lesson 1.3, 2.1)
      Line 9,11: Uniform initialization is preferred (Lesson 2.1)

      But no issues with your loop, good job!

  • Matt

    This quiz was pretty simple to handle inside of main() but I'm pretty sure it is impossible to complete (using a for-each loop) outside of main()... I fiddled with it for a while before giving up.  Here's as close as I could get (without reverting to a typical for loop).

    • Matt

      So with some more fiddling I was able to make it work, but not quite satisfactorily.  To get it to work required using a magic number in the function parameters for @hasMatch().

      Clearly more practice is needed.

      • Alex

        Yeah, the challenge here is that for-each needs full type information about the C-style array to iterate over it -- and that requires the length of the array to be passed as a parameter.

        There are several ways around this:
        * Make your hasMatch() a template function with the array length templated (see chapter 13)
        * Use a container other than a C-style array (e.g. std::vector)

    • nascardriver

      Hi Matt!

      I didn't see you solved it yourself until after writing my reply. I'll drop it here anyway, because you have some unrequired code in @main.

      • Matt

        So I don't need to create my own references, I can just pass the array and in  the receiving function ask for a reference and one will be created?

  • Marion

    Typo at the end of the "For-each loops" paragraph: "It’s assigned the value of --the the-- array element for the current loop iteration" (double "the")

    Great tutorial btw 😉

  • merocom

    • nascardriver

      Hi merocom!

      Good job! I've modified your code and added comments below.

  • A.

    > Note that because for each was added in C++11, it won’t work with older compilers.

    ....or new compilers that default to a previous standard - e.g. the latest g++

    Adding `-std=c++11` as an option to the compilation command makes things tickety-boo again for that specific compiler.

    Can I suggest adding a line saying that it might be an idea to check their compiler's default settings, since even modern compilers might not be happy with examples here and give people who are tinkering with examples an impression that their code is wrong as opposed to a legacy default setting in their compiler.

    • Alex

      While true, that's a caveat I'd have to add everywhere I mention C++11, C++14, or C++17, which I'm not willing to do. I will add an entry to the FAQ mentioning this though.

  • Dani

    Hi Alex,
    Since functions should do specific tasks, I was trying to make the quiz, rather than all thrown in main, with different function.
    And when I get to the function "searchNameOnArray" I faced the issue of forEach not working with pointers.
    So I was wondering if there's a way to use an array itself as an argument and so use forEach, or if forEach should only be used in the same block in which the array is declared and forget it in any other situation.

    • Alex

      Yes, you can pass the array by reference to your function instead of by value, which prevents the decay. Here's how you'd pass an array of 10 doubles by reference:

  • Wayne Wang

    Comment
    int maxScore = 0; // keep track of index of our largest score
    Should be
    int maxScore = 0; // keep track of our largest score

  • Leea

    Alex,

    When an array element is copied (such as in the for each loop) does the copy have its own memory address? When you say making copies is expensive, is that because more memory needs to be allocated for them? I don't understand what is happening behind the scenes when a copy is being made of a variable or array element.

    Thank you in advance 🙂

    • Alex

      Yes, copies have their own memory addresses (as copies need to live _somewhere_ in memory). Copies are "expensive" because the CPU (at runtime) needs to copy however many bytes are in the source object into the destination object. For example, let's say we had a struct that was 1000 bytes in size. If we made a copy of that struct, the CPU would have to copy 1000 bytes from the original struct into the copied struct. It's not the 1000 bytes of memory being used temporarily that's the issue (because the copy will get destroyed when it goes out of scope anyway), it's the time taken to duplicate the object in memory that's the issue.

      Additionally, copying classes is even more expensive because they have special functions that run to create and destroy them (constructors and destructors). This takes even more time.

      Copying a pointer or reference, on the other hand, typically only involves copying 4 or 8 bytes of data, which is much less.

  • Nicolas

    Hello Alex, I'm having issues with the code that I wrote for the quiz.

    I get an error at if (bool nameEntered == true) and at else if (bool nameEntered == false). I thought making a boolean to check if the user typed in one of the names would be smart, but i dont know why it doesnt just check if nameEntered is true or false. "expression preceding parenthesis of apparent call must be a pointer-to funtion type" is what it says

    • Alex

      There are three issues here:
      1) Inside the upper if/else, you're declaring nameEntered as a local variable to the block it's defined in. That means it gets destroyed at the end of the block. By the time we get down to the lower if/else, nameEntered has already been destroyed. Fix: Define nameEntered once before the for loop.
      2) You're not stopping the loop when determining that nameEntered is true, so if the user enters any name other than Holly, the loop will set nameEntered to false. Fix: Initialize nameEntered to false, and then set it to true if any of the names match.
      3) In the lower if/else, you're doing a comparison incorrectly. The compiler thinks nameEntered(true) is a function call and it can't find a function with that name (same for the false case). Fix: Use nameEntered == true.

  • AMG

    Cannot figure out why enum type is not allowed in for-each loop. Any thoughts? Thanks.

    • Alex

      It is allowed:

  • Michele

    Hi Alex!

    First of all I wanted to thank you for these wonderful tutorials, I really am learning a lot!

    Second, I think there is a mistake in the quiz' solution: that break shouldn't be there.
    If username isn't equal to the first element of the array, it exits the loop without looping through the rest.

    • Alex

      No, it's correct as written. If the username isn't equal to the first element of the array, this line will evaluate to false:

      So the break will never execute until name == username, at which point we have a definitive answer and can exit the loop.

      • Michele

        I looked again at my code and saw I made a stupid mistake. My if-statement was inside the curly brackets... Thanks for the quick reply!

  • justAnotherConfusedStudent

    For your max scores rewritten example, would it be more efficient if we iterated over a reference instead of just score (like below)?

    • Alex

      When your array is a fundamental type, iterating by value is okay since making a copy of the element isn't more expensive than setting up a reference.

      But I agree, using a const reference here is probably a better choice. I'll update the example.

  • C++ Learner

    when found gets out from for loop it becomes true?(bool found=true)

    • Alex

      found gets set to true if name==username for any of the loop iterations. It will keep whatever value it was last set to even outside of the loop.

  • James

    iterate through each element in array
    iterate through each element in the array
    Although I guess if the variable is actually called array then the grammar makes sense.

  • Dani

    #include <iostream>
    #include <string>

    using namespace std;
    int main()
    {  string name[] ={"Alex", "Betty", "Caroline", "Dave","Emily", "Fred", "Greg","Holly"} ;
       string input_name ;
       cin >> input_name ;
       for (auto print : name )
       {
          if (input_name == print )
          {
           cout << input_name << " was found ";
           return 0 ;
          }
       }
          cout << input_name << " Not found " ;
      
       return 0 ;
       }
    what do you think about my code ?
    i'm sorry i dont know how to use syntax highlighter

  • thang

    Alex, can you write a code illustrate  that for-each loop can work with structure.  Thank you

    • Alex

      I'm not sure I understand what you're asking. Are you asking if a for-each loop can step through each member of a struct? If so, the answer is no.

  • Saiteja Muppavarapu

    Hello,
    As has been said in the lesson on reference variables, a reference once initialised cannot be reassigned or redirected to reference another variable. Then, how do for each loops work when you use a reference to iterate through an array?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]