Erreur: passer à l’étiquette du cas


229

J'ai écrit un programme qui implique l'utilisation d'instructions switch ... Cependant, lors de la compilation, il montre:

Erreur: passer à l'étiquette de cas.

Pourquoi ça fait ça?

#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
Quel code essayez-vous de compiler? Quel compilateur utilisez-vous? Avez-vous enfermé chaque casebloc entre accolades?
Cody Gray

2
c'est un message d'erreur
incroyablement détourné

Réponses:


437

Le problème est que les variables déclarées dans l'une casesont toujours visibles dans les cases suivants, sauf si un { }bloc explicite est utilisé, mais elles ne seront pas initialisées car le code d'initialisation appartient à un autre case.

Dans le code suivant, si fooégal à 1, tout va bien, mais s'il est égal à 2, nous utiliserons accidentellement la ivariable qui existe mais qui contient probablement des ordures.

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

Envelopper le boîtier dans un bloc explicite résout le problème:

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
}

Éditer

Pour développer davantage, les switchdéclarations ne sont qu'un type particulièrement sophistiqué de goto. Voici un morceau de code analogue présentant le même problème mais utilisant un gotoau lieu d'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
Voir ce rapport de bogue LLVM fixe pour d'autres explications: llvm.org/bugs/show_bug.cgi?id=7789
Francesco

70

La déclaration de nouvelles variables dans les déclarations de cas est la cause des problèmes. La fermeture de toutes les caseinstructions dans {}limitera la portée des variables nouvellement déclarées au cas en cours d'exécution, ce qui résout le problème.

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

instruction de correction de nettoyage
yc_yuy

Y aura-t-il un problème si je mets l'instruction break entre les accolades?
Vishal Sharma

10

Norme C ++ 11 sur le saut par-dessus certaines initialisations

JohannesD a donné une explication, maintenant pour les normes.

Le projet de norme 6.7 C ++ 11 N3337 "Déclaration de déclaration" dit:

3 Il est possible de transférer dans un bloc, mais pas d'une manière qui contourne les déclarations avec l'initialisation. Un programme qui saute (87) d'un point où une variable avec une durée de stockage automatique n'est pas dans la portée à un point où elle est dans la portée est mal formé sauf si la variable a un type scalaire, un type de classe avec un constructeur par défaut trivial et un trivial destructor, une version qualifiée cv de l'un de ces types, ou un tableau de l'un des types précédents et est déclaré sans initialiseur (8.5).

87) Le passage de la condition d'une instruction switch à une étiquette de cas est considéré comme un saut à cet égard.

[ Exemple:

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
}

- exemple de fin]

Depuis GCC 5.2, le message d'erreur indique maintenant:

croise l'initialisation de

C

C le permet: c99 est passé à l'initialisation

Le projet d' annexe I de la norme C99 N1256 "Avertissements communs" dit:

2 Un bloc avec l'initialisation d'un objet qui a une durée de stockage automatique est sauté dans


6

La réponse de JohannesD est correcte, mais je pense qu'elle n'est pas entièrement claire sur un aspect du problème.

L'exemple qu'il donne déclare et initialise la variable idans le cas 1, puis essaie de l'utiliser dans le cas 2. Son argument est que si le commutateur allait directement au cas 2, il iserait utilisé sans être initialisé, et c'est pourquoi il y a une compilation Erreur. À ce stade, on pourrait penser qu'il n'y aurait aucun problème si les variables déclarées dans un cas n'étaient jamais utilisées dans d'autres cas. Par exemple:

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

On pourrait s'attendre à ce que ce programme compile, car les deux iet ne jsont utilisés qu'à l'intérieur des cas qui les déclarent. Malheureusement, en C ++, il ne compile pas: comme l' explique Ciro Santilli 包子 露 宪 六四 事件 法轮功 , nous ne pouvons tout simplement pas y accédercase 2: , car cela ignorerait la déclaration avec l'initialisation de i, et même s'il case 2n'utilise pas idu tout, cela est toujours interdit en C ++.

Fait intéressant, avec quelques ajustements (un #ifdefà #includel' en- tête appropriée, et un point - virgule après les étiquettes, car les étiquettes ne peuvent être suivies par des déclarations et des déclarations ne comptent pas comme des déclarations en C ), ce programme ne compile que 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;
    }
}

Grâce à un compilateur en ligne comme http://rextester.com, vous pouvez rapidement essayer de le compiler en C ou C ++, en utilisant MSVC, GCC ou Clang. En C, cela fonctionne toujours (n'oubliez pas de définir STDIN!), En C ++, aucun compilateur ne l'accepte.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.