Bagaimana cara keluar dari loop bersarang?


96

Jika saya menggunakan breakpernyataan, itu hanya akan merusak loop dalam dan saya perlu menggunakan beberapa bendera untuk memutus loop luar. Tetapi jika ada banyak loop bersarang, kode tidak akan terlihat bagus.

Apakah ada cara lain untuk memutuskan semua loop? (Tolong jangan gunakan goto stmt.)

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // both of the loops need to break and control will go to stmt2
       }
   }

}

stmt2

2
Anda dapat mencoba int i dan int j sebelum loop dimulai dan kemudian dengan syarat membuat mereka 1001 loop tidak akan mengulang berikutnya.
Khurram Ijaz

Jawaban:


43

Menggunakan:

if (condition) {
    i = j = 1000;
    break;
}

49
Bekerja, tapi jelek dan tidak umum. Bagaimana jika seseorang mengubah limit menjadi 2000 (misalkan kodenya lebih panjang, jadi Anda tidak langsung menyadarinya)?
ugoren

1
@ugoren Ini juga sangat sederhana. bagaimana jika Anda menggunakan const int count =1000 , dalam Inisialisasi global. atau sebagai #definemakro.
Laksith

4
Seperti yang ditunjukkan @ugoren, ini bukan solusi umum. Karena ini adalah hit Google pertama untuk pertanyaan ini, alangkah baiknya jika solusi umum telah dipilih. Yah, orang-orang terbiasa memeriksa # 2.
BeeOnRope

1
Saya kira hanya perlu i = 1000?
Peter Wu

189

Tidak, jangan merusak kesenangan dengan break. Ini adalah sisa penggunaan sah yang terakhir dari goto;)

Jika tidak demikian, Anda dapat menggunakan flag untuk keluar dari loop bersarang yang dalam.

Pendekatan lain untuk keluar dari loop bersarang adalah dengan memfaktorkan kedua loop menjadi fungsi terpisah, dan kembali dari fungsi tersebut saat Anda ingin keluar.

Diringkas - untuk keluar dari loop bersarang:

  1. menggunakan goto
  2. gunakan bendera
  3. faktor out loop menjadi panggilan fungsi terpisah

Tidak bisa menahan termasuk xkcd di sini :)

masukkan deskripsi gambar di sini

sumber

Goto dianggap berbahaya tetapi seperti yang disarankan oleh banyak orang di komentar, itu tidak perlu. Jika digunakan dengan bijaksana, ini bisa menjadi alat yang hebat. Apa pun yang digunakan secukupnya itu menyenangkan.


29
Goto sejelas Anda akan sampai di sini, ya. Menetapkan variabel keluar ke 1000 bahkan lebih rumit.
correnos

3
Saya ingin menambahkan bahwa gotos tidak secara eksplisit jahat, mereka hanya dapat digunakan untuk kejahatan. Saya menemukan bahwa ada cukup banyak kasus, misalnya ini, di mana mereka adalah solusi terbaik. "Jangan gunakan gotos" adalah awal yang baik, tapi menurut saya langkah keterampilan berikutnya memungkinkan Anda "Jangan gunakan gotos jarak jauh".
Tonton

1
Saya tidak setuju dengan ini: "Membuat fungsi menghasilkan jumlah eksponensial dengan menambahkan / mengurangi stack pointer". Jika ada fungsi lokal (statis) yang dipanggil hanya pada satu titik dalam alur program, kompiler setengah layak apapun akan menyebariskannya, dan kode yang dihasilkan pada dasarnya sama dengan goto. Ini mungkin kasus pengoptimalan termudah untuk semua kompiler.
DrV

1
Refactoring biasanya merupakan solusi terbersih. Namun, jika variabel di luar loop diubah selama loop dalam, semuanya menjadi rumit. Salah satu kemungkinannya adalah meneruskan variabel ke fungsi bagian dalam dengan referensi (penunjuk), tetapi ini dapat membingungkan pengoptimalan compiler dan menghasilkan kode tambahan yang tidak perlu. Kemungkinan lain adalah membuat variabel seperti itu statis pada level modul, tetapi itu juga tidak terlalu bagus. Sayangnya C tidak memiliki fungsi bertingkat, karena mereka akan menyelesaikan masalah ini - kecuali jika Anda ingin mengikat diri Anda sendiri menggunakan gcc yang menyediakan ekstensi.
DrV

1
+1. Dan Pemrograman Terstruktur Donald E. Knuth dengan pergi ke Statements ( wiki.c2.com/?StructuredProgrammingWithGoToStatements ) adalah artikel yang menarik untuk menyeimbangkan Dijkstra.
kmkaplan

40
bool stop = false;
for (int i = 0; (i < 1000) && !stop; i++)
{
    for (int j = 0; (j < 1000) && !stop; j++)
    {
        if (condition)
            stop = true;
    }
}

Solusi masih menambah kedua variabel satu per satu saat istirahat yang dapat menyebabkan masalah
TheSola10

7
Seseorang dapat mengatur "stop = true;" dan kemudian "istirahat;". Kemudian, tepat setelah akhir loop "for", lakukan "if (stop) break;".
Jeff Grigg

34

Salah satu caranya adalah dengan menempatkan semua loop bersarang ke dalam suatu fungsi dan kembali dari loop paling dalam jika perlu keluar dari semua loop.

function() 
{    
  for(int i=0; i<1000; i++)
  {
   for(int j=0; j<1000;j++)
   {
      if (condition)
        return;
   }
  }    
}

1
tampaknya solusi terbaik untuk saya
Luca Steeb

20

Saya pikir gotoakan menyelesaikan masalah

for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; i++) {
        if (condition) {
            goto end;
        }
    }
}

end:
stmt2 

@chikuba Saya mendapat jawaban dari cprogramming.com/tutorial/goto.html dan jawaban Anda tidak diposting ketika saya melakukan hal yang sama itulah mengapa saya tidak melihat posting Anda
Renjith KN

15

Anda memerlukan variabel boolean, jika Anda ingin dapat dibaca:

bool broke = false;
for(int i = 0; i < 1000; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      broke = true;
      break;
    }
  }
  if (broke)
    break;
}

Jika Anda ingin membuatnya kurang mudah dibaca, Anda dapat mengikuti evaluasi boolean:

bool broke = false;
for(int i = 0; i < 1000 && !broke; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      broke = true;
      break;
    }
  }
}

Sebagai cara pamungkas Anda dapat membatalkan pengulangan awal:

for(int i = 0; i < size; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      i = size;
      break;
    }
  }
}


4

Perhatian: Jawaban ini menunjukkan konstruksi yang benar-benar tidak jelas.

Jika Anda menggunakan GCC, lihat pustaka ini . Seperti di PHP, breakdapat menerima jumlah loop bersarang yang ingin Anda keluar. Anda bisa menulis sesuatu seperti ini:

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // break two nested enclosing loops
            break(2);
       }
   }
}

Dan di bawah tenda itu memang menggunakangoto :)
jacobq

@ iX3 Saya dapat menggunakan assembler inline dan instruksi jmp jika itu membantu.
DaBler

@DaBler, saya tidak menyadari bahwa Anda adalah penulis perpustakaan itu. Komentar saya tidak dimaksudkan sebagai umpan balik melainkan mencatat bahwa pustaka ini menggunakan metode yang sama dengan jawaban yang diterima . Semoga komentar Anda dimaksudkan sebagai lelucon karena menurut saya menggunakan fitur bahasa (genap goto) jauh lebih disukai daripada inline asm (spesifik mesin, lebih mudah membuat kesalahan, lebih sulit dibaca, ...).
jacobq

3
for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; i++) {
       if(condition) {
            goto end;
   }
} 

end:

3

Jika Anda membutuhkan nilai i dan j, ini harus berfungsi tetapi dengan kinerja yang lebih rendah daripada yang lain

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition)
            break;
    }
    if(condition) //the same condition
        break;
}

Perhatikan bahwa jika kondisi bergantung pada jnilai kondisi perlu disimpan dengan beberapa cara agar ini tetap berfungsi.
SuperBiasedMan

1
Anda benar tetapi setelah istirahat , nilai j tidak berubah dan begitu juga nilai kondisinya.
Ali Eren Çelik

Ini adalah solusi yang rusak dan tidak valid secara umum. Entah j tidak didefinisikan di luar loopnya atau for (int i = 0; i < 1000; i++) { for (int j = 0; j < 1000; j++) { if (workComplete[i][j]) break; /* do work */ workComplete[i][j] = true; } if (workComplete[i][j]) break; ... }akan selalu keluar dari loop luar setelah iterasi pertama dari loop dalam.
Chai T.Rex

-3
int i = 0, j= 0;

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition){
            i = j = 1001;
            break;
        }
    }
}

Akan mematahkan kedua loop.


-3
for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; i++) {
       if(condition) {
          func(para1, para2...);
          return;
       }
    }
}

func(para1, para2...) {
    stmt2;
}

Jadi pada dasarnya Anda mengatakan bahwa itu harus (1) membuat banyak panggilan fungsi tambahan dan kemudian (2) berputar untuk sisa waktu ketika conditionmenjadi salah. Oh, dan loop kedua akan berjalan selamanya karena itu bertambah, ibukan j, ups ...
jacobq

-4
i = 0;

do
{
  for (int j = 0; j < 1000; j++) // by the way, your code uses i++ here!
  {
     if (condition)
     {
       break;
     }
  }

  ++i;

} while ((i < 1000) && !condition);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.