3
int a = 0 , b = 0;
char* c = NULL;

int main(int argc , char ** argv){

    c = argv[2];
    a = atoi(argv[1]);
    b = atoi(argv[3]);

    switch(c){

        case "+": printf(a+b);
                  break;
    }

    printf("\n\n");

    return 0;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
aTechieSmile
  • 139
  • 1
  • 1
  • 11
  • 1
    No that is not possible but you could switch with characters. Convert them to int and them switch based on ASCII code. – qwn Dec 28 '17 at 10:33

7 Answers7

5

No, you can't. Switch is intended to compare numeric types, and for extension char types. Instead you should use the strcmp function, included in string header:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char * argv[]) {
  if (argc != 4) {
    puts("Incorrect usage");
    return 1;
  }
  /* You should check the number of arguments */

  char * op = argv[1];
  int a = atoi(argv[2]);
  int b = atoi(argv[3]);
  /* You should check correct input too */

  if (strcmp(op, "+") == 0)
    printf("%d + %d = %d\n", a, b, a + b);
  else if (strcmp(op, "-") == 0)
    printf("%d - %d = %d\n", a, b, a - b);
  /* Add more functions here */

  return 0;
}
  • yes !! i've tried this and its worked!! but is this only the way for doing this stuff?? – aTechieSmile Dec 28 '17 at 10:51
  • @RuchiM.Mewada: There are others but they are putting up an unnecessary fight with the language. This is by far the best way: although I prefer `!strcmp` to `strcmp == 0`. Still gets an upvote though. – Bathsheba Dec 28 '17 at 10:53
  • Still, compared to a switch performance can become an issue here. At least it's not performing equal for each value. – alk Dec 28 '17 at 10:58
  • @alk: yes for the same code I've mentioned above...in case of if(!(strcmp(c == "*"))...it gives me 123 for pf(%s,c) instead of * ...can anyone explain this? is this taking * as an arithmetic multi oprtr or dereference optr?? – aTechieSmile Dec 28 '17 at 11:24
3

No you can't. The case labels of a switch need to be compile time evaluable constant expressions with an integral type.

But int literals like '+' satisfy that requirement. (As do enum values for that matter.)

Some folk like to use implementation-defined multi-character literals (e.g. 'eax') as case labels as they claim it helps readability, but at that point, you're giving up consistent behaviour across different platforms.

If you need to branch on the value of a NUL-terminated char array, then use an if block.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

There are two cases to the answer ..

Firstly 6.8.4.2 (switch case)

The controlling expression of a switch statement shall have integer type

Secondly 6.8.4.2 (the case statements)

The expression of each case label shall be an integer constant expression and no two of the case constant expressions in the same switch statement shall have the same value after conversion

Long story short - you can't use string literal like that. Neither in switch controlling expression nor in case.

You can do the string comparisons using strcmp and then do the if-else conditioning. The context on which you ask this, you can simply pass the character + (argv[2][0]) instead of passing the whole literal. That way you will be passing char to the switch expression and then work accordingly.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
user2736738
  • 30,591
  • 5
  • 42
  • 56
1

Nope, that's not possible.

Quoting C11, chapter §6.8.4.2

The controlling expression of a switch statement shall have integer type.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

in your case, you don't seem to need a string but rather the first (and only character) of the string passed in the switch statement, in that case that's possible using character literal (which has integer type) in the case statements:

if (strlen(c)==1)
{
  switch(c[0]){

    case '+': printf(a+b);
              break;
    ...
  }
}

some good other alternatives are described in best way to switch on a string in C when the string has multiple characters.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • 1
    I'm sure you know this, but in C, `'+'` is an `int` type. – Bathsheba Dec 28 '17 at 10:42
  • 1
    " In C, a character literal is treated as int type where as in C++, a character literal is treated as char type" but I wasn't aware of that difference, just looked that up. Good to know. who said that C++ was a subset of C? – Jean-François Fabre Dec 28 '17 at 10:52
0

Not directly. But yes, you can.

#include <ctype.h>
#include <stdio.h>
#include <string.h>

// The way you store and search for names is entirely 
// up to you. This is a simple linear search of an 
// array. If you have a lot of names, you might choose
// a better storage + lookup, such as a hash table.
int find( const char** ss, int n, const char* s )
{
  int i = 0;
  while (i < n)
    if (strcmp( ss[i], s ) == 0) break;
    else                         i += 1;
  return i;
}

// A bevvy of little utilities to help out.
char* strupper( char* s )
{
  char* p = s;
  while ((*p = toupper( *p ))) ++p;
  return s;
}

char* zero( char* p ) { if (p) *p = 0; return p; }

#define STRINGIFY(S) STRINGIFY0(S)
#define STRINGIFY0(S) #S

int main()
{
  // Our list of names are enumerated constants with associated
  // string data. We use the Enum Macro Trick for succinct ODR happiness.
  #define NAMES(F) \
    F(MARINETTE) \
    F(ADRIAN) \
    F(ALYA) \
    F(DINO)
  #define ENUM_F(NAME) NAME,
  #define STRING_F(NAME) STRINGIFY(NAME),
  enum names { NAMES(ENUM_F) NUM_NAMES };
  const char* names[ NUM_NAMES ] = { NAMES(STRING_F) NULL };
  #undef STRING_F
  #undef ENUM_F
  #undef NAMES

  // Ask user for a name
  char s[ 500 ];
  printf( "name? " );
  fflush( stdout );
  fgets( s, sizeof( s ), stdin );
  zero( strchr( s, '\n' ) );

  // Preprocess and search for the name  
  switch (find( names, sizeof(names)/sizeof(*names), strupper( s ) ))
  {
    case MARINETTE: puts( "Ladybug!" ); break;
    case ADRIAN:    puts( "Chat Noir!" ); break;
    case ALYA:      
    case DINO:      puts( "Best friend!" ); break;
    default:        puts( "Who?" );
  }
}

Keep in mind this works by pure, unadulterated magic tricks, and is not suitable for large collections of text values.

Also, the validity of the match is entirely dependent on the degree to which you pre-process the user’s input. In this example we only ignore case, but a more advanced application might perform some more sophisticated matching.

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39
0

As others pointed out in C one cannot use a string as argument to a switch, nor to its case-labels.

To get around this limitation one could map each string to a specific integer and pass this to the switch.

Looking up the mapping requires searching the map, which can be done using the Standard C bsearch() function.

An example might look like this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>

enum Operation {
  OP_INVALID = -1,
  OP_ADD,
  OP_SUBTRACT,
  OP_MULTIPLY,
  OP_DIVIDE,
  OP_MAX
};

struct Operation_Descriptor {
  char * name;
  enum Operation op;
};

struct Operation_Descriptor operations [] = {
  {"add", OP_ADD},
  {"subtract", OP_SUBTRACT},
  {"multiply", OP_MULTIPLY},
  {"divide", OP_DIVIDE}
};

int cmp(const void * pv1, const void * pv2)
{
  const struct Operation_Descriptor * pop1 = pv1;
  const struct Operation_Descriptor * pop2 = pv2;

  return strcmp(pop1->name, pop2->name);
}

int main(int argc, char ** argv)
{
  size_t s = sizeof operations / sizeof *operations;

  /* bsearch() requires the array to search to be sorted. */
  qsort(operations, s, sizeof *operations, cmp);

  {
    struct Operation_Descriptor * pop = 
      bsearch(
        &(struct Operation_Descriptor){argv[1], OP_INVALID}, 
        operations, s, sizeof *operations, cmp);

    switch(pop ?pop->op :OP_INVALID)
    {
      case OP_ADD:
        /* Code to add goes here, */
        break;

      case OP_SUBTRACT:
        /* Code to subtract goes here, */
        break;

      case OP_MULTIPLY:
        /* Code to multiply goes here, */
        break;

      case OP_DIVIDE:
        /* Code to divide goes here, */
        break;

      case OP_INVALID:

      default:
        fprintf(stderr,  "unhandled or invalid operation '%s'\n", argv[1]);
        break;
    }
  }
}

If on POSIX one can even use a hash table, which is the fastest way to lookup the mapping.

An example might look like this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>

enum Operation {
  OP_INVALID = -1,
  OP_ADD,
  OP_SUBTRACT,
  OP_MULTIPLY,
  OP_DIVIDE,
  OP_MAX
};

struct Operation_Descriptor {
  char * name;
  enum Operation op;
};

struct Operation_Descriptor operations [] = {
  {"add", OP_ADD},
  {"subtract", OP_SUBTRACT},
  {"multiply", OP_MULTIPLY},
  {"divide", OP_DIVIDE}
};

int main(int argc, char ** argv)
{
  if (0 == hcreate(5))
  {
    perror("hcreate() failed");
    exit(EXIT_FAILURE);
  }

  for (size_t i = 0; i < s; ++i)
  {
    if (!hsearch((ENTRY){operations[i].name, &operations[i].op}, ENTER))
    {
      perror("hsearch(ENTER) failed");
      exit(EXIT_FAILURE);
    }
  }

  {
    ENTRY * ep = hsearch((ENTRY){argv[1], NULL}, FIND);

    switch(ep ?*((enum Operation *)ep->data) :OP_INVALID)
    {
      case OP_ADD:
        /* Code to add goes here, */
        break;

      case OP_SUBTRACT:
        /* Code to subtract goes here, */
        break;

      case OP_MULTIPLY:
        /* Code to multiply goes here, */
        break;

      case OP_DIVIDE:
        /* Code to divide goes here, */
        break;

      case OP_INVALID:

      default:
        fprintf(stderr,  "unhandled or invalid operation '%s'\n", argv[1]);
        break;
    }
  }

  hdestroy(); /* Clean up. */
}
alk
  • 69,737
  • 10
  • 105
  • 255