Kesalahan: Lompat ke label kasus


229

Saya menulis sebuah program yang melibatkan penggunaan pernyataan switch ... Namun pada kompilasi itu menunjukkan:

Kesalahan: Lompat ke label kasus.

Kenapa bisa begitu?

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>

using namespace std;

class contact
{
public:
    string name;
    int phonenumber;
    string address;
    contact() {
        name= "Noname";
        phonenumber= 0;
        address= "Noaddress";
    }
};

int main() {
    contact *d;
    d = new contact[200];
    string name,add;
    int choice,modchoice,t;//Variable for switch statement
    int phno,phno1;
    int i=0;
    int initsize=0, i1=0;//i is declared as a static int variable
    bool flag=false,flag_no_blank=false;

    //TAKE DATA FROM FILES.....
    //We create 3 files names, phone numbers, Address and then abstract the data from these files first!
    fstream f1;
    fstream f2;
    fstream f3;
    string file_input_name;
    string file_input_address;
    int file_input_number;

    f1.open("./names");
    while(f1>>file_input_name){
        d[i].name=file_input_name;
        i++;
    }
    initsize=i;

    f2.open("./numbers");
    while(f2>>file_input_number){
        d[i1].phonenumber=file_input_number;
        i1++;
    }
    i1=0;

    f3.open("./address");
    while(f3>>file_input_address){
        d[i1].address=file_input_address;
        i1++;
    }

    cout<<"\tWelcome to the phone Directory\n";//Welcome Message
    do{
        //do-While Loop Starts
        cout<<"Select :\n1.Add New Contact\n2.Update Existing Contact\n3.Display All Contacts\n4.Search for a Contact\n5.Delete a  Contact\n6.Exit PhoneBook\n\n\n";//Display all options
        cin>>choice;//Input Choice from user

        switch(choice){//Switch Loop Starts
        case 1:
            i++;//increment i so that values are now taken from the program and stored as different variables
            i1++;
            do{
                cout<<"\nEnter The Name\n";
                cin>>name;
                if(name==" "){cout<<"Blank Entries are not allowed";
                flag_no_blank=true;
                }
            }while(flag_no_blank==true);
            flag_no_blank=false;
            d[i].name=name;
            cout<<"\nEnter the Phone Number\n";
            cin>>phno;
            d[i1].phonenumber=phno;
            cout<<"\nEnter the address\n";
            cin>>add;
            d[i1].address=add;
            i1++;
            i++;
            break;//Exit Case 1 to the main menu
        case 2:
            cout<<"\nEnter the name\n";//Here it is assumed that no two contacts can have same contact number or address but may have the same name.
            cin>>name;
            int k=0,val;
            cout<<"\n\nSearching.........\n\n";
            for(int j=0;j<=i;j++){
                if(d[j].name==name){
                    k++;
                    cout<<k<<".\t"<<d[j].name<<"\t"<<d[j].phonenumber<<"\t"<<d[j].address<<"\n\n";
                    val=j;
                }
            }
            char ch;
            cout<<"\nTotal of "<<k<<" Entries were found....Do you wish to edit?\n";
            string staticname;
            staticname=d[val].name;
            cin>>ch;
            if(ch=='y'|| ch=='Y'){
                cout<<"Which entry do you wish to modify ?(enter the old telephone number)\n";
                cin>>phno;
                for(int j=0;j<=i;j++){
                    if(d[j].phonenumber==phno && staticname==d[j].name){
                        cout<<"Do you wish to change the name?\n";
                        cin>>ch;
                        if(ch=='y'||ch=='Y'){
                            cout<<"Enter new name\n";
                            cin>>name;
                            d[j].name=name;
                        }
                        cout<<"Do you wish to change the number?\n";
                        cin>>ch;
                        if(ch=='y'||ch=='Y'){
                            cout<<"Enter the new number\n";
                            cin>>phno1;
                            d[j].phonenumber=phno1;
                        }
                        cout<<"Do you wish to change the address?\n";
                        cin>>ch;
                        if(ch=='y'||ch=='Y'){
                            cout<<"Enter the new address\n";
                            cin>>add;
                            d[j].address=add;
                        }
                    }
                }
            }
            break;
        case 3 : {
            cout<<"\n\tContents of PhoneBook:\n\n\tNames\tPhone-Numbers\tAddresses";
            for(int t=0;t<=i;t++){
                cout<<t+1<<".\t"<<d[t].name<<"\t"<<d[t].phonenumber<<"\t"<<d[t].address;
            }
            break;
                 }
        }
    }
    while(flag==false);
    return 0;
}

1
Kode apa yang Anda coba kompilasi? Kompiler apa yang Anda gunakan? Sudahkah Anda menutup setiap caseblok di kawat gigi?
Cody Grey

2
itu salah satu pesan kesalahan bundaran yang mengesankan
jozxyqk

Jawaban:


437

Masalahnya adalah bahwa variabel yang dideklarasikan dalam satu casemasih terlihat di cases berikutnya kecuali jika { }blok eksplisit digunakan, tetapi mereka tidak akan diinisialisasi karena kode inisialisasi milik yang lain case.

Dalam kode berikut, jika foosama dengan 1, semuanya baik-baik saja, tetapi jika sama dengan 2, kita akan secara tidak sengaja menggunakan ivariabel yang ada tetapi mungkin mengandung sampah.

switch(foo) {
  case 1:
    int i = 42; // i exists all the way to the end of the switch
    dostuff(i);
    break;
  case 2:
    dostuff(i*2); // i is *also* in scope here, but is not initialized!
}

Membungkus kasing dalam blok eksplisit memecahkan masalah:

switch(foo) {
  case 1:
    {
        int i = 42; // i only exists within the { }
        dostuff(i);
        break;
    }
  case 2:
    dostuff(123); // Now you cannot use i accidentally
}

Edit

Lebih jauh, switchpernyataan hanya merupakan jenis yang sangat mewah goto. Berikut adalah sepotong kode analog yang menunjukkan masalah yang sama tetapi menggunakan gotobukan switch:

int main() {
    if(rand() % 2) // Toss a coin
        goto end;

    int i = 42;

  end:
    // We either skipped the declaration of i or not,
    // but either way the variable i exists here, because
    // variable scopes are resolved at compile time.
    // Whether the *initialization* code was run, though,
    // depends on whether rand returned 0 or 1.
    std::cout << i;
}

1
Lihat laporan bug LLVM yang telah diperbaiki ini untuk penjelasan lainnya: llvm.org/bugs/show_bug.cgi?id=7789
Francesco

70

Deklarasi variabel baru dalam pernyataan kasus adalah apa yang menyebabkan masalah. Menutup semua casepernyataan dalam {}akan membatasi ruang lingkup variabel yang baru dideklarasikan pada kasus yang sedang dieksekusi yang memecahkan masalah.

switch(choice)
{
    case 1: {
       // .......
    }break;
    case 2: {
       // .......
    }break;
    case 3: {
       // .......
    }break;
}    

instruksi perbaikan bersih
yc_yuy

Apakah akan ada masalah jika saya menempatkan pernyataan break di dalam kurung kurawal?
Vishal Sharma

10

Standar C ++ 11 untuk melompati beberapa inisialisasi

JohannesD memberikan penjelasan, sekarang untuk standar.

The C ++ 11 N3337 standar rancangan 6,7 "pernyataan Deklarasi" mengatakan:

3 Dimungkinkan untuk mentransfer ke dalam blok, tetapi tidak dengan cara yang melewati deklarasi dengan inisialisasi. Sebuah program yang melompat (87) dari titik di mana variabel dengan durasi penyimpanan otomatis tidak dalam ruang lingkup ke titik di mana ruang lingkupnya tidak terbentuk kecuali variabel tersebut memiliki tipe skalar, tipe kelas dengan konstruktor default sepele dan sepele destructor, versi cv-kualifikasi dari salah satu jenis ini, atau array dari salah satu jenis sebelumnya dan dideklarasikan tanpa penginisialisasi (8.5).

87) Transfer dari kondisi pernyataan beralih ke label kasus dianggap lompatan dalam hal ini.

[Contoh:

void f() {
   // ...
  goto lx;    // ill-formed: jump into scope of a
  // ...
ly:
  X a = 1;
  // ...
lx:
  goto ly;    // OK, jump implies destructor
              // call for a followed by construction
              // again immediately following label ly
}

- contoh akhir]

Pada GCC 5.2, pesan kesalahan sekarang mengatakan:

melintasi inisialisasi

C

C memungkinkan: c99 melewati inisialisasi

The C99 N1256 standar rancangan Annex I "peringatan umum" mengatakan:

2 Blok dengan inisialisasi objek yang memiliki durasi penyimpanan otomatis dilompati


6

Jawaban JohannesD benar, tetapi saya merasa itu tidak sepenuhnya jelas pada aspek masalah.

Contoh yang dia berikan menyatakan dan menginisialisasi variabel idalam kasus 1, dan kemudian mencoba menggunakannya dalam kasus 2. Argumennya adalah bahwa jika saklar langsung ke kasus 2, iakan digunakan tanpa diinisialisasi, dan inilah mengapa ada kompilasi kesalahan. Pada titik ini, orang bisa berpikir bahwa tidak akan ada masalah jika variabel yang dinyatakan dalam suatu kasus tidak pernah digunakan dalam kasus lain. Sebagai contoh:

switch(choice) {
    case 1:
        int i = 10; // i is never used outside of this case
        printf("i = %d\n", i);
        break;
    case 2:
        int j = 20; // j is never used outside of this case
        printf("j = %d\n", j);
        break;
}

Orang bisa mengharapkan program ini untuk dikompilasi, karena keduanya idan jhanya digunakan di dalam kasus yang menyatakannya. Sayangnya, dalam C ++ ini tidak dapat dikompilasi: seperti yang dijelaskan Ciro Santilli 包子 露 宪 六四 事件 , kami tidak dapat langsung melompat case 2:, karena ini akan melewatkan deklarasi dengan inisialisasi i, dan meskipun case 2tidak digunakan isama sekali, ini masih dilarang di C ++.

Menariknya, dengan beberapa penyesuaian (a #ifdefke #includeheader yang sesuai, dan titik koma setelah label, karena label hanya dapat diikuti oleh pernyataan, dan deklarasi tidak dihitung sebagai pernyataan dalam C ), program ini dikompilasi sebagai C:

// Disable warning issued by MSVC about scanf being deprecated
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#ifdef __cplusplus
#include <cstdio>
#else
#include <stdio.h>
#endif

int main() {

    int choice;
    printf("Please enter 1 or 2: ");
    scanf("%d", &choice);

    switch(choice) {
        case 1:
            ;
            int i = 10; // i is never used outside of this case
            printf("i = %d\n", i);
            break;
        case 2:
            ;
            int j = 20; // j is never used outside of this case
            printf("j = %d\n", j);
            break;
    }
}

Berkat kompiler online seperti http://rextester.com Anda dapat dengan cepat mencoba mengkompilasinya sebagai C atau C ++, menggunakan MSVC, GCC atau Dentang. Karena C selalu berfungsi (hanya ingat untuk mengatur STDIN!), Karena C ++ tidak ada kompiler yang menerimanya.

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.