Is there any way to simplify this statement?

69 views Asked by At

Is there a way I can reduce the number of lines of code with this switch statement? Could I use a for loop but without reassigning the ci value? Or is this the most optimized it will get in terms of assignment based on logical expression?

char ci, co;
while (fscanf(fp1, "%c", &ci) != EOF) {
    switch(ci) {
        case 97:
            co = 33;
            break;
        case 98:
            co = 34;
            break;
        case 99:
            co = 35;
            break;
        case 100:
            co = 36;
            break;
        case 101:
            co = 37;
            break;
        case 102:
            co = 38;
            break;
        case 103:
            co = 39;
            break;
        case 104:
            co = 40;
            break;
        case 105:
            co = 41;
            break;
        case 106:
            co = 42;
            break;
        case 107:
            co = 43;
            break;
        case 108:
            co = 44;
            break;
        case 109:
            co = 45;
            break;
        case 110:
            co = 46;
            break;
        case 111:
            co = 47;
            break;
        case 112:
            co = 48;
            break;
        case 113:
            co = 49;
            break;
        case 114:
            co = 50;
            break;
        case 115:
            co = 51;
            break;
        case 116:
            co = 52;
            break;
        case 117:
            co = 53;
            break;
        case 118:
            co = 54;
            break;
        case 119:
            co = 55;
            break;
        case 120:
            co = 56;
            break;
        case 121:
            co = 57;
            break;
        case 122:
            co = 58;
            break;
        case 48:
            co = 59;
            break;
        case 49:
            co = 60;
            break;
        case 50:
            co = 61;
            break;
        case 51:
            co = 62;
            break;
        case 52:
            co = 63;
            break;
        case 53:
            co = 64;
            break;
        case 54:
            co = 65;
            break;
        case 55:
            co = 66;
            break;
        case 56:
            co = 67;
            break;
        case 57:
            co = 68;
            break;
        case 32:
            co = 69;
            break;
        case 10:
            co = 70;
            break;
        case 13:
            co = 71;
            break;
        default:
            break;
    }
    fprintf(fp2, "%c", co);
}
5

There are 5 answers

0
BLUEPIXY On

reduce switch

switch(ci) {
    case 97:
    case 98:
    case 99:
    case 100:
    case 101:
    case 102:
    case 103:
    case 104:
    case 105:
    case 106:
    case 107:
    case 108:
    case 109:
    case 110:
    case 111:
    case 112:
    case 113:
    case 114:
    case 115:
    case 116:
    case 117:
    case 118:
    case 119:
    case 120:
    case 121:
    case 122:
        co = 33 + (ci - 97);
        break;
    case 48:
    case 49:
    case 50:
    case 51:
    case 52:
    case 53:
    case 54:
    case 55:
    case 56:
    case 57:
        co = 59 + (ci - 48);
        break;
    case 32:
        co = 69;
        break;
    case 10:
        co = 70;
        break;
    case 13:
        co = 71;
        break;
    default:
        break;
}
0
BrunoLoops On

Maybe using some ifs:

if(ci>96){

   co=ci-64;

}elseif(ci>47){
   co=ci+11;
}elseif(ci==32){
   co=69;
}elseif(ci==10){
   co=70;
}elseif(ci==13){
   co=71;
}

Is cleaner than the other code. Try just to agrup the cases that are equal by computing.

0
Bill Tarbell On

This is more succinct by breaking the checks into the patterned ranges that i saw in your cases.

if (ci >= 97 && ci <= 122){
  co = 33 + (ci - 97);
}
else if (ci >= 48 && ci <= 57){
  co = 59 + (ci - 48);
}
else if (ci == 32){
  co = 69;
}
else if (ci == 10){
  co = 70;
}
else if (ci == 13){
  co = 71;
}
6
rost0031 On

Use if/else to group the several patterns you have. So:

char ci, co;
while (fscanf(fp1, "%c", &ci) != EOF) {
    if ( ci => 97 && ci <= 122 ) {
        co = ci - 64;
    } else if ( ci => 48 && ci <= 57) {
        co = ci + 11;
    } else if ( ci == 32 ) {
        co = 69;
    } else if ( ci == 10 ) {
        co = 70;
    } else if ( ci == 13 ) {
        co = 71;
    } else {
        printf("Unhandled case: ci = %d\n", ci);
    }
    fprintf(fp2, "%c", co);
}

Edit: added the rest of the cases.

1
John Bollinger On

As others have already observed, you can leverage the functional relationship between your switch value and your output value. Even better, however, would be to use a lookup table:

#include <limits.h>
#include <stdio.h>

void f() {
    static const unsigned char table[256] = {
        0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  70,  11,  12,  71,  14,  15,
       16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
       69,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
       59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  58,  59,  60,  61,  62,  63,
       64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
       80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
       96,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
       48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58, 123, 124, 125, 126, 127,
      128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
      144, 145, 146, 147, 148, 149, 150, 151, 152, 123, 154, 155, 156, 157, 158, 159,
      160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
      176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
      192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
      208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
      224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
      240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
    };
    char ci, co;
    while (fscanf(fp1, "%c", &ci) != EOF) {

#if CHAR_MIN < 0
        /* default char is signed -- watch out for negative values! */
        unsigned char uc = table[(unsigned char) ci];
        co = (uc <= CHAR_MAX) ? uc : (uc - (UCHAR_MAX + 1));
#else
        /* default char is unsigned -- all clear */
        co = table[ci];
#endif

        fprintf(fp2, "%c", co);
    }
}

Overall, it's not quite as short as some of the alternatives, but it's lightning-fast, especially on systems that have unsigned default chars. Of course, if you count only the loop body then you can hardly get any shorter.

Note, by the way, that your original code produces undefined behavior for many possible values scanned from the file, because it only sets co for certain values of ci, but it reads that value in every case. Until you set it at least once, you should not read its value. Even after you do set its value once, it seems surprising that you would actually want to possibly carry that value over in the next loop iteration. The lookup table version, on the other hand, always sets co, often to the same value as ci.

Note that this does depend on UCHAR_MAX to be 255 (or less); if it is larger then table lookups can access past the end of the table. You could work around that with programmatic initialization of the lookup table, if you were actually concerned about your code running on a machine on which unsigned char has more than 8 bits.