-2

I don't understand/know how to change my if else statements to become switch statement with cases. Please help! I just need to change my if else statements to a switch and my assignment will be complete! Its fully running and functioning!

This C program provides a main function that supports a bash-like history capability; The main objective for the circular buffer is to repeatedly display a prompt to the user, and each prompt assigns an input number starting at 1. Each line inputted into the circular buffer is stored until it gets overwritten, the buffer only allows up to 5 lines of stored input, FIFO(First in, first out).

Giving the user 4 command options: !x: With x meaning the line number selected, and the exclamation point("!") meaning repeat the (absolute) input line numbered x. This only works if this line is one of the saved commands. This command will display the original input line as well as storing a copy. If the argument x is invalid, an error message will be displayed.

exit(case sensitive): Terminates the program.

history(case sensitive): Prints the saved commands

parse(case sensitive): Tokenize input line number x, This input line shouldn't be stored in the buffer, but instead display each word on a seperate line.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CIRCULAR_HISTORY_BUFFER 5 
#define CHARACTER_LENGTH 128

void CircularHistoryBuffer()
{
char memory[CIRCULAR_HISTORY_BUFFER][CHARACTER_LENGTH];
char command_line[CHARACTER_LENGTH];
int data, n, i;
int number = 0; 
while(1) 
{
    printf("%d>", number + 1);

    fgets(command_line, CHARACTER_LENGTH - 1, stdin);
    for(i = 0; i < CHARACTER_LENGTH; i++)
    {
        if(command_line[i] == '\n')
        {
            command_line[i] = '\0';
            break;
        }
    }
    if(command_line[0] == '!')
    {
        n = atoi(command_line + 1);
     if(n < number - CIRCULAR_HISTORY_BUFFER + 1 || n > number || n <= 0)
        {
            printf( "%d: Not found\n", n);
        }
        else
        {
            data = (n - 1) % CIRCULAR_HISTORY_BUFFER;
            printf("%s\n", memory[data]);
            strcpy(memory[number % CIRCULAR_HISTORY_BUFFER], memory[data]);
            number++;
        }
    }
    else if(strcmp(command_line, "exit") == 0)
    {
        exit(0);
    }
    else if(strcmp(command_line, "history") == 0)
    {
        if(number <= CIRCULAR_HISTORY_BUFFER)
        {
            for(i = 0; i < number; i++)
            {
                printf("%d\t%s\n", i + 1, memory[i]);
            }
        }
        else 
        {
            n = number - CIRCULAR_HISTORY_BUFFER + 1;
            data = number % CIRCULAR_HISTORY_BUFFER;
            for(i = data; i < CIRCULAR_HISTORY_BUFFER; i++)
            {
                printf("%d\t%s\n", n++, memory[i]);
            }
            for(i = 0; i < data; i++)
            {
                printf("%d\t%s\n", n++, memory[i]);
            }
        }
    }
    else if(strncmp(command_line, "parse", 5) == 0)
    {
        n = atoi(command_line + 5);
     if(n < number - CIRCULAR_HISTORY_BUFFER + 1 || n > number || n <= 0)
        {
            printf("%d: event not found\n", n);
        }
        else
        {
            data = (n - 1) % CIRCULAR_HISTORY_BUFFER;
            for(i = 0; i < strlen(memory[data]); i++)
            {
                if(memory[data][i] == ' ')
                {
                    printf("\n");
                }
                else
                {
                    printf("%c", memory[data][i]);
                }
            }
            printf("\n");
        }
    }
    else
    {
        strcpy(memory[number % CIRCULAR_HISTORY_BUFFER], command_line);
        number++;
    }
  }
 }

int main()
{
  CircularHistoryBuffer();

return 0;
}
saadal
  • 1
  • 4
    How about you read the documentation for switch statement instead? And try to implement it by yourself first – Andreas Jan 17 '19 at 09:18
  • You mainly compare strings, if you want to use a _switch_ it will apply on the first character (! e h p) but after except for ! you will have to compare the full command and if it is not what you expected to do the final 'else' case, so that one will be present present several times in your code. For me it is a bad idea to want to use _switch_ rather than the current if else if – bruno Jan 17 '19 at 09:40
  • Do you know how to convert a series of numeric comparisons to `switch`...`case`? If you only have a problem with the string comparisons you could use an array of all the strings to compare with and a loop over the array to get a unique number for every expected string comparison result, then use `switch`...`case`. – Bodo Jan 17 '19 at 09:45

3 Answers3

0

In this case it doesn't make much sense to use a switch statement, since you are looking at doing several string comparisons.

What you could do instead is a table look-up, based on a table sorted in alphabetic order:

const char* STR_TABLE[] =  // must be sorted in alphabetic order
{
  "exit",
  "history",
  "parse",
  ...
};

const size_t STR_TABLE_SIZE = sizeof(STR_TABLE) / sizeof(STR_TABLE[0]);

You can then search through the table for the correct string. The naive implementation being a for loop:

for(size_t i=0; i<STR_TABLE_SIZE; i++)
{
  if(strcmp(STR_TABLE[i], user_input)==0)
  {
    // found, do something
    break;
  }
}

This is the best option when the number of strings in the table are limited. For larger tables, you would use binary search instead. Something like this:

int strcmp_wrapper (const void* obj1, const void* obj2)
{
  return strcmp(obj1, *(const char**)obj2);
}

const char** result = bsearch(user_input, 
                              STR_TABLE,
                              STR_TABLE_SIZE,
                              sizeof(const char*),
                              strcmp_wrapper);

if(result != NULL)
{
  printf("User picked option %s at index %d.", *result, (int)(result - STR_TABLE));
}                               
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

switch-statement will works only with integer values. There is switch-statement uses:

switch(a) { case '1': doSomething(); break; // if you forget break operator, than secondcasealso will invoke and so one case '2': doSomethingElse(); break; default: doSomethingElse2(); }

You can use switch-statement if you need work with integer values/constants from specific range.

alexzok
  • 81
  • 7
0

currently your code is like :

  if(command_line[0] == '!')
   {
       <recall>
   }
   else if(strcmp(command_line, "exit") == 0)
   {
       <exit>
   }
   else if(strcmp(command_line, "history") == 0)
   {
       <historic>
   }
   else if(strncmp(command_line, "parse", 5) == 0)
   {
       <parse>
   }
   else
   {
       <other>
   }

to use a switch will give something like that :

   switch (command_line[0]) {
    case '!':
        <recall>
        break;
    case 'e':
       if(strcmp(command_line + 1, "xit") == 0)
       {
         <exit>
       }
       else
       {
         <other>
       }
       break
    case 'h':
       if(strcmp(command_line + 1, "istory") == 0)
       {
         <historic>
       }
       else
       {
         <other>
       }
       break
    case 'p':
       if(strncmp(command_line + 1, "arse", 4) == 0)
       {
         <parse>
         break;
       }
       // no fallthrough
    default:
      {
         <other>
      }
    }

This is less readable, facilitates the introduction of a bugs if it has to be modified, and has no benefic effect on the speed if this what you expected

For me don't do that ... but ask yourself about the strcmp but strncmp in one case

bruno
  • 32,421
  • 7
  • 25
  • 37
  • `strncmp` shouldn't be used. Instead the user input should be verified, after which `strcmp` should be used. – Lundin Jan 17 '19 at 10:02