5
#include<stdio.h>

int main(){

    char name[20];

    printf("enter a name ");
    scanf("%s",name);
    switch(name[20]){
        case "kevin" : 
        printf("hello");
        break;
    }
    printf("%s",name);
    getch();
}

It seems it will not work. Is this possible? I mean is there any way we can make a switch statement of a string. How to solve the problem, actually?

3
  • Which book are you reading? I ask this because those who read books usually don't have this question; The book answers it. If you're not using a book as a guide, then you're probably a liability; Stop learning C, and learn a programming language that doesn't allow you to accidentally shoot yourself in the feet. Alternatively, get yourself a book... (duh, hintedy hint) Commented Aug 1, 2013 at 3:22
  • im not reading any book :) uh.. c language is our lesson and we have a project about it. yeah i want to stop learning this we are just forced to do so :)) Commented Aug 1, 2013 at 14:33
  • 1
    Isn't name[20] undefined? Commented Sep 27, 2016 at 17:46

8 Answers 8

8

Switch statements in C aren't smart like one's found in other languages (such as Java 7 or Go) you cannot switch on a string (Nor can you compare strings with ==). Switch can only operate on integral types (int, char, etc).

In your code you call switch with: switch(name[20]). That means switch(*(name + 20)). In other words switch on the 21st char in name (because name[0] is the first). As name only has 20 chars you are accessing whatever memory is after name. (which could do unpredictable things)

Also the string "kevin" is compiled to a char[N] (where N is strlen("kevin") + 1) which contains the string. When you do case "kevin". It will only work if name is in the exact same piece of memory storing the string. So even if I copied kevin into name. It still would not match as it is stored in a different piece of memory.

To do what you seem to be trying you would do this:

#include <string.h>
...
    if (strcmp(name, "kevin") == 0) {
        ...
    }

String compare (strcmp) returns different values based on the difference in the strings. Eg:

int ord = strcmp(str1, str2);
if (ord < 0)  
    printf("str1 is before str2 alphabetically\n");
else if (ord == 0) 
    printf("str1 is the same as str2\n");
else if (ord > 0)  
    printf("str1 is after str2 alphabetically\n");

Side note: Dont use scanf("%s", name) in that form. It creates a common security problem use fgets like this: (there is a safe way to use scanf too)

#define MAX_LEN 20
int main() { 
    char name[MAX_LEN]; 
    fgets(name, MAX_LEN, stdin);
    ...
Sign up to request clarification or add additional context in comments.

3 Comments

Please note that string literals do not compile to const char *. String literals are arrays of char, and have type char[n] where n is one more than the number of bytes in the string ("ABCD" has four bytes, so it would be of type char[5]), and when used in a pointer context, they evaluate to pointers which are of type char *. It is true that you aren't allowed to modify their content, but for historical reasons they do not have const type.
Cheers, changed the text to fix that. I wasn't sure if C recognized string literals as const as C++ seems to, C won't complain about loosing const-ness.
Incidentally, here's a subtlety for you. While it is true that the string literal "kevin" is an array N of char where N is equal to strlen("kevin") + 1, this does not hold true for all string constants. Consider the perfectly valid string constant "degenerate\0string\0constant", which (if I've counted correctly) is is an array 27 of char, not an array 11 of char.
6

Switch statements work on int values (or enum), but not on char arrays.

You could do

if (strcmp(name, "kevin")==0) {
    printf("hello");
}
else if (strcmp(name, "Laura")==0) {
    printf("Allo");
}
else if (strcmp(name, "Mike")==0) {
    printf("Good day");
}
else  {
    printf("Help!");
}

Comments

2

There are plenty of ways to go about this! For example, use a...

3-letter hash

#include <stdio.h>

int main(){

    char name[20];

    printf("enter a name ");
    scanf("%s",name);
    switch((int)*name * (int)*(name+1) * (int)*(name+2)){
          case (1275226) : // "kevin"
            printf("hello %s.\n", name);
            break;
          case (1293980) : // "astro"
            printf("welcome %s.\n", name);
            break;
    }
    printf("%d",(int)*name * (int)*(name+1) * (int)*(name+2));
}

1 Comment

For strings of length 8 or less you should be able to switch on a unsigned long long by bit shifting each char.
0

No, you cannot use the switch statement in C with the value of a string or character array. The closest alternative is to use some sort of data structure mapping strings to function pointers. The function pointer could be called after a string is used to look it up.

Comments

0

since the name is declared as a char type ,it would be better if you use "%c" instead of using "%s" inside the scanf() method.

Comments

0

You can use "hash-string.h" library that converts strings into hash code integer. Create a header file and paste this code: http://www.opensource.apple.com/source/gcc/gcc-5484/intl/hash-string.h

#include <stdio.h>
#include <stdlib.h>
#include "hash-string.h"

int main(){

  char name[20];

  printf("Enter a name: ");
  scanf("%s",name);

  unsigned long nameInt = hash_string(name);

  switch(nameInt){
    case 7458046 /* "kevin" */: { printf("Hello %s", name); break; }
    default: { printf("You are not kevin"); }
  }

  printf("\n");
  return 0;
}

Comments

0

Remember the rules while using switch statements.

Switch constraints

1. The controlling expression of a switch statement must have "integer type".

2. The expression of each case label shall be an integer constant expression and no two of the case constant expressions in the same switch statement shall have the same value after conversion. There may be at most one default label in a switch statement.

3. Any enclosed switch statement may have a default label or case constant expressions with values that duplicate case constant expressions in the enclosing switch statement.

Comments

0

If you are after performing specific actions for specific strings this implies you know the strings in advance. This in turn implies their number is limited, is countable, like for example a set of N commands:

const char * commands[] = {
 "command-1",
 "command-2",
 ...
 "command-N"

}

To address those commands inside the array above from your code using a swtich you need to know their index, which is error prone. So number them, give them an ID:

enum Command_id {
  NO_COMMAND,
  COMMAND_1,
  COMMAND_2,
  //...
  COMMAND_N,
};

Now put the two above together using a struct:

struct Command_info {
  const char * command;
  enum Command_id id;
} command_infos[] = {
  {"", NO_COMMAND},
  {"command-1", COMMAND_1},
  {"command-2", COMMAND_2},
  // ...
  {"command-N", COMMAND_N},
};

Now you have nice mapping of strings and their related IDs. To be able to map from string to ID during runtime the mapping above needs to be searched. To do this in a efficient manner you want to us binary search. The C library proveids bsearch() for this. The only prerequsite is that the array to be searched need to sorted.

To sort use qsort() also proveid by the C library. For qsort() to work we you need a comparsion function:

int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
  const struct Command_info * pCI1 = pvCI1;
  const struct Command_info * pCI2 = pvCI2;

  return strcmp(pCI1->command, pCI2->command);
}

Call qsort() like this

qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);

Now as the array is sorted one can look it up using bsearch(). For "COMMAND-2" this would look like this:

    ... = bsearch(&(struct Command_info){"COMMAND-2", NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);

Putting all this together could result in:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


enum Command_id {
  NO_COMMAND,
  COMMAND_1,
  COMMAND_2,
  //...
  COMMAND_N,
};

struct Command_info {
  const char * command;
  enum Command_id id;
} command_infos[] = {
  {"", NO_COMMAND},
  {"command-1", COMMAND_1},
  {"command-2", COMMAND_2},
  // ...
  {"command-N", COMMAND_N},
};


int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
  const struct Command_info * pCI1 = pvCI1;
  const struct Command_info * pCI2 = pvCI2;

  return strcmp(pCI1->command, pCI2->command);
}


int main(int argc, char ** argv)
{
  qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);


  {
    enum Command_id command_id = NO_COMMAND;
    struct Command_info * pCI = bsearch(&(struct Command_info){argv[1], NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);

    if (NULL == pCI)
    {
      printf("Command = '%s' is unknown\n", argv[1]);
    }
    else
    {
      printf("Command = '%s' --> ID = %d\n", pCI->command, pCI->id);


      switch(command_id)
      {
        case COMMAND_1:
          /* perform action on COMMAND 1 here */
          break;

        case COMMAND_2:
          /* perform action on COMMAND 1 here */
          break;

        default:
          /* unknow command, do nothing */
          break;
      }
    }
  }
}

Call it like:

./a.out command-1

giving:

Command = 'command-1' --> ID = 1

or:

./a.out command-bla

giving:

Command = 'command-bla' is unknown

or even

./a.out ""

giving:

Command = '' --> ID = 0

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.