1

How can I compare an array of char in c++ using switch-case? Here is a part of my code:

char[256] buff;
switch(buff){
case "Name": printf("%s",buff);
             break;
case "Number": printf("Number "%s",buff);
               break;
defaul : break
}

I receive the error :" error: switch quantity not an integer".How can I resolve it?

john
  • 47
  • 1
  • 1
  • 3

10 Answers10

10

If you really need a switch statement, you will need to convert your buff variable to an integer. To do so, you could use a hash function or a std::map.

The easy approach would be to make a std::map<std::string,int> containing the keys you want to use in the switch associated with unique int values. You would get something like:

std::map<string,int> switchmap;
...
switch(switchmap.find(std::string(buff))->second){
...
}

The std::map approach is very readable and shouldn't cause much confusion.

Marc Claesen
  • 16,778
  • 6
  • 27
  • 62
3

You just can't use an array as the expression in a switch construct.

Crowman
  • 25,242
  • 5
  • 48
  • 56
3

In C++ case statements require a constant integer value and cannot be used with values calculated at runtime. However if you are using C++11 you can use a constexpr function to generate case values simulate using strings with a case statement.

This uses a hash function that takes a pointer to a string and generates a value at compile time instead of runtime. If more than one string generates the same value (a hash collision) you get the familiar error message about multiple case statements using the same value.

constexpr unsigned int djb2Hash(const char* str, int index = 0)
{
    return !str[index] ? 0x1505 : (djb2Hash(str, index + 1) * 0x21) ^ str[index];
}

The djb2Hash function can then be used directly in both the switch and case statements. There is one caveat however, the hash function can result in a collision at runtime. The probability of this happening is driven primarily by the quality of the hash function. The solution presented here does not attempt to address this problem (but may in the future).

void DoSomething(const char *str)
{
    switch(djb2Hash(str))
    {
        case djb2Hash("Hello"): SayHello(); break;
        case djb2Hash("World"): SayWorld(); break;
    }
}

This works very well but might be considered ugly. You can simplify this further by declaring a user defined literal that handles invoking the hash function.

// Create a literal type for short-hand case strings
constexpr unsigned int operator"" _C ( const char str[], size_t size)
{
    return djb2Hash(str);
}

void DoSomething(const char *str)
{
    switch(djb2Hash(str))
    {
        case "Hello"_C: SayHello(); break;
        case "World"_C: SayWorld(); break;
    }
}

This provides a more intuitive usage of strings in a switch statements but may also be considered slightly confusing because of the user defined literal.

[Edit: Added note about runtime hash collisions. Much Kudos to R. Martinho Fernandes for bringing it to my attention!]

Community
  • 1
  • 1
Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
  • Collisions at compile-time are not the biggest problem. Collisions at runtime are. `DoSomething("CollidesWithHello")`? – R. Martinho Fernandes May 23 '13 at 23:36
  • @R.MartinhoFernandes Yes, collisions originating from the conditional can happen - haven't quite gotten to working that aspect of it out yet. I'll update the answer to note that. – Captain Obvlious May 24 '13 at 00:32
  • Point is you cannot work it out of it. – R. Martinho Fernandes May 24 '13 at 10:11
  • @R.MartinhoFernandes Using a `std::map` to source the condition value would solve the problem. I'm not particularly keen on the idea yet but it seems to be a suitable trade off to avoid runtime collisions. – Captain Obvlious May 24 '13 at 13:51
  • I worked it out here: https://stackoverflow.com/questions/4165131/c-c-switch-for-non-integers/45226108#45226108. The trick is that you have to check for equality in the case with the matched string, `case "World"_C: if( strcmp(str,"World") ){SayWorld(); break;} `. This makes a string-switch macro that much more attractive. – wawiesel Jul 21 '17 at 06:10
1

You cannot use a non-integral type in a switch statement. Your problem would require something like:

char buff[256];
if(!strcmp(buf, "Name") printf("%s",buff);
if(!strcmp(buf, "Number") printf("%s",buff);

To get the results you are looking for - basically a bunch of if statements to replace the switch.

Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61
0

You are trying to do something we all dearly wish we could, but not in C/C++ :) The case in a switch statement must be integral values. One easy alternative is to have an enumeration that matches the set of strings you want to act on.

Ben Brammer
  • 988
  • 4
  • 11
0

In C++ you can use a switch-case only with integers (char, int, ...) but not with c-strings (char *)

In your case you have to use a if-then-else construct

if (strcmp(buff, "Name") == 0) {
    ...
} else if (...) {
    ...
}
JDS
  • 1,173
  • 12
  • 26
0

As the error says, switch only works for integers. The simplest resolution is to use a chain of if...else if... tests.

However, using a char array rather than a string is awkward, since you need quirky C-style functions to compare them. I suggest you use std::string instead.

std::string buff;
if (buff == "Name") {
    // deal with name
} else if (buff == "Number") {
    // deal with number
} else {
    // none of the above
}

More complex approaches, perhaps mapping strings to numbers for use in a switch or to functors to call, are possible and may be more efficient if you have a huge number of cases; but you should get the simple version working before worrying about such optimisations.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

Unlike many other languages that allow string and other object comparisons to be used in a switch-case, c++ requires that the underlying value be an integer. If you want use more complex object types, you will have to use an if else-if construct.

csj
  • 21,818
  • 2
  • 20
  • 26
0

You can't use a switch directly for this situation.

Typically, you'd want to use a std::map (or std::unordered_map) to store the action to associate with each input. You might (for example) use a std::map<std::string, std::function>, and then store the addresses of functions/function objects in the map, so your final construct would be something like:

std::map<std::string, std::function> funcs;
funcs["Name"] = [](std::string const &n) {std::cout <<  n;};
funcs["Number"] = [](std::string const &n) {std::cout << "Number: " << n;};

// ...
auto f = funcs[buff];
f(buff);
// or combine lookup and call: funcs[buff](buff);

Two notes: first, you probably really want to use map::find for the second part, so you can detect when/if the string you're looking for isn't present in the map.

Second, as it stands, your code doesn't seem to make much sense -- you're both switching on buff and printing out buff's value, so (for example) if you buff contains Number, your output will be "Number Number". I'd guess you intend to use buff and some other variable that holds the value you care about.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

You can partially do a "string" compare.

The below does not specifically satisfy your query (as C won't ride that pony), nor is it elegant code, but a variation on it may get you through your need. I do not recommend you do this if you a learning C/C++, but this construct has worked well in limited programming environment.
(I use it in PIC programming where strlen(buff)==1 or 2 and sizeof(int)==2.)

Let's assume sizeof(int) == 4 and strlen(buff) >= 3.

char buff[256];
// buff assignment code is TBD.
// Form a switch 4-byte key from the string "buff".
// assuming a big endian CPU.
int key = (buff[0] << 3*8) | (buff[1] << 2*8) | (buff[2] << 1*8) | (buff[3] << 0*8);
// if on a little endian machine use:
// int key = (buff[0] << 0*8) | (buff[1] << 1*8) | (buff[2] << 2*8) | (buff[3] << 3*8);
switch (key) {
  // Notice the single quote vs. double quote use of constructing case constants.
  case 'Name': printf("%s",buff);         break;
  case 'Numb': printf("Number \"%s\"",buff); break;
  default : ;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256