102 votes

Comment comparer des chaînes en C à l'aide d'une instruction « switch » ?

En C, il existe une construction switch qui permet d'exécuter différentes branches conditionnelles de code basées sur une valeur entière de test, par exemple,

 int a;
/* Read the value of "a" from some source, e.g. user input */
switch (a) {
  case 100:
    // Code
    break;
  case 200:
    // Code
    break;
  default:
    // Code
    break;
}

Comment est-il possible d'obtenir le même comportement (c'est-à-dire éviter le soi-disant " if - else ladder") pour une valeur de chaîne, c'est-à-dire un char * ?

128voto

Si vous voulez dire, comment écrire quelque chose de similaire à ceci :

 // switch statement
switch (string) {
  case "B1": 
    // do something
    break;
  /* more case "xxx" parts */
}

Ensuite, la solution canonique en C consiste à utiliser une échelle if-else :

 if (strcmp(string, "B1") == 0) 
{
  // do something
} 
else if (strcmp(string, "xxx") == 0)
{
  // do something else
}
/* more else if clauses */
else /* default: */
{
}

56voto

Edgar Bonet Points 1425

Si vous avez de nombreux cas et que vous ne voulez pas écrire une tonne d' strcmp() , vous pouvez faire quelque chose comme :

 switch(my_hash_function(the_string)) {
    case HASH_B1: ...
    /* ...etc... */
}

Vous devez juste vous assurer que votre fonction de hachage n'a pas de collisions dans l'ensemble des valeurs possibles pour la chaîne.

45voto

plinth Points 26817

Il n'y a aucun moyen de le faire en C. Il existe de nombreuses approches différentes. Généralement, le plus simple consiste à définir un ensemble de constantes qui représentent vos chaînes et à rechercher par chaîne pour obtenir la constante :

 #define BADKEY -1
#define A1 1
#define A2 2
#define B1 3
#define B2 4

typedef struct { char *key; int val; } t_symstruct;

static t_symstruct lookuptable[] = {
    { "A1", A1 }, { "A2", A2 }, { "B1", B1 }, { "B2", B2 }
};

#define NKEYS (sizeof(lookuptable)/sizeof(t_symstruct))

int keyfromstring(char *key)
{
    int i;
    for (i=0; i < NKEYS; i++) {
        t_symstruct *sym = lookuptable[i];
        if (strcmp(sym->key, key) == 0)
            return sym->val;
    }
    return BADKEY;
}

/* ... */
switch (keyfromstring(somestring)) {
case A1: /* ... */ break;
case A2: /* ... */ break;
case B1: /* ... */ break;
case B2: /* ... */ break;
case BADKEY: /* handle failed lookup */
}

Il existe bien sûr des moyens plus efficaces de le faire. Si vous gardez vos clés triées, vous pouvez utiliser une recherche binaire. Vous pouvez également utiliser une table de hachage. Ces choses changent vos performances au détriment de la maintenance.

17voto

xtofl Points 22333

Je pense que la meilleure façon de le faire est de séparer la « reconnaissance » de la fonctionnalité :

 struct stringcase { char* string; void (*func)(void); };

void funcB1();
void funcAzA();

stringcase cases [] = 
{ { "B1", funcB1 }
, { "AzA", funcAzA }
};

void myswitch( char* token ) {
  for( stringcases* pCase = cases
     ; pCase != cases + sizeof( cases ) / sizeof( cases[0] )
     ; pCase++ )
  {
    if( 0 == strcmp( pCase->string, token ) ) {
       (*pCase->func)();
       break;
    }
  }

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X