有没有办法(在 C 中)编写类似switch
语句的构造,但用于字符串?有没有办法在 C 中编写 C构造?
C 构造是指带有大括号的语句……就像语句带有大括号一样if
,它是 C 构造……对吗?
有没有办法(在 C 中)编写类似switch
语句的构造,但用于字符串?有没有办法在 C 中编写 C构造?
C 构造是指带有大括号的语句……就像语句带有大括号一样if
,它是 C 构造……对吗?
不,你必须自己做。有很多变种:
if (strcmp(str, "toto") == 0)
{
// ...
}
else if (strcmp(str, "tata") == 0)
{
// ...
}
else
{
// ...
}
如果字符串的数量预计会增长,那么带有函数指针的调度表
struct dispatch_entry
{
const char *key;
void (*action)(void);
};
// Make sure it is sorted !
dispatch_entry dispatch_table[] =
{
{ "tata", &action_tata },
{ "toto", &action_toto },
};
再加上二分查找:
int dispatch_compare(const void *x, const void *y)
{
const dispatch_entry *xx = x, *yy = y;
return strcmp(xx->key, yy->key);
}
// Return -1 on failure
int dispatch(const char *str)
{
static const size = sizeof(struct dispatch_entry);
static const n = sizeof(dispatch_table) / size ;
dispatch_entry tmp = { str, NULL };
dispatch_entry *what = bsearch(tmp, dispatch_table, n, size, &dispatch_compare);
if (what == NULL) return -1;
(*what->action)();
return 0;
}
会做。基于哈希表的方法也可以。
最简单的方法是使用 if-else 链进行strcmp
比较:
if (strcmp(str, "String 1") == 0)
// do something
else if (strcmp(str, "String 2") == 0)
// do something else
else if (strcmp(str, "String 3") == 0)
// do something else
...
else
printf("%s not found\n", str);
更复杂的方法是使用查找表,以字符串为键:
struct lookup {const char *key; int value};
struct lookup LookupTable[] = {
{"String 1", 1},
{"String 2", 2},
{"String 3", 3},
...
{NULL, -1}
};
int lookup(const char *key)
{
size_t i = 0;
while (LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].value;
else
i++;
return -1;
}
...
switch(lookup(str))
{
case 1: ...
case 2: ...
case 3: ...
...
default: printf("%s not found\n", str); break;
}
如果您想真正花哨,可以修改查找表,使值是指向函数的指针:
void String1Cmd(void) { ... }
void String2Cmd(void) { ... }
void String3Cmd(void) { ... }
...
void BadCmd(void) { printf("Key not found!\n"); }
struct lookup {char *key, void (*cmd)(void); };
struct lookup LookupTable[] = {
{"String 1", String1Cmd},
{"String 2", String2Cmd},
{"String 3", String3Cmd},
...
{NULL, BadCmd}
};
void (*lookup(const char *str))(void)
{
size_t i = 0;
while(LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].cmd;
else
i++;
return BadCmd;
}
...
void (*f)(void) = lookup(str); // retrieve the function for the given string
f(); // execute the function
在最后一个例子中,if str
== "String 1", thenString1Cmd
将被执行。如果str
是在查找表中找不到的字符串,BadCmd
则将执行。这种方法非常灵活,并且根据您的设计,允许您在运行时添加行为(一种插件架构)。
但是,请注意,我们刚刚将主要问题 - 在字符串值上分支 - 推迟到lookup
函数,并且lookup
函数返回到只strcmp
针对表中的每个值执行操作。我们可以通过使用哈希表或树来加速这部分过程,以最大限度地减少比较次数。根据您要分支的字符串数量,这可能值得也可能不值得付出额外的努力。
如果你的库(POSIX 或 gcc)中有函数lfind,你可以像这样使用它:
enum { NOTFOUND, HELLO, WORLD, FOO, BAR };
char list[][100]={"hello","world","foo","bar"};
size_t r, siz = sizeof*list, num = sizeof list/siz;
char *tosearch = "foo";
switch ( (r=lfind(tosearch,list,&num,siz,strcmp))?
(r+siz-(size_t)list)/siz:0 ) {
case HELLO: puts("hello");break;
case WORLD: puts("world");break;
case FOO: puts("foo"); break;
case BAR: puts("bar"); break;
case NOTFOUND:puts("not found");
}
数组中的每个字符串必须具有相同的大小,并且不应该是指针
如果您有大量字符串并且速度是一个问题,则使用哈希表
不可以,因为该开关只能与整数类型或可转换为整数类型的类型一起使用
是的,方法是 - 长if-else-if
声明。(供参考:为什么switch语句不能应用于字符串?)
您所说的“C 中的 C 构造” oO 是什么意思?当你回答时,我会编辑我的帖子:)
不,switch
适用于整数值(我认为甚至不允许浮点数/双精度数)。你可以用 if/else if/else doing 来模仿strcmp
。
if (strcmp(mystr, "this") == 0) {
//mystr == "this"
}
else if (strcmp(mystr, "that") == 0) {
//mystr == "that"
}
else {
//mystr is not "this" or "that"
}
当然,这取决于你愿意做多少工作。
您可以使用预处理器和一些宏将字符串映射到整数标识符,为您提供如下语法:
switch (SOSID_LOOKUP (sample_string)) {
case SOSID (hello): printf ("Hello "); break;
case SOSID (world): printf ("World! "); break;
case 0: default: printf ("unknown "); break;
}
如果您可以使用 C++ 而不是 C,则可以使用litb 的 基于模板的字符串切换器,为您提供如下语法:
sswitch(s) {
scase("foo"): {
std::cout << "s is foo" << std::endl;
break; // could fall-through if we wanted
}
// supports brace-less style too
scase("bar"):
std::cout << "s is bar" << std::endl;
break;
// default must be at the end
sdefault():
std::cout << "neither of those!" << std::endl;
break;
}