【问题标题】:Switch Case in c++ [duplicate]C ++中的切换案例[重复]
【发布时间】:2013-05-23 18:38:57
【问题描述】:

如何使用 switch-case 比较 C++ 中的字符数组? 这是我的代码的一部分:

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

我收到错误:“错误:开关量不是整数”。我该如何解决?

【问题讨论】:

标签: c++ switch-statement


【解决方案1】:

如果你真的需要一个 switch 语句,你需要将你的 buff 变量转换为一个整数。为此,您可以使用哈希函数或std::map

简单的方法是创建一个std::map<std::string,int>,其中包含您要在与唯一int 值关联的开关中使用的键。你会得到类似的东西:

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

std::map 方法可读性很强,不会引起太多混乱。

【讨论】:

  • 我喜欢这个。可能超出了他对作业的理解程度,但它解决了问题并使用了 switch 语句 - 不错!
  • 最好在取消引用之前添加一个检查 .find() 不是结束迭代器。
  • @MooingDuck 在实践中,是的。我在这里选择简洁来说明基本思想。在部署之前需要进行一些打磨。
  • +1 最佳策略,虽然我个人更喜欢使用“枚举”。
【解决方案2】:

您不能将数组用作 switch 构造中的表达式。

【讨论】:

  • 是的,你可以:char buf[256];开关(buf[0]){} ...
  • 您仍在开关中使用直字符。使用数组和使用数组元素不是一回事。
  • 我在 switch 构造中使用了一个数组。只需稍微改一下你的答案,我就很满意了。事实上,听起来任何数组的使用都是禁止使用的。
  • 谢谢你,先生 :)
【解决方案3】:

在 C++ 中,case 语句需要一个常量整数值,并且不能与在运行时计算的值一起使用。但是,如果您使用的是 C++11,则可以使用 constexpr 函数生成 casesimulate 使用带有 case 语句的字符串。

这使用了一个哈希函数,它接受一个指向字符串的指针并在编译时而不是运行时生成一个值。如果多个字符串生成相同的值(哈希冲突),您会收到熟悉的错误消息,即多个 case 语句使用相同的值。

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

djb2Hash 函数可以直接在switchcase 语句中使用。但是有一个警告,散列函数可能在运行时导致冲突。发生这种情况的概率主要取决于散列函数的质量。此处介绍的解决方案并未尝试解决此问题(但可能会在未来解决)。

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

这很好用,但可能会被认为。您可以通过声明处理调用哈希函数的用户定义文字来进一步简化此操作。

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

这在 switch 语句中提供了更直观的字符串用法,但由于用户定义的文字,也可能会被认为有点混乱。

[编辑:添加了关于运行时哈希冲突的注释。非常感谢R. Martinho Fernandes 引起我的注意!]

【讨论】:

  • 编译时的冲突并不是最大的问题。运行时的碰撞是。 DoSomething("CollidesWithHello")?
  • @R.MartinhoFernandes 是的,可能会发生源自条件的冲突——还没有完全解决它的这方面问题。我会更新答案以说明这一点。
  • 重点是你无法摆脱它。
  • @R.MartinhoFernandes 使用std::map 获取条件值可以解决问题。我还不是特别热衷于这个想法,但它似乎是避免运行时冲突的合适权衡。
  • 我在这里解决了:stackoverflow.com/questions/4165131/c-c-switch-for-non-integers/…。诀窍是您必须检查匹配字符串case "World"_C: if( strcmp(str,"World") ){SayWorld(); break;} 是否相等。这使得字符串切换宏更具吸引力。
【解决方案4】:

您不能在 switch 语句中使用非整数类型。您的问题需要类似:

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

要获得您正在寻找的结果 - 基本上是一堆 if 语句来替换开关。

【讨论】:

  • char[256] buff; 语法无效。
  • 复制他的代码 - 已修复。
【解决方案5】:

您正在尝试做一些我们都非常希望我们能做的事情,但在 C/C++ 中却不行 :) switch 语句中的 case 必须是整数值。一个简单的替代方法是使用与您要操作的字符串集匹配的枚举。

【讨论】:

  • 我们不希望那样。
【解决方案6】:

在 C++ 中,switch-case 只能用于整数(charint、...),但不能用于 c 字符串(char *

在您的情况下,您必须使用 if-then-else 构造

if (strcmp(buff, "Name") == 0) {
    ...
} else if (...) {
    ...
}

【讨论】:

    【解决方案7】:

    正如错误所说,switch 仅适用于整数。最简单的解决方案是使用if...else if... 测试链。

    但是,使用 char 数组而不是字符串是很尴尬的,因为您需要古怪的 C 风格函数来比较它们。我建议你改用std::string

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

    更复杂的方法,也许将字符串映射到数字以在switch 中使用或映射到要调用的函子,如果您有大量案例,可能会更有效;但在担心此类优化之前,您应该先让简单版本工作。

    【讨论】:

      【解决方案8】:

      与许多其他允许在 switch-case 中使用字符串和其他对象比较的语言不同,c++ 要求基础值是整数。如果您想使用更复杂的对象类型,则必须使用 if else-if 构造。

      【讨论】:

        【解决方案9】:

        对于这种情况,您不能直接使用switch

        通常,您希望使用std::map(或std::unordered_map)来存储与每个输入关联的操作。您可能(例如)使用std::map&lt;std::string, std::function&gt;,然后将函数/函数对象的地址存储在映射中,因此您的最终构造将类似于:

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

        两个注意事项:首先,您可能真的想在第二部分使用map::find,这样您就可以检测何时/如果您要查找的字符串不存在于地图中。

        其次,就目前而言,您的代码似乎没有多大意义——您同时打开buff 并打印出buff 的值,所以(例如)如果您buff包含Number,您的输出将是“数字编号”。我猜你打算使用buff 和其他一些包含你关心的值的变量。

        【讨论】:

          【解决方案10】:

          您可以部分地进行“字符串”比较。

          以下内容并不能特别满足您的查询(因为 C 不会骑那匹小马),也不是优雅的代码,但它的变体可能会满足您的需求。如果您正在学习 C/C++,我不建议您这样做,但这种结构在有限的编程环境中运行良好。
          (我在 PIC 编程中使用它,其中 strlen(buff)==1 或 2 和 sizeof(int)==2。)

          让我们假设 sizeof(int) == 4 和 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 : ;
          }
          

          【讨论】:

            猜你喜欢
            • 2021-11-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-04-20
            • 1970-01-01
            • 2019-12-11
            • 1970-01-01
            相关资源
            最近更新 更多