【问题标题】:switch statement using string in C [duplicate]在C中使用字符串的switch语句[重复]
【发布时间】:2011-11-28 22:23:29
【问题描述】:

可能重复:
C/C++: switch for non-integers
C/C++ switch case with string

我将字符串传递给函数 get_band(char *str) 然后我将传递的参数与特定的字符串进行比较

if(strcmp(str, "auto"))
{
  //do something
}

我的问题是 - 因为我有很多要比较的字符串,我如何使用 switch 语句而不是 if/else,因为 switch 语句只支持整数类型。

【问题讨论】:

  • 请注意,当 str 与 'auto' 不匹配时,您的语句将执行 'do something'
  • 计算一些字符串的哈希值?
  • @KevinDTimm 很好地抓住了那里脱帽
  • 还要注意 strcmp 返回 -1、0 和 1 - 当 str 在词法上小于、等于或大于“auto”时

标签: c switch-statement


【解决方案1】:

简短的回答:你不能。

长答案:此问题与C/C++ switch case with string 重复。

【讨论】:

  • 我同意重复,尽管链接的答案指定了一个哈希值。这是标记字符串的一种方法,但不是最好的恕我直言,除非您准备好处理冲突(即两个字符串散列到相同的值)。
  • 添加 Ben Voigt 的建议,更多关于标记字符串的信息。您可以考虑使用词法分析器,例如 flex(1),轻松将字符串流转换为标记流,因为可以轻松打开此类标记。
【解决方案2】:

你可以这样做:

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

char *words[] = {"one", "two", "four"}; // words is an array of pointers to char

void f(char *str);

int main(void) {
    f("two");
    return 0;
}

void f(char *str) {

    int i;
    for (i = 0; i < sizeof words/sizeof words[0]; i++) {
        if (!strcmp(str, words[i])) {
            /* Do something */
        }
    }
}

【讨论】:

  • 适合模拟默认,也适合我的情况。顺便说一句,似乎char *words 应该有一个[]
【解决方案3】:

不,switch 仅适用于整数。

如果你想优化,你可以使用一些数据结构来确定字符串是否是任何已知的字符串。例如:

要使用这样的数据结构,给每个已知字符串分配一个常量整数(例如定义或枚举);给定一个字符串,您可以使用数据结构将其映射到某个数字的已知字符串(可能某个数字表示“未知”)。 然后你可以在这个数字上使用一个开关,并为每种情况做任何你想做的事情。

您可以找到上述任何一个的现有实现,但如果您是 C 新手,那么自己实现它可能会有所帮助。

【讨论】:

  • @Macmade:你错了。参见 C99 标准,6.8.4.2:“switch 语句的控制表达式应具有整数类型。”
  • switch语句的控制表达式应该是integral类型。
  • @Macmade:不,它说 integer。我已经将它从 PDF 中粘贴出来了。请至少在声称我错了之前阅读它。
  • 啊,我想我们都是对的:)
  • ; ) 没什么大不了的......祝你有美好的一天
【解决方案4】:

switch 语句基于对以下表达式的求值进行分支。

在您的情况下, strcmp 只承诺返回小于零、零或大于零。即使您假设这意味着 -1、0 和 1(分别),这也意味着您在 switch 案例中只能选择 3 个值。 [顺便说一句,这不是一个安全的假设......]

相反,如果您的字符串取自一组封闭的字符串(即只能有一组值),您可以对字符串进行标记。实际上有程序可以为您执行此操作,即将字符串转换为标记。 (请参阅 flex(1)。)这意味着您期望的每个字符串都有一些唯一值,您可以打开该值。

如果这样太麻烦,就使用你在问题中使用的方法,即:

if (strcmp("some string", str) == 0) {
   // handle some string
} else if strcmp("some other string", str) == 0) {
   // handle alternate case here

...

} else {
   // handle error/default case here
}

【讨论】:

  • 您可能应该在其中一个相关问题中添加一个关于词法分析器(通常是离散有限自动机)的答案,因为这是一个完全重复的问题,它很快就会被扔进历史的垃圾箱。
【解决方案5】:

考虑更改程序的逻辑以使用枚举而不是字符串。然后,您可以使用数组查找将整数枚举映射到相应的字符串以进行显示和记录。其他选项包括 hash 等都已经介绍过了。

【讨论】:

    【解决方案6】:

    C/C++ 中的 switch 语句只接受三种 case 类型:整数、字符和枚举数据类型(这实际上是整数的另一种说法)。当评估为 ascii 代码时,字符也会减少为整数。

    @Nikolai N Fetissov 提出了一个很好的建议:打开字符串的哈希:

    #define hashOfString1 <integer hash goes here>
    #define hashOfString2 <integer hash goes here>
    #define hashOfString3 <integer hash goes here>
    
    . . .
    
    switch (hashMyString("MyString")) {
      case hashOfString1:
        /* do this */
        break;
      case hashOfString2:
        /* do that */
        break;
      case hashOfString3:
        /* do other */
        break;
      default:
        /* default behavior */
        break;
    }
    

    【讨论】:

    • 这是错误的,你需要在这里处理哈希冲突,例如在每种情况下,“if (strcmp(string, ThisString)) goto default;”。此外,如果任何已知字符串具有相同的哈希值(不太可能),它将根本不起作用。
    • 只要你说出哈希这个词,你就会意识到哈希冲突的可能性是非零的,这就是为什么你选择一个哈希,与输入数字相比,它在一个非常大的空间中分配输入。我实现这一点的方式甚至在程序编译之前就捕获了冲突(如果 Angel 在定义哈希值之前检测到相同的哈希,他们可以尝试备用哈希)。
    • 当然可以提前处理已知单词哈希之间的冲突。但对我来说,要确保对于给定的已知 String1,没有 no 具有相同哈希的其他字符串(任何,不仅仅是一个已知字符串)似乎要困难得多。对于任意散列函数,这是不可能的,因为您必须检查无限数量的字符串。我猜你需要一种特殊的散列函数,可以提前避免这些冲突。尽管如此,假设已知字符串之间的冲突已得到解决,在每个案例之后添加一个简单的检查将使其正确。
    猜你喜欢
    • 2013-04-06
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    相关资源
    最近更新 更多