2014-05-16 2 views
1

저는 C를 배우고 있습니다. 수업 연습을 위해, 길이가 긴 if... else if... else... 블록을 다음 코드를 사용하여보다 효율적인 C 코드로 변환하려고합니다. switch 문. 이 코드는 / 또는 -에 대한 지원을 유지해야하며, 또한 그것을 다음 . 무엇이든은 선택 /c, /c.abc의 가변 길이를 지원해야합니다만약 ... else if ... else ... 스위치를 차단하십시오.

  1. 두 가지 문제가 있습니다.
  2. char *argv[]은 유닉스 파일 경로를 허용 할 수 있습니다.

기존 블록은 다음과 같습니다

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

내 초기 생각은 / 또는 - 문제를 방지하기 위해 argv[i][1]switch를 사용하는 것이 었습니다. 예 :

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.과 같은 잘못된 플래그를 허용합니다. switch에서 가변 길이의 경우 (예를 들어, /c 또는 /c.abc)를 제거

은 또 다른 가능성이다, 그러나 나는 또한 유효한 /c을 적용하지 않고 다른 경우는 두 문자의 문자열 길이가 있는지 확인하는 방법을 모르겠어요.

if... else if... else... 블록을 switch 블록으로 변환하는 더 효과적인 방법이 있습니까?

도움을 주시면 감사하겠습니다.

+1

정확히를 elses 멀리 경우에서 이동하려고하는 이유는 무엇입니까? 스위치가 더 효율적이지만 유스 케이스에 맞지 않습니다. –

+0

'을 허용하지 않는 스위치에 대해서만 첫 번째 경우를 확인하여'(! argv [i] [2] || argv [i] [2] =='. ')))'를 대체하십시오. –

+1

getopt : http://man7.org/linux/man-pages/man3/getopt.3.html – kvanberendonck

답변

0

만들기 위해 기능으로 작업을 분할하는 첫 번째 시도 오류 처리 메인 더 읽기

구문 등을 검사 한 기능을 수행

char* arg = argv[i]; 

이제 실제 명령을 변환 :

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

하나 개의 기능은 더 읽을 수 있도록 인수에 PTR을 가지고, 기본에 사용할 수있는 구문

void printSyntax() 
{ ... } 

쓰기 char를 소문자로 변환합니다 (ctype.우리가 'C'에서처럼, 그것을 넣을 수있는 그래서 버퍼를 가지고있는 옵션 가변 길이 명령 를 추출해야 할 수 있습니다

int ch = tolower(arg[1]); 

시간이) 너무

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 (ch) 
{ 
    case 'a': 
    doA(); 
    break; 
    case 'b': 
    doB(); 
    break; 
    case 'c': 
    if (!doC(argv)) 
    { 
     printSyntax(); 
    } 
    break; 
    case 'd': 
    doD(); 
    break; 
    default: 
    printSyntax(); 
    break; 
} 
+0

와우. 따라서 'if ... else if ... else ...'문을 사용하는 것을 피할 수는 있지만 실제로는 그렇게 실용적이지 않습니다. 자세한 답변을 해 주셔서 감사합니다. –

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'의 대소 문자를 사용하면 위험을 피할 수 있습니다. –

+0

좋은 조언을 주셔서 감사합니다 @MohitJain. 이 기능을 추가하기위한 답을 편집했습니다. –

+0

@MahonriMoriancumer 매우 인상적입니다. 이제 왜 'if ... else if ... else ...'블록을 사용하면 효율이 약간 떨어졌음에도 불구하고이 작업이 더 쉬워 졌는지 이해할 수 있습니다. –

관련 문제