Erreur: Aller à l’étiquette de cas

J’ai écrit un programme qui implique l’utilisation d’instructions switch … Cependant sur la compilation cela montre:

Erreur: Aller à l’étiquette de cas.

Pourquoi ça fait ça?

#include  #include  #include  #include  using namespace std; class contact { public: ssortingng name; int phonenumber; ssortingng address; contact() { name= "Noname"; phonenumber= 0; address= "Noaddress"; } }; int main() { contact *d; d = new contact[200]; ssortingng 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; ssortingng file_input_name; ssortingng 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<>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<>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<>phno; d[i1].phonenumber=phno; cout<>add; d[i1].address=add; i1++; i++; break;//Exit Case 1 to the main menu case 2: cout<>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<>ch; if(ch=='y'|| ch=='Y'){ cout<>phno; for(int j=0;j<=i;j++){ if(d[j].phonenumber==phno && staticname==d[j].name){ cout<>ch; if(ch=='y'||ch=='Y'){ cout<>name; d[j].name=name; } cout<>ch; if(ch=='y'||ch=='Y'){ cout<>phno1; d[j].phonenumber=phno1; } cout<>ch; if(ch=='y'||ch=='Y'){ cout<>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; } 

Le problème est que les variables déclarées dans un case sont toujours visibles dans les case suivants case 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 est égal à 1, tout va bien, mais s’il est égal à 2, nous utiliserons accidentellement la variable i qui existe mais qui contient probablement des erreurs.

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

modifier

Pour donner plus de précisions, les déclarations de switch compte ne sont qu’un type particulier de fantaisie. Voici un morceau de code analogue présentant le même problème mais utilisant un goto au 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 comstack time. // Whether the *initialization* code was run, though, // depends on whether rand returned 0 or 1. std::cout << i; } 

La déclaration de nouvelles variables dans les déclarations de cas est ce qui pose problème. Enfermer toutes les instructions de case dans {} limitera la scope des variables nouvellement déclarées au cas en cours d’exécution qui résout le problème.

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

Norme C ++ 11 sautant certaines initialisations

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

C ++ 11 N3337, projet standard 6.7 Déclaration de déclaration 3) :

Il est possible de transférer dans un bloc, mais pas d’une manière qui contourne les déclarations avec initialisation. Un programme qui saute (87) d’un point où une variable avec une durée de stockage automatique n’est pas à scope est mal formé à moins que la variable ait un type scalaire, un type de classe avec un constructeur par défaut sortingvial et un sortingvial destructeur, 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 transfert de la condition d’une déclaration de commutation à 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]

A partir de GCC 5.2, le message d’erreur indique maintenant:

traverse l’initialisation de

C

C le permet: c99 goto passé initialisation

Le projet de norme C99 N1256, Annexe I, Avertissements communs 2) :

Un bloc avec initialisation d’un object qui a une durée de stockage automatique est sauté dans

La réponse de JohannesD est correcte, mais j’estime que ce n’est pas tout à fait clair sur un aspect du problème.

L’exemple qu’il donne déclare et initialise la variable i dans le cas 1, puis essaie de l’utiliser dans le cas 2. Son argument est que si le commutateur passait directement au cas 2, i serais utilisé sans être initialisé, et c’est pourquoi il y a une erreur de compilation. À ce stade, on pourrait penser qu’il n’y aurait pas de 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 se comstack, car i et j sont utilisés qu’à l’intérieur des cas qui les déclarent. Malheureusement, en C ++, il ne comstack pas: comme Ciro Santilli l’a expliqué , nous ne pouvons simplement pas sauter à la case 2: , car cela ignorerait la déclaration avec l’initialisation de i et même si le case 2 ne le fait pas. Ne pas utiliser du tout, cela est toujours interdit en C ++.

Fait intéressant, avec quelques ajustements (un #ifdef à #ifdef l’en-tête approprié et un point-virgule après les étiquettes, car les étiquettes ne peuvent être suivies que par des instructions et les déclarations ne sont pas considérées comme des instructions en C ), ce programme se comstack en C:

 // Disable warning issued by MSVC about scanf being deprecated #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #ifdef __cplusplus #include  #else #include  #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 tel que http://rextester.com, vous pouvez rapidement essayer de le comstackr en C ou C ++, en utilisant MSVC, GCC ou Clang. Comme C, cela fonctionne toujours (n’oubliez pas de définir STDIN!), Car aucun compilateur ne l’accepte.