Dapatkah loop 'for' di dalam loop 'for' menggunakan nama variabel counter yang sama?

107

Dapatkah saya menggunakan variabel penghitung yang sama untuk forperulangan di dalam forperulangan?

Atau akankah variabel mempengaruhi satu sama lain? Haruskah kode berikut menggunakan variabel yang berbeda untuk loop kedua, seperti j, or is ifine?

for(int i = 0; i < 10; i++)
{
  for(int i = 0; i < 10; i++)
  {
  }
}
Uclydde
sumber
72
Ini membingungkan - tidak akan melewati saya dalam peninjauan kode. Tapi itu sah. Ada dua variabel berbeda yang disebut keduanya i, dengan cakupan berbeda. Gunakan -Wshadowdengan GCC agar masalah seperti itu dilaporkan secara otomatis.
Jonathan Leffler
15
Saya terkejut itu -Wshadowtidak termasuk dalam -Wall.
kiri sekitar
5
@leftaroundabout juga -Wshadowmemperingatkan tentang membayangi variabel global, yang dapat dengan mudah mengganggu dalam proyek yang lebih besar.
Kubik
9
@leftaroundabout bahkan lebih mengejutkan, bahkan -Wextratidak termasuk -Wshadow. Saya kira itu cukup umum di beberapa proyek, atau beberapa pengembang gcc suka membayangi sebagai gaya pengkodean, untuk menjamin ditinggalkan seperti ini.
hyde
5
@leftaroundabout Menggema apa yang dikatakan Cubic, -Wshadowmemiliki tingkat positif palsu yang menghebohkan, membuatnya sama sekali tidak berguna. Cakupan ada karena suatu alasan, dan shadowing secara apriori tidak bermasalah. Sekarang -Wshadow-local(catatan: tidak -Wshadow=local ) sangat berbeda. Namun sayangnya GCC sejauh ini menolak untuk memasukkannya ke dalam trunk (meskipun tampaknya ada garpu GCC yang menyertakannya).
Konrad Rudolph

Jawaban:

140

Anda dapat menggunakan nama yang sama (pengenal). Ini akan menjadi objek yang berbeda. Mereka tidak akan saling mempengaruhi. Di dalam loop dalam, tidak ada cara untuk merujuk ke objek yang digunakan di loop luar (kecuali Anda membuat ketentuan khusus untuk itu, seperti dengan memberikan pointer ke objek tersebut).

Ini umumnya gaya yang buruk, cenderung membingungkan, dan harus dihindari.

Objek akan berbeda hanya jika bagian dalam ditentukan secara terpisah, seperti yang int itelah Anda tunjukkan. Jika nama yang sama digunakan tanpa mendefinisikan objek baru, loop akan menggunakan objek yang sama dan akan saling mengganggu.

Eric Postpischil
sumber
3
menggunakan for (i) dan for (j) nested, dan inside i ++, akan meningkatkan variabel loop luar. Namun apa yang Anda katakan benar jika Anda menggunakan pengenal yang sama di kedua loop, karena keduanya adalah variabel dengan cakupan yang berbeda.
KYL3R
3
@BloodGain: "Objek" adalah istilah teknis yang digunakan dalam standar C. Saya sengaja menggunakannya di sini.
Eric Postpischil
1
@EricPostpischil: Ah, begitu, ya. Saya tidak mengetahui definisi itu dalam standar, dan takut itu akan menyesatkan bagi pemrogram baru (karena ini jelas merupakan pertanyaan pemula), karena C tidak memiliki "objek" dalam arti yang biasanya kita gunakan istilah tersebut. Saya melihatnya di standar C11, dan sekarang saya penasaran apakah itu didefinisikan seperti itu sebelum C11.
Bloodgain
1
Dulu. Ini 3,14 dalam standar C99, bukan 3,15. Jadi tidak ada alasan dari pihak saya. Itu akan mengajari saya untuk menanyai Anda <: - |
Bloodgain
1
Secara lebih umum: tidak ada yang mencegah Anda menggunakan kembali nama variabel dalam cakupan bersarang apa pun. Kecuali, tentu saja, ketakutan akan Hukuman Tuhan karena menulis kode yang membingungkan.
Isaac Rabinovitch
56

Pertama, ini benar-benar legal: kode akan mengkompilasi dan menjalankan, mengulangi isi loop bersarang 10 × 10 = 100 kali. Penghitung loop idi dalam loop bersarang akan menyembunyikan penghitung dari loop luar, sehingga dua penghitung akan bertambah secara independen satu sama lain.

Sejak luar i tersembunyi, kode di dalam badan loop bersarang hanya akan memiliki akses ke nilai dari iloop bersarang, bukan idari loop luar. Dalam situasi ketika loop bersarang tidak membutuhkan akses ke luar, ikode seperti itu bisa dibenarkan dengan sempurna. Namun, hal ini kemungkinan akan membuat lebih banyak kebingungan pada pembacanya, jadi sebaiknya hindari menulis kode seperti itu untuk menghindari "kewajiban pemeliharaan".

Catatan: Meskipun variabel penghitung dari kedua loop memiliki pengenal yang samai , keduanya tetap merupakan dua variabel independen, yaitu Anda tidak menggunakan variabel yang sama di kedua loop. Menggunakan variabel yang sama di kedua loop juga dimungkinkan, tetapi kodenya akan sulit dibaca. Berikut ini contohnya:

for (int i = 1 ; i < 100 ; i++) {
    for ( ; i % 10 != 0 ; i++) {
        printf("%02d ", i);
    }
    printf("%d\n", i);
}

Sekarang kedua loop menggunakan variabel yang sama. Namun, dibutuhkan beberapa saat untuk mengetahui apa yang dilakukan kode ini tanpa mengkompilasinya ( demo );

dasblinkenlight
sumber
4
Karena pertanyaannya diutarakan sebagai "menggunakan variabel penghitung yang sama", saya juga ingin menunjukkan bahwa bayangan hanya terjadi ketika definisi ulang terjadi. Menghilangkan intloop for dalam, yaitu sebenarnya menggunakan variabel counter yang sama, akan menyebabkan loop luar hanya berjalan sekali, karena loop dalam akan keluar i == 10. Ini sepele, tetapi berpikir itu memberikan klarifikasi mengingat bagaimana pertanyaan itu dinyatakan
Easton Bornemeier
@EastonBornemeier Anda benar, saya pikir saya harus membahas masalah "variabel yang sama" di tubuh jawabannya. Terima kasih!
dasblinkenlight
@EricPostpischil "Variable shadowing" adalah istilah resmi, lengkap dengan halamannya sendiri di wikipedia . Saya telah memperbarui jawabannya agar konsisten dengan kata-kata standar. Terima kasih!
dasblinkenlight
2
@dasblinkenlight: Sebenarnya, saya mengalami kejang otak tentang arah, dan nama bagian dalam membayangi nama luar. Komentar saya sebelumnya salah dalam hal itu. Permintaan maaf saya. (Namun, itu dalam arti bahasa Inggris, bukan dalam arti resmi — Wikipedia bukanlah publikasi resmi untuk C atau pemrograman secara umum, dan saya tidak mengetahui kantor atau badan otoritatif mana pun yang mendefinisikan istilah tersebut.) Standar C menggunakan "Sembunyikan", jadi itu lebih disukai.
Eric Postpischil
Bagus, terutama dengan contoh "variabel yang sama". Namun, menurut saya " kode akan dikompilasi dan berjalan seperti yang diharapkan " akan lebih baik karena "kode akan dikompilasi dan dijalankan sebagai seseorang yang telah membacanya dengan cermat dan memahami semua konsekuensi yang diharapkan" ... seperti yang Anda katakan, kode seperti ini " mungkin akan membuat lebih banyak kebingungan dalam pembacanya "dan masalahnya adalah pembaca yang bingung mungkin mengharapkan sesuatu selain dari apa yang dilakukannya.
TripeHound
26

Kamu bisa. Tetapi Anda harus menyadari ruang lingkup is. jika kita menyebut outer iwith i_1dan inner iwith i_2, maka cakupan is adalah sebagai berikut:

for(int i = 0; i < 10; i++)
{
     // i means i_1
     for(int i = 0; i < 10; i++)
     {
        // i means i_2
     }
     // i means i_1
}

Anda harus memperhatikan bahwa mereka tidak mempengaruhi satu sama lain, dan hanya ruang lingkup definisinya yang berbeda.

Oh Tuhan
sumber
17

Itu sepenuhnya mungkin tetapi perlu diingat, Anda tidak akan dapat menangani yang pertama dinyatakan i

for(int i = 0; i < 10; i++)//I MEAN THE ONE HERE
{

  for(int i = 0; i < 10; i++)
    {

    }
}

di loop kedua dalam loop anak kedua

for(int i = 0; i < 10; i++)
{

  for(int i = 0; i < 10; i++)//the new i
    {
        // i cant see the i thats before this new i here
    }
}

jika Anda perlu menyesuaikan atau mendapatkan nilai i pertama, gunakan j di loop kedua

for(int i = 0; i < 10; i++)
{

  for(int j = 0; j < 10; j++)
    {

    }
}

dan jika Anda cukup kreatif, Anda dapat melakukan keduanya dalam satu putaran

for(int i ,j= 0; i < 10; (j>9) ? (i++,j=0) : 0 ,j++)
{
    printf("%d %d\n",i,j);
}
Dodo
sumber
6
Jika saya menangkap variabel i yang dibayangi dalam loop bersarang selama peninjauan kode, saya akan melihatnya sebagai peluang pelatihan. Jika saya melihat seseorang mengaburkan loop dalam seperti contoh terakhir Anda (itu BUKAN satu loop), saya mungkin akan membuangnya ke luar jendela.
Bloodgain
itu adalah satu loop, itu hanya memiliki satu untuk loop, jika itu 2 itu akan memiliki dua untuk kata kunci atau dua sementara kata kunci atau untuk dan sementara kata kunci
Dodo
3
Itulah mengapa saya mengatakan Anda mengaburkan loop. Anda masih mengulang, Anda baru saja menyembunyikannya dengan sintaks yang kurang jelas. Dan itu lebih buruk dalam segala hal.
Bloodgain
12

Ya, Anda dapat menggunakan nama variabel penghitung yang sama untuk forloop dalam seperti untuk forloop luar .

Dari for loop :

for ( init_clause ; cond_expression ; iteration_expression ) loop_statement
Pernyataan ekspresi digunakan sebagai loop_statement menetapkan sendiri lingkup blok, berbeda dari ruang lingkup dari init_clause .

for (int i = 0; ; ) {
    long i = 1;   // valid C, invalid C++
    // ...
}  

Ruang lingkup loop_statement adalah bersarang dalam lingkup init_clause .

Dari C Standards # 6.8.5p5 Pernyataan Iterasi [penekanan saya]

Pernyataan iterasi adalah blok yang cakupannya merupakan subset ketat dari cakupan blok yang melingkupinya. Badan perulangan juga merupakan blok yang cakupannya merupakan subset ketat dari cakupan pernyataan iterasi .

Dari C Standards # 6.2.1p4 Cakupan pengidentifikasi [penekanan saya]

.... Dalam lingkup dalam, pengidentifikasi menunjuk entitas yang dideklarasikan dalam lingkup dalam; yang entitas dideklarasikan pada lingkup luar tersembunyi (dan tidak terlihat) dalam lingkup batin.

HS
sumber
10

Dari perspektif kode / kompiler, ini akan menjadi hal yang sah dan sah untuk dilakukan. The int idinyatakan dalam batin for(int i = 0; i < 10; i++)loop dalam lingkup baru dan lebih kecil, sehingga deklarasi bayangan deklarasi int idi lingkaran luar (atau, dengan kata lain: Dalam lingkup batin semua akses ke variabel ipergi ke int idideklarasikan dalam lingkup batin, meninggalkanint i di lingkup luar tidak tersentuh).

Yang mengatakan, dari perspektif kualitas kode ini benar-benar mengerikan. Sulit dibaca, sulit dipahami, dan mudah salah paham. Jangan lakukan itu.

CharonX
sumber
8

Ya, Anda dapat menggunakannya tetapi cukup membingungkan. Yang terpenting adalah ruang lingkup variabel lokal di dalam loop. Sejauh variabel dideklarasikan di dalam suatu fungsi, ruang lingkup variabel itu adalah fungsi itu.

int a = 5;
// scope of a that has value 5
int func(){
    int a = 10;
   // scope of a that has value 10
}
// scope of a that has value 5

Demikian pula halnya dengan loop, variabel yang dideklarasikan di dalam loop dalam memiliki cakupan yang berbeda dan variabel yang dideklarasikan loop luar memiliki cakupan yang berbeda.

for(int i = 0; i < 10; i++){
    // In first iteration, value of i is 0

    for(int i = 1; i < 10; i++){
        // In first iteration, value of i is 1
    }
    // In first iteration, value of i is 0
}

Pendekatan yang lebih baik adalah dengan menggunakan variabel yang berbeda untuk loop dalam dan luar.

for(int i = 0; i < 10; i++){

    for(int j = 1; j < 10; j++){

    }

}
Safwan Shaikh
sumber
8

Ya pasti Anda bisa menggunakan variabel nama yang sama.

Variabel pemrograman C dapat dideklarasikan di tiga tempat:
variabel lokal: -Di dalam fungsi atau blok.
Variabel global: -Keluar dari semua fungsi.
Parameter formal: -Dalam parameter fungsi.

Tetapi dalam kasus Anda i scopeharus memikirkan hal-hal di bawah ini

for(int i = 0; i < 10; i++)
{
     // i means 1st for loop variable
     for(int i = 0; i < 10; i++)
     {
        // but here i means 2nd for loop  variable
     }
     //interesting thing here i means 1st for loop variable
}

Catatan: Ini akan menjadi praktik terbaik untuk menggunakan variabel yang berbeda untuk loop dalam dan luar

Zaynul Abadin Tuhin
sumber
6

Ya - dan yang lebih menarik lagi, Anda dapat menggunakan kembali nama variabel setiap kali Anda membuka satu set tanda kurung. Ini sering kali berguna saat memasukkan kode diagnostik. Ketik tanda kurung kurawal buka '{' diikuti dengan deklarasi dan penggunaan variabel, kemudian tutup kurung kurawal dan variabel-variabel tersebut akan hilang. Ini menjamin bahwa Anda tidak akan mengganggu apa pun di badan utama sambil tetap mempertahankan keuntungan dari variabel, kelas, dan metode apa pun yang dideklarasikan di luar kurung kurawal.

SuwaneeCreek
sumber
3

Aturan Lingkup: Variabel yang dideklarasikan dalam pernyataan for hanya dapat digunakan dalam pernyataan itu dan badan perulangan.

Jika dalam kode Anda, Anda telah menentukan beberapa instance i di loop dalam, setiap instance akan menempati ruang memorinya sendiri. Jadi tidak ada yang perlu dikhawatirkan hasilnya akan sama.

int main(void) {

    int i = 2; //defined with file global scope outside of a function and will remain 2
    if(1)
    {       //new scope, variables created here with same name are different
        int i = 5;//will remain == 5
        for(int i = 0; i < 10; i++)
        {   //new scope for "i"

            printf("i value in first loop: %d \n", i); // Will print 0 in first iteration
            for(int i = 8; i < 15; i++) 
            {   //new scope again for "i", variable with same name is not the same
                printf("i value in nested loop: %d \n", i); // Will print 8 in first iteration
            }
        }

    }

    return 0;
}

Tetapi tidak disarankan untuk menggunakan nama variabel yang sama karena sulit untuk dipahami dan nantinya menjadi kode yang tidak dapat dipelihara.

Subash J
sumber
1

Bagian penting adalah berisi parameter loop dalam int i. Karena ididefinisikan ulang dengan cara ini, kedua variabel tidak saling mempengaruhi; cakupan mereka berbeda. Berikut dua contoh untuk menunjukkannya:

for(int i = 0; i < 10; i++) // This code will print "Test" 100 times
{
 for(int i = 0; i < 10; i++)
 {
  puts("Test");
 }
}

Perhatikan bahwa kode di atas termasuk int idalam parameter loop dalam, dan kode di bawah ini hanya menyertakan i.

for(int i = 0; i < 10; i++) // This code will print "Test" 10 times
{
 for(i = 0; i < 10; i++)
 {
  puts("Test");
 }
}
Uclydde
sumber
0

Nah, Anda dapat melakukan ini tanpa skrip Anda mengalami masalah, tetapi Anda harus menghindari struktur itu. Ini biasanya menyebabkan kebingungan

Api unggun
sumber