转换冗长的if ... else if ... else ... block to switch

时间:2014-05-16 03:20:11

标签: c if-statement switch-statement

我正在学习C.对于课堂练习,我尝试使用if... else if... else...语句将冗长的switch块转换为更高效的C代码。有两个问题:

  1. 代码必须保持对/-的支持,并且还必须支持/c/c.abc的可变长度,其中.和任何内容以下是可选的。
  2. char *argv[]可以接受unix文件路径。
  3. 现有的块看起来像这样:

    #include <strings.h>
    
    int main(int argc, char* argv[])
    {
        int i;
    
        for (i=1; i<argc; i++)
        {
            if (!strcasecmp(argv[i], "/a") || !strcasecmp(argv[i], "-a"))
                /* Do something */
            else if (!strcasecmp(argv[i], "/b") || !strcasecmp(argv[i], "-b"))
                /* Do something */
            else if (!strncasecmp(argv[i], "/c", 2) || !strncasecmp(argv[i], "-c", 2))
                /* Do something */
            else if (!strcasecmp(argv[i], "/d") || !strcasecmp(argv[i], "-d"))
                /* Do something */
            else if ((argv[i][0] == '/' || argv[i][0] == '-') && (!argv[i][2] || argv[i][2] == '.'))
            {
                /* Error message */
                return 1;
            }
        else
        {
            /* For unix filepaths. */
        }
        return 0;
    }
    

    我最初的想法是在switch上使用argv[i][1]来避免/-问题。例如:

    if ((argv[i][0] == '/' || argv[i][0] == '-') && (!argv[i][2] || argv[i][2] == '.'))
    {
        switch(argv[i][1])
        {
        case 'a':
            /* Do something */
            break;
        case 'b':
            /* Do something */
            break;
        case 'c':
            /* Do something and process any characters after the . */
            break;
        case 'd':
            /* Do something */
            break;
        default:
            /* Error message */
            return 1;
        }
    }
    else
    {
        /* Unix filepaths and anything else. */
    }
    

    到目前为止,switch完成了大部分任务。不幸的是,声明if ((argv[i][0] == '/' || argv[i][0] == '-') && (!argv[i][2] || argv[i][2] == '.'))也会接受无效的标记,例如/a.

    /c移除可变长度的案例(例如/c.abcswitch)是另一种可能性,但后来我不确定如何确保其他案例有字符串长度为两个字符,但不接受/c有效。

    是否有更好或更有效的方法将if... else if... else...块转换为switch

    感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

可以通过一次仅考虑argv[i]的一个字符来完成:

#include <strings.h>

int main(int argc, char* argv[])
   {
   int i;

   for (i=1; i<argc; i++)
      {
      switch(argv[i][0])
         {
         case '/':
         case '-':
            switch(argv[i][1])
               {
               case '\0':
                  /* No further characters in argv[i]; Do something? Print error? */
                  /* As per suggestion of @Mohit Jain. */
                  break;

               case 'a':
                  /* Do something */;
                  break;

               case 'b':
                  /* Do something */;
                  break;

               case 'c':
                  /* Do something */;
                  break;

               case 'd':
                  /* Do something */;
                  break;

               default:
                  if(!argv[i][2] || ('.' == argv[i][2])) // a little danger here...
                     {
                     /* Error message */
                     return 1;
                     }
                  else
                     {
                     /* For unix filepaths. */
                     }
                  break;
               }
            break;

         default:
            /* Error message */
            return 1;
         }
      }

   return 0;
   }

答案 1 :(得分:0)

在你的用例中,我不认为你会通过拥有来节省很多工作 一个开关,特别是当你添加错误处理

首先尝试将工作分解为功能以使您的主要功能 更具可读性

执行一个检查语法的函数,例如

int syntaxOk(char* arg)
{
  if ( (strlen(arg) < 2) // too short
     || (arg[0] != '-' && arg[0] != '/') // invalid format
  {
    printSyntax();
    return 0;
  }
  return 1;
}

和一个写可用语法的函数

void printSyntax()
{ ... }
在你的主要文件中,有一个参数的ptr,使其更具可读性:

char* arg = argv[i];

现在将实际命令char转换为小写(ctype.h)

int ch = tolower( arg[1] );

您可能需要提取可选的变长命令 所以有一个缓冲区我们可以把它放在那里,比如在&#39; c&#39;所以 一个功能

int doC(char* argv)
{
  size_t len = strlen(argv);
  if ( len > 2 && arg[2] == '.' )
  {
    char cOption[64] = {0};
    strncpy(cOption, arg + 3, sizeof(cOption));
    // do something
    return 1;
  }
  else if ( len == 2 )
  {
    // do something else?
    return 1;
  }
  else
  {
    printSyntax();
    return 0;
  }
}

你可以动态地使cOption取决于参数的大小,但我留给你试试。例如char* cOption = malloc(len+1);而不是固定大小或取决于您的编译器版本,您可以使用可变大小的数组。

然后你的switch语句看起来像这样:

switch (ch)
{
  case 'a': 
    doA();
    break;
  case 'b':
    doB();
    break;
  case 'c': 
    if (!doC(argv))
    {
      printSyntax();
    }
    break;
  case 'd':
    doD();
    break;
  default:
    printSyntax();
    break;
}