Errore: passa all'etichetta della custodia


229

Ho scritto un programma che prevede l'uso di istruzioni switch ... Comunque sulla compilazione mostra:

Errore: passa all'etichetta della custodia.

Perché lo fa?

#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
Quale codice stai cercando di compilare? Che compilatore stai usando? Hai racchiuso ogni caseblocco tra parentesi graffe?
Cody Grey

2
questo è un messaggio di errore incredibilmente rotonda
jozxyqk,

Risposte:


437

Il problema è che le variabili dichiarate in una casesono ancora visibili nelle successive casese non { }viene utilizzato un blocco esplicito , ma non verranno inizializzate perché il codice di inizializzazione appartiene a un altro case.

Nel codice seguente, se è foouguale a 1, tutto è ok, ma se è uguale a 2, utilizzeremo accidentalmente la ivariabile che esiste ma che probabilmente contiene immondizia.

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!
}

Avvolgere il caso in un blocco esplicito risolve il problema:

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
}

modificare

Per elaborare ulteriormente, le switchdichiarazioni sono solo un tipo particolarmente elaborato di a goto. Ecco un pezzo di codice analogo che mostra lo stesso problema ma che utilizza un gotoanziché un 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
Vedi questo bug report LLVM corretto per altre spiegazioni: llvm.org/bugs/show_bug.cgi?id=7789
Francesco

70

La dichiarazione di nuove variabili nelle dichiarazioni dei casi è ciò che causa problemi. Racchiudere tutte le caseistruzioni in {}limiterà l'ambito delle variabili appena dichiarate al caso attualmente in esecuzione che risolve il problema.

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

istruzioni di correzione più pulite
yc_yuy

Ci saranno problemi se inserisco la frase di interruzione tra parentesi graffe?
Vishal Sharma,

10

Standard C ++ 11 sul saltare alcune inizializzazioni

JohannesD ha dato una spiegazione, ora per gli standard.

La bozza standard C ++ 11 N3337 6.7 "Dichiarazione" afferma:

3 È possibile trasferire in un blocco, ma non in modo da bypassare le dichiarazioni con l'inizializzazione. Un programma che salta (87) da un punto in cui una variabile con durata di memorizzazione automatica non rientra nell'ambito in un punto in cui è nell'ambito è mal formato a meno che la variabile non abbia un tipo scalare, un tipo di classe con un costruttore predefinito banale e un oggetto banale distruttore, una versione qualificata cv di uno di questi tipi o una matrice di uno dei tipi precedenti ed è dichiarata senza un inizializzatore (8.5).

87) Il passaggio dalla condizione di un'istruzione switch a un'etichetta case è considerato un salto in questo senso.

[ Esempio:

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
}

- fine esempio]

A partire da GCC 5.2, il messaggio di errore ora dice:

attraversa l'inizializzazione di

C

C lo consente: c99 passa all'inizializzazione precedente

La bozza standard C99 N1256 dell'allegato I "Avvertenze comuni" recita:

2 Viene saltato un blocco con inizializzazione di un oggetto con durata di memorizzazione automatica


6

La risposta di JohannesD è corretta, ma ritengo che non sia del tutto chiaro su un aspetto del problema.

L'esempio che fornisce dichiara e inizializza la variabile inel caso 1, quindi cerca di usarla nel caso 2. Il suo argomento è che se lo switch passasse direttamente al caso 2, isarebbe usato senza essere inizializzato, ed è per questo che c'è una compilazione errore. A questo punto, si potrebbe pensare che non ci sarebbero problemi se le variabili dichiarate in un caso non fossero mai utilizzate in altri casi. Per esempio:

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;
}

Ci si potrebbe aspettare che questo programma venga compilato, poiché entrambi ie jvengono utilizzati solo all'interno dei casi che li dichiarano. Sfortunatamente, in C ++ non si compila: come ha spiegato Ciro Santilli simply 露 to 六四 事件 法轮功 , semplicemente non possiamo saltare case 2:, perché questo salterebbe la dichiarazione con l'inizializzazione di i, e anche se case 2non lo usa iaffatto, questo è ancora vietato in C ++.

È interessante notare, con alcune modifiche (una #ifdefper #includel'intestazione appropriata, e una virgola dopo le etichette, perché le etichette possono essere effettuati soltanto da istruzioni, e dichiarazioni non contano le dichiarazioni a C ), il programma fa compilazione come 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;
    }
}

Grazie a un compilatore online come http://rextester.com puoi provare rapidamente a compilarlo come C o C ++, usando MSVC, GCC o Clang. Come C funziona sempre (ricorda di impostare STDIN!), Poiché C ++ nessun compilatore lo accetta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.