Link to home
Start Free TrialLog in
Avatar of Khawar091697
Khawar091697

asked on

Restricting the execution of a case block in a switch statement?

Hello,

The scenario is that there is a while loop which terminates on some condition. There is a switch statement in the loop, which has many case statements. I want that every case block should be executed only once and whenever control comes in the already executed case, it should generate error.

Can somebody please write a best suited implementation strategy for this?

Thanks
ASKER CERTIFIED SOLUTION
Avatar of jasonclarke
jasonclarke

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You could also use static 'bool's inside the case statements -- either singular or an array.

static bool arr_blnValues[NUM_OF_CASES];
switch (intMyVal)
{
   case 1:
      {
      if (!arr_blnValues[intMyVal])
         {
         arr_blnValues[intMyVal]=true;
         DoFunctionForThisValue(intMyVal);
         }
       break;
      }
    case 2:
      {
      if (!arr_blnValues[intMyVal])
         {
         arr_blnValues[intMyVal]=true;
         DoFunctionForThisValue(intMyVal);
         }
       break;
      }
    default :
      break;
}
Avatar of Khawar091697
Khawar091697

ASKER

Well, I did consider the bools option, but first thing is I don't want to keep them static, due to the potential multi-threading problems.

Will u pls. comment on keping an integer variable and assigning one bit of that variable for each case. How is this technique... in terms of elegance and efficiency.

Pls. comment in detail

Thanks
Comment from Mr. jasonclarke! is also good. I will definitly consider it in my final decision.

But Mr. jasonclarke can u pls. also comment on my suggetion of using bits for each case.

Thanks.
> Will u pls. comment on keping an integer variable and
> assigning one bit of that variable for each case.
> How is this technique... in terms of elegance and
> efficiency.

in terms of elegance - very poor - in general you should avoid bit twiddling unless there is a real need for it, it is quite error prone and somewhat messy - and what will you do if you get more than 32 elements in your large case statement?  Using bits where some sort of array would do is probably a bad idea.  

in terms of efficiency, it would be fairly efficient.

You should, if you can, avoid a solution that requires work in each element of the switch statement.  This would be an error prone approach - and it seems you can avoid this if I understand the problem correctly.
I'd like to answer from the perspective of someone who doesn't want to get into the abstract containers like std::set in the stl unless its absolutely vital.

This solution uses scoping so that information about doneness is manifestly processed in exactly the same way by each case handler. By using statics you cleanly prevent the doneness flags from ever being reset by accident.

while(condition)
 {
   switch(value)
   {
     case 1:
       static bool done=false;
       if(done){
         cout<<"1 done already ;exit(-1);}
       //Do case 1;
       done=true;
       break;
     case 2:
       static bool done=false;
       if(done){
         cout<<"1 done already ;exit(-1);}
       //Do case 1;
       done=true;
       break;
/...for other cases
   }
}
should of course be

case 2:
                 static bool done=false;
                 if(done){
                   cout<<"2 done already ;exit(-1);}
                 //Do case 2;
                 done=true;
                 break;
>Well, I did consider the bools option, but first thing is >I don't want to keep them static, due to the
>           potential multi-threading problems


Aie!!! sorry.
>>By using statics you cleanly prevent the
>>doneness flags from ever being reset by accident.

Yes, I agree.
I like the array because you can cheaply and easily tell which ones have been done from a higher scope.
> By using statics you cleanly prevent the doneness flags > from ever being reset by accident.

I assumed that they need to be checked each time the loop was entered (or at least more than once).  This solution only allows the check to be made once in the lifetime of the program.

As far as I can see, there is no need to put code in every element case of the switch statement - repeated code is *bad*.

> get into the abstract containers like std::set in the
> stl unless its absolutely vital.

I find this kind of attitude uttely bizarre, but thats your choice, I suppose...



Hmm.. at least my solution *has* a switch statement.

>As far as I can see, there is no need to put code in every >element case of the switch statement - repeated
>code is *bad*.

I find this kind of attitude uttely bizarre, but thats your choice, I suppose...

FORTRAN FOREVER!!!!
I think jasonclarke's solution is very good, but using std::bitset is probably preferable over std::set, since this is really std::bitset's purpose.
I'd just like to pick triskelion up on one thing - with my compiler anyways you've gotta initialize those bools to false, else .. enter the twilight zone
> Hmm.. at least my solution *has* a switch statement.

so did mine, if you bothered to read it...the original switch stament - unchanged from however Khawar has his code at the moment.

The check for already having done a particular case can be done *once* outside the loop - thus avoiding gratuitous repetition of code - but I expect that avoiding gratuitous repetition of code is something you don't want to get into.

> but using std::bitset is probably preferable over std::set

sounds like a good idea, I didn't think of that at the time...
ah yes, found it.. good old Alt-F. Sorry for not spotting that.

I agree with jasonclarke and triskelion that, if you want to check which cases have been done outside the loop, you shouldn't put the doneness flags in the scope of the individual cases, but instead should use one of their solutions.

>>I'd just like to pick triskelion up on one thing -
>> with my compiler anyways you've gotta initialize
>> those bools to false, else .. enter the twilight zone

Making them static (at least with the MS compiler) inits them to (0 / NULL / False).

In either case, you can either init them {false,false,...}
or memset them to NULL if there are a gaggle of them.
memset() may be overkill.
Triskelion,
I just tried for myself, and it looks like what you said is true on my compiler (gcc) as well, static bools are initialized to false. Sorry for being careless, thanks for the info.
I have the following comments:

Triskelions answer is efficient, and of course his list of static bools could be replaced by a non-static list, suitably initialized, because of your thread requirement.
It suffers from the potential drawback, that your case values may not be 1,2,3,4....10 but 1 388888 577311741 3274723 and that then has to be dealt with either by having a huge array or by processing them additionally. Of course that may not be a problem.

jasonclarkes/mnshadkas answer doesn't have that problem, but it is less efficient, since this `find' algorithm (although it's surely well optimized) has to check for doneness by comparing against potentially *all* members of a set. Furthermore, I don't know how a set is implemented but it might well be a linked list, and everyone knows that it's slower to search a linked list than a simple array. (If a set was a simple array then you would performing additional operations with his `insert' command which would have to resize the array using dynamic allocation every time it is invoked.

Which of these solutions you choose depends on how many cases there are and what numbers they correspond to.

If there is any way of detaching a static variable from shared memory so that it is local to each thread, please consider my solution, which doesn't suffer from either of these problems.
Well, that's not a problem... I can avoid abstract containers and use array instead.... But the approach from mr. jasonclarke seems very clean and least error prone....

More comments / suggestions please...
If all of your values are known (even if they're not), you have the option of making a static structure of the values (or an array) and use the offset for the case.

Of course you would have to do the lookup yourself to find the offset, but it's fairly efficient.

Or even better (maybe)...
a static struct that has the bools and values built in.
Flip them when the case has been triggered.

static struct     tagMyValues
{
     int     intValue;
     bool     blnTripped;
}     xaMyValues[]=
     {
          {123, false},
          {24755, false},
          {989, false},
          {1, false},
          {755, false},
          {0, false},
          {-1, false}
     };


int main(void)
{
     xaMyValues[0].blnTripped=true;/*example*/
     return 0;
}
> but it is less efficient, since this `find'
> algorithm (although it's surely well optimized) has to
> check for doneness by comparing against potentially
> *all* members of a set. Furthermore, I don't know how a > set is implemented but it might well be a linked
> list,

no, a set is an ordered container, and as such it is usually implemented using a balanced tree, so look-ups are likely to be fast.  I think there is actually a guaranty in the standard so that set find will have O(logn) or better performance

Regardless, there are not many applications where the difference in performance that the use of set in this way would make the slightest difference.  The usual best practise  approach to performance anyway is do it right first and then optimise where there is a problem.
>from mr. jasonclarke seems very clean and least error >prone..
I'm sorry to disagree but it ain't so clean. I guess you're thinking of using an array of int to store the values as you come across them, instead of stl::set. But you still have to search the whole array each time.. and of course you have to write your own `search' and `insert' procedures. `Insert' operation is harder with a simple array - that's the price you pay for an easier `search'.

Then I have to say that what I would plump for in the end is a modified version of Triskelion/my solution of the following form:

bool flags[max number of cases];
for(...)flags[i]=false;
while(condition)
           {
             switch(value)
             {
               case 475:
                 static const int index=0;
                 if(flags[index]){
                   cout<<index<<"1 done already ;exit(-1);}
                 //Do case 475;
                 flags[index]=true;
                 break;
               case 4435936:
                 static const int index=1;
                 if(flags[index]){
                   cout<<index<<" done already ;exit(-1);}
                 //Do case 4435936;
                 flages[index]=true;
                 break;
           /...for other cases
             }
           }


And, if you were concerned about code replication, you could turn
                 if(flags[index]){
                   cout<<index<<" done already ;exit(-1);}
                 flages[index]=true;
                 break;

into a macro.
#define MACRO if(flags[index]){cout<<index<<" done already ;exit(-1);}flages[index]=true;break;

bool flags[max number of cases];
for(...)flags[i]=false;
while(condition)
{
 switch(value)
 {
   case 475:static const int index=0;MACRO
   case 4347653:static const int index=1;MACRO
   case 643433:static const int index=2;MACRO
   case 936653:static const int index=3;MACRO
   default:break;
 }
}

That's looking better isnt it?
But in this case lots and lots of structure initializations...
Infact the values for the cases are always enumerated values and will be in the range 0 - 300 always...

This is also a good suggestion and i was also considering this too... I was planning to make an array of structs, for each case and check, containing an enum value and a bool value....
I think arrays are not the best solution here.  You should use std::bitset.  I also think that it's a good idea to check the status beforehand, which will allow you to do your check once, rather than in each case, like:

std::bitset<max_number> flags;
while(...)
{
  if(flags.at(value))
  {
    std::cout << "Number already here" << std::endl;
    exit(-1);
  }

  flags.set(value);
  switch(value)
  {
  case 1:
    ...
    break;
  ...
  }
}
mr.khawar - take a look -it's clean and easy to read, its fast and transparent (no stl apart from `cout'). What more could a person want?

I don't know why these guys are recommending the stl routines. They clearly take longer to look stuff up than using an array, which just involves one dereferencing operation.
if you rename MACRO to ERROR_IF_DONE, it is really a masterpiece:
#define ERROR_IF_DONE if(flags[index]){cout<<index<<" done already ;exit(-1);}flages[index]=true;break;

bool flags[max number of cases];
for(...)flags[i]=false;
while(condition)
{
  switch(value)
  {
    case 275:static const int index=0;ERROR_IF_DONE
    case 43:static const int index=1;ERROR_IF_DONE
    case 134:static const int index=2;ERROR_IF_DONE
    case 253:static const int index=3;ERROR_IF_DONE
    default:break;
  }
}
glebspy,
The bitset is usually implemented as an array, so the performance overhead is negligible.  The initialization is done for you, and its clean and easy to read.  I personally think that the STL adds an immense amount of power and usefulness to C++.  But that's just my opinion.
[Off Topic]
Why not fix ERROR_IF_DONE take a parameter so it at least looks like a function?
You can then use the index as a hard-coded param with no variable/const declaration and less obfuscation.
triskelion - not my style, but I suppose you're right. It never even occurred to me to use a macro with an argument.
Khawar, I hope that you have enough C++ knowledge to understand that, IMHO, the sort of approach presented by glebspy here is horrendous C++ style.

I believe that you would be much better off if you take something like the solution mnashadka proposes, or possibly one like my original one.  

> I personally think that the STL adds an immense amount
> of power and usefulness to C++.

not only power, but also clarity, simplicity and extensibility.  IMHO if you avoid the STL then you are missing much of what modern C++ can offer you.
I like what jasonclarke is implying about modern C++, however, that modernism has to be weighed with efficiency.

There are still certain things in STL and MFC I won't use.
I also love watching tight code run in the debugger :}

My suggestion, try everything.  Compare the pain with functionality with efficiency.  Use the best option for your situation.
> that modernism has to be weighed with efficiency.

STL is a model of efficiency.  In many cases, you would find it very hard indeed to hand craft code that worked more efficiently than what is in the STL.  A prime design goal of the STL was to make it highly efficient.


Wow, buzzword city.
>>A prime design goal of the STL was to make it
highly efficient.

Another was to make it more safe.
Safety means type and range checking.
If you need it, it's good.

The idea I mentioned was not to suggest rolling the entire functionality of the STL yourself.

If you're just going next door, walking across the grass is just as quick as skating down the sidewalk and up the driveway.
> Another was to make it more safe.
> Safety means type and range checking.
> If you need it, it's good.

type safety does not make something less efficient (type safety is a compile time thing).

The STL does not do range checking in simple cases, this means that, for example, iterating over an STL vector should be no less efficient than iterating over a C style array (and this is easy to verify with tests).


>> You could also use static 'bool's
>> inside the case statements -- either singular or an >> array.
But if the bools are static inside of each case, how would you reinitalize them the next time the proceure needed to be performed?  You can't.  You could use an array/vector of bools that is local the function, but not static ones in each case statement.

>> but first thing is I don't want to keep
>> them static, due to the
>> potential multi-threading problems.
Forget multi-threading. How would you ever even make it work since they could never be reset for a 2nd run and you coudl never test them, except for one defined in a case statement while in that statement.  

>> By using statics you cleanly prevent the
>> doneness flags from ever being reset by accident.
Or on purpose.  If this code needs to be run a second time in the program, this won't work.

>>  take a look -it's clean and easy to read,
>> its fast and transparent (no stl apart from `cout').
>> What more could a person want?
Code that can be executed a 2nd time.  Code that can test to make sure each statement is called once.  code that is reentrant.

>> since this `find'
>> algorithm (although it's surely well optimized)
>> has to check for doneness by comparing against
>> potentially *all* members of a set.
Every soluton has to do this.   Your solution is unable to do this.  But given the parameters of the question it must be done.  so your solution does not suffer this overhead because it does not fill the requirements.

>> Furthermore, I don't know how a set is implemented
>> but it might well be a linked list, and everyone
>> knows that it's slower to search a linked list than
>> a simple array.
But the complexity of operations on set<> are rigirously defined?  You don't need to know how it is defined in order to know how efficient it is.  Searches are O(lg n) so they are much better than an array.

>> I think arrays are not the best solution
>> here.  You should use std::bitset.
given the fact that we now know there are no more than 300 consecutuve entries, this is possibly a good solution.  Its hard to say whehtor it is better or worse than a set<>.  both are good though.

>> I personally think that the STL adds an immense
>> amount of power and usefulness to C++.  But that's
>> just my opinion.
You must be alone in that opinin.  hardly!  :-)

>> I hope that you have enough C++ knowledge to
>> understand that, IMHO, the sort of approach
>> presented by glebspy here is horrendous C++ style.
I STRONGLY agree.  The fact that it uses macros shoudl be the first big tip.   The fact that it avoids STL simply because it seems to hard to use is another tip.  In additon it also has bugs.  You have to declare local variables in a case statment in a {  } scope.

>> modernism has to be weighed with
>> efficiency.
modernism and efficiency are not odds.  Compare bitset with  storing bit flags in an int for example.  the bitset code is much simpler and easier to write, but often the optimizer produces the exact same code.

>> Safety means type and range checking.
>> If you need it, it's good.
When Bjarne Stroustrup wrote the first STL stream class (okay it wasn't tempalteixed in those days, so maybe SL not STL) it was because an article had been published that suggested that type checking I/O had to be slower than the C alternative.  Bjarne Stroustrup showed that is not necessarily true, in fact it can be faster since work can be done at compile time that otherwise would be done at runtime.
As nietod pointed out, I'm not a professional programmer. Furthermore I always learn a great deal from him, particularly about the finer details of the rules of the language (like the `case' braces).

I'm sorry about the macros and statics. Here's the proposed solution again with bugs and macros removed.

bool flags[max number of cases];
for(...)flags[i]=false;
while(condition)
  {
  switch(value)
    {
    case 300:
      if(flags[0])
       {cout<<"0 done already"<<endl;exit(-1);}
      else
       {flags[0]=true;do whatever}
    case 203:
      if(flags[1])
       {cout<<"1 done already"<<endl;exit(-1);}
      else
       {flags[1]=true;do whatever}

    default:...
    }
  }

This is reentrant and thread-safe, isn't it? You can use an stl container if it suits you.

Indexing the array as I have done here, or using the form proposed by j.. where the array index takes on the same values as the switch seems superficially at least to require more operations than with the statics. If you don't need to execute the code more than once, or access the flags outside for any purpose other than stated, go for the statics.

The statement then is still:
   Use an array of bool
   Initialize them to false
   map the bool array to the case statements
   toggle the associated bool when its case is triggered.

Implementation aside, that is what I proposed all along.
?? This is reentrant and thread-safe, isn't it?
Yes

But look at all the code duplication.  You have to have up to 300 of those if statements.  Why not do

while(condition)
{
   if(flags[value])
   {
      cout<< "0 done already"<<endl;
      throw -1;
   }
   else
   {
     flags[value]=true;
   }
   switch(value)
   {
     case 300: // whatever ...
     case 203: // whatever ...
     default:...
   }
}

This is much shorter and much easier to maintain and test.  (what if you accidentally screw up numbering in your scheme.  you might easily miss that in testing...)  

This approach is fine if the values int he swithc statement are reasonably sequential.  If there are large gaps, the array would be full of too many unused entries.  In that case the best fix would be to use a bitset....
>> Implementation aside, that is what I
>> proposed all along.
And that is fine as long as the entries will be somewhat sequential.  We didn't know that was true at the start, we know that now.  But in the general case, a bit set will be better as it could handle non sequential entries equally well.
WE SHOULD CLEAR OFF ONE THING... THAT THERE IS NO QUESTION OF SEQUENTIAL OR RANDOM VALUES... THE SWITCH IS NOT CHECKING INTEGER VALUES.... IT IS CHECKING ENUMERATED VALUES (WHICH ARE OF COURSE INDIRECTLY INTEGERAL VALUES). SO THERE IS AN ENUM TYPE AND THERE ARE   M  A  N Y   FUNCTIONS WHICH HAVE SWITCH STATEMENTS CONTAINING SUBSETS OF CASE STATEMENTS FROM THIS ENUMERATED POOL. EACH METHOD HAVE APPROX. 2 - 15 VALUES MAX. THATS IT.

SO IN THIS SITUATION, CURRENTLY I AM INCLINED TO THE ORIGINAL ANSWER FROM MR. JASONCLARKE PLUS THE BITSET SUGGESTION FROM MR. mnashadka. BUT I AM PLANNING TO EVALUATE ALL THESE POSSIBILITIES OVER THE WEEKEND AND WILL COME UP WITH THE FINAL SOLUTION WHICH WILL BE THE MIX OF THE ABOVE MENTIONED SOLS PLUS ANY OTHER THING THAT I WILL LOOK INTO.

ANY MORE COMMENTS WILL BE WELCOME ...
Avatar of DanRollins
typedef enum {
    STP_None= 0,
    STP_Start=1,
    STP_DoWork=2,
    STP_Finish=3,
} CaseStep;

#define MAX_STEP 300
CaseStep anStepDone[MAX_STEP+1]; // initially all 0s
// or you can loop through and init to STP_None

BOOL IsDone( CaseStep eStep )
{
    for (int j=0; j< MAX_STEP; j++ ) {
        if ( anStepDone[j] == eStep ) { // done, error out
            printf("Oh no!, case %d was already done!\r\n", eStep );
            return( TRUE );
        }
        if ( anStepDone[j] == STP_None ) { // never done, add to the list
            anStepDone[j]= eStep;
            return( FALSE );
        }
    }
    ASSERT(0); // should never get here
}


#define FAILDUPCASE(n) case n : if (!IsDone(n))

void SomFn()
{
    CaseStep eStep= STP_Start;

    switch( eStep ) {
        FAILDUPCASE( STP_Start ) {
            // do something, this step has never been done before
        }
        break;
        FAILDUPCASE( STP_DoWork ) {
            // do something, this has step never been done before
        }
        break;
        FAILDUPCASE( STP_Finish ) {
            // do something, this has step never been done before
        }
        break;
        default: ASSERT(0);
    }
}

=-=-=-=-=-=-=-=-=-
If you think that the IsDone fn is doing a lot of work, you should try single-stepping through the STL bitset code sometime.  It is a simple linear search over max 300 items.  The overhead will be lost in the noise.

If you object to the use of the macro, then you are foolishly purist.  A good programmer uses all of the tools available to simplify coding.

-- Dan
First of all, why use defines?   That is the classic example of how they should not be used in C++.  You can replace

>> #define MAX_STEP 300
with

const int MAX_STEP = 300;

The switch can be replaced with

IsDone(eStep);
switch( eStep )
{
  case: ...
}

so there is no need for that FAILDUPCASE macro.  This has many advantages. First of all it eliminates pre-processor macros which are a bad indea in C++ since they do not obey scope and all the usual semenatics of the C++ language.  2nd it removes a tremendous amount of duplicate code.  Why perform that test, or the call to it 300 times when 1 single call will do?   Third it is clearer.  It does not hide the propper C++ syntax inside of a macro.

Basically this is just a varieation of what Triskelion suggested (without the static array) but storing more states.  

>> It is a simple linear search over max 300 items
For what operation?  If you are searching for the first set bit, yes that requires a linear search.  So does your array.  You didn't codee that part of the logic in your example, but it is still needed.  At the end there must be a check to make sure every state was used.  You need to do that with a linear search.   All operations are chomprable to an array in speed.  Why would you suggest that bitset is slower than an array?  essentually it is an array, but of bits not bool, so there is the VERY slight overhead of bit operations.

>> If you object to the use of the macro, then
>> you are foolishly purist.
These fools include Scott meyers and Bjarne Stroustrup.

There may be times that macros are justified, but that tends to be pretty rare.  This one didn't get you something you couldn't have gotten another way and actually a better way.

>> A good programmer uses all of
>> the tools available to simplify coding.
Or use dangerious tools unnecessarily.
Khawar, since this is for lots of different circumstances.  consider this variation which automates the setting of the  array/bitset and the testing at the end using a tempalte class.  This should make it much easier.  Like

template <size_t NumCas>
class CaseTest
{
   bitset<N> Flg; // Lots of possible containers here.
public:
   CaseTest()
   {
      Flg.reset(); // This isn't really needed,it is
                   // done automatically, but just makng
                   // it explicit.
   };
   ~CaseTest()
   {
      if (!Flg.all()) // If a flag was not set.
         throw 0; // ERROR, throw an exception.
   };
   TestCase(int Case)
   {
      if (Flg[Case]) // If case was already performed.
         throw 0; // ERROR Throw exception.
      Flg[Case] = true; // set the case's flag.
   }  
};

You woud use it like

enum SomeEnum
{
   value1,value2,value3,value4
};

int somefunction()
{
   SomeEnum E;
   CaseTest<value4> Tester;
   // No need to clear tester, done automatically.

   while (...)
   {
      Tester.TestCase(E); //Test this case. Only use of
                          // tester required.
      switch (E)
      {
      };
   };
   // no need to test that all cases were run.  That is
   // done automatically.
}
neitod:
I bring to your attention the title of the question:

>> Restricting the execution of a case block in a switch statement?

Of course you can call IsDone() outside of the switch block, but for whatever reason, Khawar wants to do it inside of the switch block.  Hard to figure, but explicitly stated.

>> >> It is a simple linear search over max 300 items
I was refering to my IsDone() fn.  Simple.  Linear.  Not hidden by the obscurities of hard to debug tamplate usage.

>>You didn't codee that part of the logic in your example, but it is still needed.

I believe I did.

>>At the end there must be a check to make sure every state was used.

Th original question is somewhat ambiguous here (and never clarified) so I'm not certain at this is a requirement.  Anyway, it would be easy to check.  Once there are exactly 300 entries in the table, all 300 cases have been executed.  Replace ASSERT(0) with printf("ta da!");

Khawar:
Is it important to know ... at some point ... that ALL of the possible case statements were executed?  That is, that each was executed exactly once and that none were not executed?

-- Dan
>> Khawar wants to
>> do it inside of the switch block
No.  All he wants to do is to insure that every cases is executed exactly one time.  He said

  "I want that every case block should be
  executed only once and whenever control comes
  in the already executed case, it should
  generate error.

He never required that all the work has to be done within the switch stateement.  

Besides, that would be impossible.  The only way to make sure that _every_ statement is executed is goign to require some work after the end of the switch().  There is no avoiding that.  It can be automated, but it still has to occur.

>> Not hidden by the obscurities of hard to debug
>> tamplate usage.
You don't need to debug the STL.  Just like you don't need to debug the standard C library.

Wait a second?  What is that loop in IsDone for?  That doesn't seem to make sense?  Why not use the enum as an index into the array.  That would at least be faster.  Why use a linear search like that when you don't have to.  And if you search, why not use a binary search?  They are much faster and are easier to code, if you use STL.

>>What is that loop in IsDone for?  
You're right.  A much better implementation is would be to have an array of BOOLs and use eStep as an index.

BOOL afStepDone[ 300 ]; // initially all FALSE

BOOL IsDone( CaseStep eStep )
{
   if ( afStepDone[eStep]  ) { // done, error out
      printf("Oh no!, case %d was already done!\r\n", eStep );
      return( TRUE );
   }
   afStepDone[eStep]= TRUE;
}

-- Dan
But that assumes that either there is no need to check for completness or that all of the enumerated values are sequential.  The looping method works even with gaps in the sequence.

-- Dan
Now who should I assign points to? :)
If you're completely at a loss, which is understandable, my advice is to give the points to the first person who responded, i.e. jasonclarke. Say something nice to everyone else though, a lot of these people are really smart (not me of course)
Yes, that is what I was thinking too.

Mr. jasonclarke's answer was the first one and I am going to adopt it, a slightly modified version though.

I am extremely thankful to all other people who have contributed their comments. It was really a knowledgeable discussion for me.

Thanks to everyone again.
Mr. jasonclarke! can u please write me your e-mail account at "khawarjawad@hotmail.com", if yes, pls. write the one that u use most frequently.
Thanks