繁体   English   中英

在数组上使用字符串的 switch 语句

[英]Switch statement using string on an array

#include<stdio.h>

int main(){

    char name[20];

    printf("enter a name ");
    scanf("%s",name);
    switch(name[20]){
        case "kevin" : 
        printf("hello");
        break;
    }
    printf("%s",name);
    getch();
}

看来是行不通了。 这可能吗? 我的意思是有什么办法可以让一个字符串的 switch 语句。 如何解决问题,实际上?

C 中的 switch 语句不像在其他语言(例如 Java 7 或 Go)中发现的那样智能,您不能在字符串上切换(也不能将字符串与==进行比较)。 Switch 只能对整数类型( intchar等)进行操作。

在您的代码中,您使用以下命令调用 switch: switch(name[20]) 这意味着switch(*(name + 20)) 换句话说,打开 name 中的第 21 个char (因为name[0]是第一个)。 由于name只有 20 个字符,因此您正在访问名称后的任何内存。 (这可能会做不可预测的事情)

此外,字符串"kevin"被编译为包含字符串的char[N] (其中Nstrlen("kevin") + 1 )。 当你做case "kevin" 仅当 name 位于存储字符串的完全相同的内存中时,它才会起作用。 因此,即使我将kevin复制到名称中。 它仍然不会匹配,因为它存储在不同的内存中。

要做您似乎正在尝试的事情,您可以这样做:

#include <string.h>
...
    if (strcmp(name, "kevin") == 0) {
        ...
    }

字符串比较 ( strcmp ) 根据字符串的差异返回不同的值。 例如:

int ord = strcmp(str1, str2);
if (ord < 0)  
    printf("str1 is before str2 alphabetically\n");
else if (ord == 0) 
    printf("str1 is the same as str2\n");
else if (ord > 0)  
    printf("str1 is after str2 alphabetically\n");

旁注:不要以那种形式使用scanf("%s", name) 它创建了一个常见的安全问题,使用fgets是这样的:(也有一种使用scanf的安全方法)

#define MAX_LEN 20
int main() { 
    char name[MAX_LEN]; 
    fgets(name, MAX_LEN, stdin);
    ...

Switch 语句适用于int值(或enum ),但不适用于char数组。

你可以做

if (strcmp(name, "kevin")==0) {
    printf("hello");
}
else if (strcmp(name, "Laura")==0) {
    printf("Allo");
}
else if (strcmp(name, "Mike")==0) {
    printf("Good day");
}
else  {
    printf("Help!");
}

有很多方法可以解决这个问题! 例如,使用一个...

3 个字母的哈希

#include <stdio.h>

int main(){

    char name[20];

    printf("enter a name ");
    scanf("%s",name);
    switch((int)*name * (int)*(name+1) * (int)*(name+2)){
          case (1275226) : // "kevin"
            printf("hello %s.\n", name);
            break;
          case (1293980) : // "astro"
            printf("welcome %s.\n", name);
            break;
    }
    printf("%d",(int)*name * (int)*(name+1) * (int)*(name+2));
}

不,您不能将 C 中的switch语句与字符串或字符数组的值一起使用。 最接近的替代方法是使用某种数据结构映射字符串到函数指针。 可以在使用字符串查找后调用函数指针。

记住使用switch语句时的规则。

开关约束

1. switch 语句的控制表达式必须具有“整数类型”。

2 、每个case标签的表达式必须是整数常量表达式,并且同一个switch语句中的两个case常量表达式转换后的值不能相同。 switch 语句中最多可能有一个默认标签。

3.任何封闭的 switch 语句都可能有一个默认标签或 case 常量表达式,其值与封闭的 switch 语句中的 case 常量表达式重复。

由于名称被声明为字符类型,如果在scanf()方法中使用"%c"而不是使用"%s"会更好。

您可以使用“hash-string.h”库将字符串转换为哈希码整数。 创建一个头文件并粘贴此代码: http : //www.opensource.apple.com/source/gcc/gcc-5484/intl/hash-string.h

#include <stdio.h>
#include <stdlib.h>
#include "hash-string.h"

int main(){

  char name[20];

  printf("Enter a name: ");
  scanf("%s",name);

  unsigned long nameInt = hash_string(name);

  switch(nameInt){
    case 7458046 /* "kevin" */: { printf("Hello %s", name); break; }
    default: { printf("You are not kevin"); }
  }

  printf("\n");
  return 0;
}

如果您在对特定字符串执行特定操作之后,这意味着您事先知道这些字符串。 这反过来意味着它们的数量是有限的,是可数的,例如一组 N 个命令:

const char * commands[] = {
 "command-1",
 "command-2",
 ...
 "command-N"

}

要使用 swtich 从您的代码中处理上面数组中的那些命令,您需要知道它们的索引,这很容易出错。 所以给他们编号,给他们一个ID:

enum Command_id {
  NO_COMMAND,
  COMMAND_1,
  COMMAND_2,
  //...
  COMMAND_N,
};

现在使用结构将上面的两个放在一起:

struct Command_info {
  const char * command;
  enum Command_id id;
} command_infos[] = {
  {"", NO_COMMAND},
  {"command-1", COMMAND_1},
  {"command-2", COMMAND_2},
  // ...
  {"command-N", COMMAND_N},
};

现在您有了很好的字符串及其相关 ID 的映射。 为了能够在运行时从字符串映射到 ID,需要搜索上面的映射。 要以有效的方式执行此操作,您需要我们进行二分搜索。 C 库为此证明了bsearch() 唯一的先决条件是要搜索的数组需要排序。

排序使用qsort()也由 C 库证明。 为了让qsort()工作,我们需要一个比较函数:

int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
  const struct Command_info * pCI1 = pvCI1;
  const struct Command_info * pCI2 = pvCI2;

  return strcmp(pCI1->command, pCI2->command);
}

像这样调用qsort()

qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);

现在当数组被排序时,可以使用bsearch()查找它。 对于“COMMAND-2”,它看起来像这样:

    ... = bsearch(&(struct Command_info){"COMMAND-2", NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);

将所有这些放在一起可能会导致:

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


enum Command_id {
  NO_COMMAND,
  COMMAND_1,
  COMMAND_2,
  //...
  COMMAND_N,
};

struct Command_info {
  const char * command;
  enum Command_id id;
} command_infos[] = {
  {"", NO_COMMAND},
  {"command-1", COMMAND_1},
  {"command-2", COMMAND_2},
  // ...
  {"command-N", COMMAND_N},
};


int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
  const struct Command_info * pCI1 = pvCI1;
  const struct Command_info * pCI2 = pvCI2;

  return strcmp(pCI1->command, pCI2->command);
}


int main(int argc, char ** argv)
{
  qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);


  {
    enum Command_id command_id = NO_COMMAND;
    struct Command_info * pCI = bsearch(&(struct Command_info){argv[1], NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);

    if (NULL == pCI)
    {
      printf("Command = '%s' is unknown\n", argv[1]);
    }
    else
    {
      printf("Command = '%s' --> ID = %d\n", pCI->command, pCI->id);


      switch(command_id)
      {
        case COMMAND_1:
          /* perform action on COMMAND 1 here */
          break;

        case COMMAND_2:
          /* perform action on COMMAND 1 here */
          break;

        default:
          /* unknow command, do nothing */
          break;
      }
    }
  }
}

像这样称呼它:

./a.out command-1

给予:

Command = 'command-1' --> ID = 1

要么:

./a.out command-bla

给予:

Command = 'command-bla' is unknown

甚至

./a.out ""

给予:

Command = '' --> ID = 0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM