etiqueta descripcion c++

c++ - descripcion - Error: Salte a la etiqueta del caso



meta title html (4)

El problema es que las variables declaradas en un case siguen siendo visibles en el case subsiguiente a menos que se use un bloque { } explícito, pero no se inicializarán porque el código de inicialización pertenece a otro case .

En el siguiente código, si foo es igual a 1, todo está bien, pero si es igual a 2, accidentalmente usaremos la variable i que existe pero que probablemente contenga basura.

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

Envolver la caja en un bloque explícito resuelve el 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 }

Editar

Para seguir elaborando, las declaraciones de switch son solo un tipo de goto particularmente elegante. Aquí hay una pieza de código análoga que muestra el mismo problema pero que utiliza un goto lugar de 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; }

Escribí un programa que implica el uso de instrucciones de cambio ... Sin embargo, en la compilación muestra:

Error: salta a la etiqueta de la caja.

¿Porque hace eso?

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


La declaración de nuevas variables en las declaraciones de casos es lo que causa problemas. Encerrar todas las declaraciones de case en {} limitará el alcance de las variables recién declaradas al caso de ejecución actual que resuelve el problema.

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


Estándar C ++ 11 saltando sobre algunas inicializaciones

JohannesD dio una explicación, ahora para los estándares.

Proyecto estándar C ++ 11 N3337 6.7 Declaración de declaración 3) dice:

Es posible transferir a un bloque, pero no de una manera que puentee las declaraciones con la inicialización. Un programa que salta (87) desde un punto donde una variable con duración de almacenamiento automática no está en alcance hasta un punto en el que está dentro del alcance está mal formado a menos que la variable tenga tipo escalar, tipo de clase con un constructor trivial predeterminado y un trivial destructor, una versión cv-calificada de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador (8.5).

87) La transferencia de la condición de una declaración de cambio a una etiqueta de caso se considera un salto en este sentido.

[Ejemplo:

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 }

- ejemplo final]

A partir de GCC 5.2, el mensaje de error ahora dice:

cruza la inicialización de

do

C lo permite: c99 pasó a la inicialización

C99 N1256 proyecto estándar Anexo I Advertencias comunes 2) dice:

Se salta a un bloque con inicialización de un objeto que tiene una duración de almacenamiento automática


La respuesta de JohannesD es correcta, pero creo que no está del todo claro en un aspecto del problema.

El ejemplo que él da declara e inicializa la variable i en el caso 1, y luego trata de usarla en el caso 2. Su argumento es que si el interruptor fuera directo al caso 2, se usaría sin inicializar, y esta es la razón por la cual hay un error de compilación En este punto, uno podría pensar que no habría problemas si las variables declaradas en un caso nunca se usaran en otros casos. Por ejemplo:

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

Uno podría esperar que este programa compilara, ya que tanto i como j se usan solo dentro de los casos que los declaran. Desafortunadamente, en C ++ no compila: como explicó Ciro Santilli, 露,,,,, simplemente no podemos saltar al case 2: porque esto omitirá la declaración con la inicialización de i , y aunque el case 2 no lo hace No uso i en absoluto, esto todavía está prohibido en C ++.

Curiosamente, con algunos ajustes (un #ifdef para #ifdef el encabezado apropiado, y un punto y coma después de las etiquetas, porque las etiquetas solo pueden ser seguidas por las declaraciones, y las declaraciones no cuentan como declaraciones en C ), este programa se compila como 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; } }

Gracias a un compilador en línea como http://rextester.com , puede intentar compilarlo rápidamente como C o C ++, utilizando MSVC, GCC o Clang. Como C siempre funciona (¡simplemente recuerde establecer STDIN!), Como C ++ ningún compilador lo acepta.