Fehler: Zum Falletikett springen

229

Ich habe ein Programm geschrieben, das die Verwendung von switch-Anweisungen beinhaltet ... Beim Kompilieren zeigt es jedoch:

Fehler: Zum Falletikett springen.

Warum macht es das?

#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;
}
Frustrierter Coder
quelle
1
Welchen Code versuchen Sie zu kompilieren? Welchen Compiler verwenden Sie? Haben Sie jeden caseBlock in geschweiften Klammern eingeschlossen?
Cody Gray
2
Das ist eine beeindruckende Fehlermeldung im Kreisverkehr
jozxyqk

Antworten:

437

Das Problem ist, dass in einem deklarierte Variablen casein den folgenden cases weiterhin sichtbar sind, sofern kein expliziter { }Block verwendet wird. Sie werden jedoch nicht initialisiert, da der Initialisierungscode zu einem anderen gehört case.

Wenn im folgenden Code foogleich 1 ist, ist alles in Ordnung, aber wenn es gleich 2 ist, verwenden wir versehentlich die iVariable, die zwar existiert, aber wahrscheinlich Müll enthält.

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

Das Umschließen des Falls in einen expliziten Block löst das Problem:

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
}

Bearbeiten

Zum weiteren aufwendigen, switchAussagen sind nur eine besonders ausgefallene Art ein goto. Hier ist ein analoger Code, der das gleiche Problem aufweist, jedoch ein gotoanstelle eines 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;
}
JohannesD
quelle
1
Weitere Erklärungen finden Sie in diesem behobenen
Francesco
70

Die Deklaration neuer Variablen in case-Anweisungen verursacht Probleme. Wenn Sie alle caseAnweisungen in einschließen, {}wird der Umfang neu deklarierter Variablen auf den aktuell ausgeführten Fall beschränkt, der das Problem löst.

switch(choice)
{
    case 1: {
       // .......
    }break;
    case 2: {
       // .......
    }break;
    case 3: {
       // .......
    }break;
}    
Mahesh
quelle
Cleaner Fix Anleitung
yc_yuy
Wird es ein Problem geben, wenn ich die break-Anweisung in die geschweiften Klammern setze?
Vishal Sharma
10

C ++ 11-Standard zum Überspringen einiger Initialisierungen

JohannesD gab eine Erklärung, jetzt für die Standards.

Der C ++ 11 N3337-Standardentwurf 6.7 "Deklarationserklärung" lautet:

3 Es ist möglich, in einen Block zu übertragen, jedoch nicht so, dass Deklarationen bei der Initialisierung umgangen werden. Ein Programm, das von einem Punkt, an dem sich eine Variable mit automatischer Speicherdauer nicht im Gültigkeitsbereich befindet, zu einem Punkt springt, an dem sie sich im Gültigkeitsbereich befindet, ist fehlerhaft, es sei denn, die Variable hat einen Skalartyp, einen Klassentyp mit einem trivialen Standardkonstruktor und einen trivialen destructor, eine cv-qualifizierte Version eines dieser Typen oder ein Array eines der vorhergehenden Typen und wird ohne Initialisierer deklariert (8.5).

87) Die Übertragung von der Bedingung einer switch-Anweisung auf eine Fallbezeichnung wird in dieser Hinsicht als Sprung angesehen.

[Beispiel:

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
}

- Beispiel beenden]

Ab GCC 5.2 lautet die Fehlermeldung jetzt:

kreuzt Initialisierung von

C.

C erlaubt es: c99 geht nach der Initialisierung

Der C99 N1256 Standardentwurf Anhang I "Allgemeine Warnungen" lautet:

2 In einen Block mit Initialisierung eines Objekts mit automatischer Speicherdauer wird gesprungen

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
6

Die Antwort von JohannesD ist richtig, aber ich bin der Meinung, dass ein Aspekt des Problems nicht ganz klar ist.

Das Beispiel, das er gibt, deklariert und initialisiert die Variable iin Fall 1 und versucht dann, sie in Fall 2 zu verwenden. Sein Argument ist, dass, wenn der Wechsel direkt zu Fall 2 ging, iohne Initialisierung verwendet würde, und deshalb gibt es eine Kompilierung Error. An diesem Punkt könnte man denken, dass es kein Problem geben würde, wenn in einem Fall deklarierte Variablen in anderen Fällen niemals verwendet würden. Beispielsweise:

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

Man könnte erwarten, dass dieses Programm kompiliert wird, da beide iund jnur in den Fällen verwendet werden, die sie deklarieren. Leider wird es in C ++ nicht kompiliert: Wie Ciro Santilli erklärte , können wir einfach nicht springen case 2:, da dies die Deklaration mit der Initialisierung von überspringen würde iund obwohl sie case 2überhaupt nicht verwendet iwird. Dies ist in C ++ immer noch verboten.

Interessanterweise mit einigen Anpassungen (ein #ifdefauf #includeden entsprechenden Header und ein Semikolon nach den Etiketten, weil Etiketten können nur von Anweisungen folgen, und Erklärungen gelten nicht als Aussagen in C ), ist dieses Programm tut Kompilierung als 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;
    }
}

Dank eines Online-Compilers wie http://rextester.com können Sie schnell versuchen, ihn mithilfe von MSVC, GCC oder Clang entweder als C oder C ++ zu kompilieren. Als C funktioniert es immer (denken Sie daran, STDIN zu setzen!), Als C ++ akzeptiert es kein Compiler.

Fabio sagt Reinstate Monica
quelle