Skip to content
C++ Better Explained
Go back
How to Break Out of a Nested Loop in C++

How to Break Out of a Nested Loop in C++

Short answer: break only exits the innermost loop. To leave both, put the loops in a function and return, or use a flag, or goto a label after the loops.

C++ has no labelled break — that’s a Java and JavaScript feature.


The Problem

#include <iostream>

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

    for (int r = 0; r < 3; ++r) {
        for (int c = 0; c < 3; ++c) {
            if (grid[r][c] == 5) {
                std::cout << "Found at " << r << "," << c << '\n';
                break;                  // only leaves the INNER loop
            }
        }
        // execution lands here, then the outer loop keeps going
    }
}

The break ends the c loop. The r loop carries on to the next row. If you wanted to stop searching entirely, this doesn’t do it.

Option 1: Extract a Function and return (cleanest)

#include <iostream>
#include <utility>

std::pair<int,int> findValue(int grid[3][3], int target) {
    for (int r = 0; r < 3; ++r) {
        for (int c = 0; c < 3; ++c) {
            if (grid[r][c] == target) {
                return {r, c};          // leaves both loops at once
            }
        }
    }
    return {-1, -1};                    // not found
}

int main() {
    int grid[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    auto [row, col] = findValue(grid, 5);

    if (row != -1) std::cout << "Found at " << row << "," << col << '\n';
    else           std::cout << "Not found\n";
}

return leaves every loop in the function, however deep. This is usually the right answer: searching is its own job, so it deserves its own function, and the code reads better afterwards.

Learning C++ properly? The C++ Better Explained Ebook covers loops, functions and control flow in plain English — 87 pages, just $19.

Option 2: A Flag

bool found = false;

for (int r = 0; r < 3 && !found; ++r) {
    for (int c = 0; c < 3; ++c) {
        if (grid[r][c] == 5) {
            std::cout << "Found at " << r << "," << c << '\n';
            found = true;
            break;                      // leave inner loop
        }
    }
}

The outer loop’s condition now checks !found, so once the flag flips the outer loop stops too.

It works, but it costs you a variable and two extra places to look when reading the code. With three levels of nesting it gets genuinely ugly.

Option 3: goto

for (int r = 0; r < 3; ++r) {
    for (int c = 0; c < 3; ++c) {
        if (grid[r][c] == 5) {
            std::cout << "Found at " << r << "," << c << '\n';
            goto done;
        }
    }
}
done:
std::cout << "Search finished\n";

Yes, goto. Breaking out of nested loops is the one case where it’s widely accepted — it appears in the Linux kernel, and several major C++ style guides permit it here specifically.

Two conditions make it safe: the jump goes forward, and the label sits immediately after the loops. Jumping backwards or into a block is where goto earns its reputation.

Option 4: Restructure So You Don’t Need To

Often the nesting isn’t necessary. A single loop over a flattened index:

for (int i = 0; i < 9; ++i) {
    int r = i / 3, c = i % 3;
    if (grid[r][c] == 5) {
        std::cout << "Found at " << r << "," << c << '\n';
        break;                          // one loop, one break
    }
}

Or let the standard library do the searching:

#include <algorithm>
#include <vector>

std::vector<std::vector<int>> grid = {{1,2,3},{4,5,6},{7,8,9}};

for (const auto& row : grid) {
    auto it = std::find(row.begin(), row.end(), 5);
    if (it != row.end()) {
        std::cout << "Found\n";
        break;                          // only one loop to leave
    }
}

When you reach for a flag or a goto, it’s worth a moment’s thought about whether the loop structure itself is the problem. See std::find in C++.

What About continue?

continue has the same scope rule — it skips to the next iteration of the innermost loop only:

for (int r = 0; r < 3; ++r) {
    for (int c = 0; c < 3; ++c) {
        if (grid[r][c] % 2 == 0) continue;   // next c, not next r
        std::cout << grid[r][c] << ' ';
    }
}

To skip to the next outer iteration, break out of the inner loop instead — that lands you at the end of the outer body, which is the same thing.

Quick Reference

ApproachWhen to use
Extract function + returnDefault choice — clearest, works at any depth
Boolean flagTwo levels, when a function feels heavy
goto forward labelDeep nesting where a flag gets noisy
Flatten to one loopWhen the nesting was incidental
std::find / algorithmsWhen you are really just searching
Labelled breakNot available in C++

Take Your C++ Further

If you want loops, functions and control flow explained properly rather than pieced together, the C++ Better Explained Ebook covers it in plain English. Just $19.

👉 Get the C++ Better Explained Ebook — $19


📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Next Post
Getters and Setters in C++: How and When to Use Them

Keep Learning