Forum: PC-Programmierung Switch case mit string


von Tom A. (thomas_a)


Lesenswert?

Hallo,
ich habe c++ porgramm entwickelt, dass ich jetzt mit Hilfe von 
Parametern aus der Console aus aufrufen möchte.

also z.B.: "myprog.exe -reset"
Dann soll der reset ausgeführt werden und vieles mehr.
Da es hier mindestens 15 fälle gibt wollte ich das mit einer Switch case 
realisieren, dass will aber nicht funktionieren.

Hat jmd. eine sinnvolle Idee, wie ich das realisieren kann. Switch case 
kann nur char oder int. Also habe ich versucht das zu mappen, aber das 
hat nicht richtig funktioniert.

Des weiteren bin ich auch getopt gestoßen, aber das bekomme ich iwie 
nicht richtig zum laufen (windows).

Hat jmd. eine Idee? Hat jmd. schonmal ein ähnliches problem gehabt?

Ich hab also mehrere Anstäze und keiner hat auf Anhieb funktionier ;) 
Jetzt wollte ich mich erstmal umhören, bevor ich mich auf einen 
festlege.

Vielen dank für die Ideen schonmal.

Grüße tom

von Karl H. (kbuchegg)


Lesenswert?

Tom A. schrieb:

> Hat jmd. eine sinnvolle Idee, wie ich das realisieren kann.

1
  if( ...... ) {
2
  }
3
4
  else if( ...... ) {
5
  }
6
7
8
  else if( ...... ) {
9
  }
10
11
  else {
12
  }

von Tom A. (thomas_a)


Lesenswert?

Genau darum habe ich nach einer sinnvollen Idee gefragt ;)
Stell dir das jetzt 15 mal vor... Das ist nicht sonderlich schön ^^

Bin für weitere Ideen noch offen :D

von Huch (Gast)


Lesenswert?

Dann gib uns bitte mehr Informationen.
Was ist eine "schöne" Löaung, eine "sinnvolle"?
Das sind abstrakte Eigenschaften die jeder anders objektiviert.

von Tom A. (thomas_a)


Lesenswert?

Es kann ja nicht sein, dass ich 15 IF abfragen hintereinander machen 
muss oder liege ich da falsch?

Bei fast bei jedem Befehl in der cmd gibt es die Parameter, welche 
einfach angehängt werden. Ich dachte eben, dafür gibt es eine Art 
Standard wie das im allgemeinen gelöst wird.

Würdet ihr das etwa mit IF-ELSE lösen?

von Timmo H. (masterfx)


Lesenswert?

Mach dir ein Array, wo du alle "Vergleichsstrings" ablegst und mach vor 
dem Switch ein strcmp und werte die Zahl aus. Also etwa so
1
#include <stdlib.h>
2
#include <stdio.h>
3
4
#define NR_STRINGS 5
5
char cmp_strings[][20] = {"scheisse","mit","erdbeeren","ihh", "erdbeeren!"};
6
7
int main(){
8
   int cmp_str,i;
9
   char buffer[]="mit";
10
   
11
   //string_abfragen(buffer);
12
   
13
   for(i=0; i < NR_STRINGS; i++){
14
     if(!strcmp(buffer, cmp_strings[i]))
15
       break;
16
     if(i == NR_STRINGS -1)
17
       i = -1;
18
   }
19
   switch(i){
20
      case 0:
21
        printf("Da stand was ekeliges drin");
22
        break;
23
      case 1:
24
        printf("Da stand \"mit\" drin");
25
        break;
26
      ...
27
   }
28
}

von Huch (Gast)


Lesenswert?

Ich würde getopt nehmen.

von Peter (Gast)


Lesenswert?

Tom A. schrieb:
> Es kann ja nicht sein, dass ich 15 IF abfragen hintereinander machen
> muss oder liege ich da falsch?

was glaubst du denn wie ein switch case funktioniert? (Es wird nich 
immer mit Sprungtabelle gearbeitet!)

von Timmo H. (masterfx)


Lesenswert?

Geht natürlich auch so:
1
#include <stdlib.h>
2
#include <stdio.h>
3
4
#define NR_STRINGS 5
5
char *cmp_strings[] = {"scheisse","mit","erdbeeren","ihh", "erdbeeren!"};
6
7
int main(){
8
   int cmp_str,i;
9
   char buffer[20];
10
   
11
   string_abfragen(buffer);
12
   
13
   for(i=0; i < NR_STRINGS; i++){
14
     if(!strcmp(buffer, cmp_strings[i]))
15
       break;
16
     if(i == NR_STRINGS -1)
17
       i = -1;
18
   }
19
   switch(i){
20
      case 0:
21
        printf("Da stand was ekeliges drin");
22
        break;
23
      case 1:
24
        printf("Da stand \"mit\" drin");
25
        break;
26
      ...
27
   }
28
}

von Tom A. (thomas_a)


Lesenswert?

Hi,
mit den Posts hat es sich gerade ein wenig überschlagen. Ich hab mich 
jetzt für die Lösung von Timmo entschieden, die ist meiner Meinung nach 
sehr elegant ;)
Hab noch kurz eine schleife drumherum gebaut und ZACK kann man alle 
Eingabeparameter auswerten.

Vielen Dank nochmal, an alle die sich hier so schnell und fleißig 
gemeldet haben.

Hier das Resultat:
1
#define NR_STRINGS 5
2
char *cmp_strings[20] = {"-status","-reset","erdbeeren","ihh", "erdbeeren!"};
3
4
5
int main(int argc, char** argv)
6
{
7
  USBDev a;
8
9
   int cmp_str,i;
10
   for(int j =1;j<argc;j++)
11
   {  
12
     for(i=0; i < NR_STRINGS; i++){
13
     if(!strcmp(argv[j], cmp_strings[i]))
14
       break;
15
     if(i == NR_STRINGS -1)
16
       i = -1;
17
     }
18
       switch(i){
19
        case 0:
20
        printf("-status");
21
        break;
22
        case 1:
23
        printf("-reset");
24
        break;
25
       }
26
   }
27
}

von Vorschlag (Gast)


Lesenswert?

Ich würde eine Klasse dazu erstellen. Für jeden Parameter instanzierst 
du diese Klasse und übergibst ihr die Kommandozeile und den Parameter 
den du haben willst. Nun baust du noch eine Funktion ein die prüft ob 
der Parameter gesetzt wurde, dieser gibt halt true oder false zurück, je 
nachdem ob der Parameter in der übergebenen Liste ist oder nicht.

z.b. hab ich eine Klasse generiert die "clpar" heisst.
Als Konstruktor nimmt sie argc, argv und den Parameter (in echt noch 
mehr).
Dann gibts noch ne Funktion namens isSet() (auch hier natürlich noch 
andere).

Also z.B.:
1
clpar parameterABC(argc, argv, "--ABC");
2
clpar parameterDEF(argc, argv, "-def");
3
4
if (parameterABC.isSet()) // hier tue was

Das war jetzt natürlich nur so grob die Vorgehensweise.
Damit hat man ne schöne Kapselung vom Rest des Projektes und kann die 
Klasse immer schön wiederverwenden.
Ich hab z.B. noch so Sachen wie Argumente für Parameter und deren 
Prüfung mittels Regex eingebaut.

von Sven P. (Gast)


Lesenswert?

Ich würde mich nach getopt umschauen. Oder die Parameter sortieren und 
mit bsearch() arbeiten.

Alternativ kann man in der Suchtabelle prima Callbacks hinterlegen oder 
Zeiger auf Flaggen und so weiter.

von Timmo H. (masterfx)


Lesenswert?

oder xgetopt

von Huch (Gast)


Lesenswert?

Ich würde sogar sagen, man könnte getopt nehmen.

von nicht Gast (Gast)


Lesenswert?

Tom A. schrieb:
> Ich hab mich
> jetzt für die Lösung von Timmo entschieden, die ist meiner Meinung nach
> sehr elegant ;)

Dann mach es so, ich finde es nicht sehr schön, da man ein 
aussagekräftigen string Vergleich durch eine Zahl ersetzt wird.
Ein paar else if Anweisungen finde ich persönlich schöner, die muss man 
dann noch nicht mal mehr kommentieren, da der Inhalt schon der Kommentar 
ist.

und wie schon gesagt bist du nicht der erste der das Problem hatte -> 
getopt

von Klaus W. (mfgkw)


Lesenswert?

Was in C++ auch geht, ist eine
  std::map< std::string, void(*)() >   meinemap;
oder so ähnlich, also eine Map, die Strings auf Funktionen mappt.
Dann geht die Auswahl mit einem schnöden meinemap[meinstring]()
oder ggf. analog mit Parametern oder Funktionsobjekten statt
Funktionen, falls man richtig schick programmieren will.

von Karl H. (kbuchegg)


Lesenswert?

Tom A. schrieb:

> Würdet ihr das etwa mit IF-ELSE lösen?

Kommt drauf an.
Wenn das alles ist, was ausgewertet werden muss: Ja, warum nicht?
15 sind doch nicht viel.

Das ist einfach, schnell geschrieben, leicht zu durchschauen, leicht zu 
erweitern (im Falle eines Falles).

Der Lösung krampfhaft einen switch-case über den Umweg eines Indizes 
einzuführen, kann ich zb überhaupt nichts abgewinnen. Da ist die 
eigentlich wichtige Information, nämlich welches Codestück zu welchem 
Paramater gehört über einen nicht unerkleckliches Stück Code 
verschmiert. Um zu wissen, wann genau der case mit der Nummer 13 
ausgeführt wird, muss ich Wörter in einem Array abzählen. Da schau ich 
lieber auf das if am Anfang des Abschnitts, denn dort steht im Klartext, 
wie die Option lautet. Denn: kürzer ist diese 'Index in Array suchen und 
darauf ausbauen switchen' Lösung in Wirklichkeit auch nicht. Sie 
verschleiert nur ein wenig mehr, was da eigentlich passiert.

Aber seis drum.
Irgendwann wirst auch du merken, dass die vermeintliche Tipparbeit das 
kleinste aller Probleme ist. Code schreibt man nur einmal (ok, manchmal 
wird er noch korrigiert), aber man liest ihn viele male. Da schreib ich 
mir den Code lieber so, dass ich beim Lesen nicht vielen Querverweisen 
folgen und ständig rauf/runter scrollen muss um die Details zu sehen.

von Tom A. (thomas_a)


Lesenswert?

Ok, das mit der switch case, das sehe ich nun auch ein ist Käse ;) da 
man später wirklich nicht mehr durch ...

Ich werde mir jetzt mal das mappen von Funktionen anschauen und mal 
schauen ob das eine gute Lösung für mich ist.

Die if else Lösung finde ich nach wie vor noch nicht soooo tolle ;)

Danke für die Ideen.

Grüße Tom

von Tom A. (thomas_a)


Lesenswert?

Ok, also ich werde es jetzt mal mit einer map realisieren, wenn mich 
dann nochmal etwas stören sollte, werde ich es über den haufen werfen ;)

Die Lösung sieht jetzt so aus:
1
#include <iostream>
2
#include <string>
3
#include <map>
4
using namespace std;
5
6
7
void status() { cout << "status" << endl; }
8
void reset() { cout << "reset" << endl; }
9
10
int main(int argc, char** argv)
11
{
12
13
14
  typedef void (*ptr_fct)();
15
  typedef   map<string, ptr_fct> MapCall;
16
  MapCall fct_map;
17
  fct_map.insert(MapCall::value_type("-status",status));
18
  fct_map.insert(MapCall::value_type("-reset",reset));
19
  MapCall::const_iterator call;
20
21
  
22
  for(int i =1; i<argc;i++)
23
  {
24
    call = fct_map.find(argv[i]);
25
    if (call != fct_map.end())
26
    {
27
      (*call).second();
28
    }
29
    else
30
      cout << "Unknown call requested" << endl;
31
  }
32
}

Vielen dank für die Inspiration ;)

Grüße Tom

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Tom A. schrieb:
> Die if else Lösung finde ich nach wie vor noch nicht soooo tolle
Macht auch nicht das was du jetzt programmiert hast, den auf diese Weise 
werden alle Übergebenen Befehle ausgewertet, bei der else/if Lösung 
jedoch höchstens einer...

von Rolf M. (rmagnus)


Lesenswert?

Klaus Wachtler schrieb:
> Was in C++ auch geht, ist eine
>   std::map< std::string, void(*)() >   meinemap;
> oder so ähnlich, also eine Map, die Strings auf Funktionen mappt.
> Dann geht die Auswahl mit einem schnöden meinemap[meinstring]()

Nein, denn das hätte böse Folgen, wenn jemand einen Paramter übergibt, 
den das Programm nicht kennt. Tom hat das mit der Benutzung von find() 
schon richtig gemacht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.