Ошибка: перейти к метке регистра
Я написал программу, которая включает использование операторов switch... Однако при компиляции это показывает:
Ошибка: перейти к метке регистра.
Почему это так?
#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;
}
4 ответа
Проблема в том, что переменные объявлены в одном case
все еще видны в последующем case
с, если явно { }
блок используется, но они не будут инициализированы, потому что код инициализации принадлежит другому case
,
В следующем коде, если foo
равно 1, все в порядке, но если оно равно 2, мы случайно будем использовать i
переменная, которая существует, но, вероятно, содержит мусор.
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!
}
Заключение в явный блок решает проблему:
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
}
редактировать
Для дальнейшей разработки, switch
заявления являются просто особенно причудливым видом goto
, Вот аналогичный кусок кода, демонстрирующий ту же проблему, но с использованием goto
вместо 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;
}
Объявление новых переменных в выражениях case - это то, что вызывает проблемы. Включая все case
заявления в {}
ограничит область действия вновь объявленных переменных текущим делом, которое решает проблему.
switch(choice)
{
case 1: {
// .......
}break;
case 2: {
// .......
}break;
case 3: {
// .......
}break;
}
Стандарт C++11, перепрыгивающий через некоторые инициализации
JohannesD дал объяснение, теперь для стандартов.
Проект стандарта C++11 N3337 6.7 Заявление о декларации 3) гласит:
Можно передавать в блок, но не так, чтобы обойти объявления с инициализацией. Программа, которая переходит (87) из точки, в которой переменная с автоматическим хранением находится вне области действия, до точки, в которой она находится в области видимости, плохо сформирована, если переменная не имеет скалярного типа, типа класса с тривиальным конструктором по умолчанию и тривиальным деструктор, cv-квалифицированная версия одного из этих типов или массив одного из предыдущих типов и объявляется без инициализатора (8.5).
87) Переход от условия оператора switch к метке регистра считается скачком в этом отношении.
[ Пример:
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 }
- конец примера]
Начиная с GCC 5.2, сообщение об ошибке теперь говорит:
пересекает инициализацию
С
C позволяет это: C99 Перейти к инициализации
Проект стандарта C99 N1256,Приложение I Общие предупреждения 2) гласит:
Блок с инициализацией объекта, который имеет автоматическую продолжительность хранения, перемещается в
JohannesD ответ правильный, но я чувствую, что не совсем ясно по аспекту проблемы.
Пример, который он дает, объявляет и инициализирует переменную i
в случае 1, а затем пытается использовать его в случае 2. Его аргумент заключается в том, что если переключение перешло прямо к случаю 2, i
будет использоваться без инициализации, и именно поэтому есть ошибка компиляции. В этот момент можно подумать, что не будет проблем, если переменные, объявленные в одном случае, никогда не будут использоваться в других случаях. Например:
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;
}
Можно ожидать, что эта программа компилируется, так как оба i
а также j
используются только внутри случаев, которые их объявляют. К сожалению, в C++ он не компилируется: как объяснил Ciro Santilli 包子露 jump 六四事件 法轮功, мы просто не можем перейти к case 2:
потому что это пропустит объявление с инициализацией i
и хотя case 2
не использует i
вообще, это все еще запрещено в C++.
Интересно, что с некоторыми корректировками (#ifdef
в #include
соответствующий заголовок и точка с запятой после меток, поскольку за метками могут следовать только операторы, а объявления не считаются как операторы в C), эта программа компилируется как 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;
}
}
Благодаря онлайн-компилятору, такому как http://rextester.com/ вы можете быстро попытаться скомпилировать его как C или C++, используя MSVC, GCC или Clang. Как C всегда работает (только не забудьте установить STDIN!), Так как C++ никакой компилятор не принимает.