How to fix "Segmentation Fault" in this case - c

I want to make a program that reads a string with the information of a party, separates the information between "/" and then creates an object with the info.
I made a cicle, as shown in the web. If I just want to print it, it works fine, but when I try to assign it to the variables, the error happens - Segmentation Fault
My struct is the following:
typedef struct {
char description[40];
int date;
int time;
int duration;
int room;
char parent[40];
char kids[3][40]
} Party;
And the function that reads the string is:
void createParty():
Party p;
char s[LIMIT] = "John's Birthday/25032019/2230/10/1/Thomas/Anna/Jack/Sarah";
char c[2] = "c";
char *token;
int i=0;
token = strtok(str, s);
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
if (i==0)
strcpy(p.description,token);
else if (i==1)
p.date=atoi(token);
else if (i==2)
p.time=atoi(token);
else if (i==3)
p.duration=atoi(token):
else if (i==4)
p.room=atoi(token);
else if (i==5)
strcpy(p.parent,token);
else
strcpy(p.kids[j-6],token);
i++
}
I expected that all the values would be assigned with no problems, but when I try to assign the last kid, it gives me the Segmentation Fault. If I don't try to assign the last name, there is no errors.
Thanks!

the following proposed code:
eliminates the multiple testing of variable i
eliminates the use of 'magic' numbers
corrects the logic errors
corrects the syntax errors
assures that char arrays are not overflowed
cleanly compiles
needs a 'main()function to call thecreateParty()` function
properly prototypes the function: createParty()
defines the struct in a flexible manner
defines a 'tag' name so a debugger can loop at the individual fields in the struct
separates the 'typedef' from the struct definition
allows there to be more than one party, simply by changing the MAX_PARTIES to a value other than 1
documents why each header file was included
uses appropriate horizontal and vertical spacing for readability
the OPs code called strtok() at the top of the loop, so the results from the first call to strtok() were printed, but never processed into the struct
and now, the proposed code:
#include <stdio.h> // printf()
#include <string.h> // strtok(), strncpy()
#include <stdlib.h> // atoi()
#define LIMIT 500
#define MAX_PARTIES 1
#define MAX_DESC_LEN 40
#define MAX_PARENT_LEN 40
#define MAX_KIDS 3
#define MAX_KID_LEN 40
struct PARTY
{
char description[ MAX_DESC_LEN ];
int date;
int time;
int duration;
int room;
char parent[ MAX_PARENT_LEN ];
char kids[ MAX_KIDS ][ MAX_KID_LEN ]; // was missing trailing semicolon
};
typedef struct PARTY MyParty;
// prototypes
void createParty( void ); // notice 'void' parameter in prototype
void createParty() // removed extranious trailing char
{
MyParty p[ MAX_PARTIES ]; // Note: a 2 space indent level can be 'lost' with variable width fonts
char s[LIMIT] = "John's Birthday/25032019/2230/10/1/Thomas/Anna/Jack/Sarah";
char delimiters[] = "//"; // note using '//' as first slash 'escapes' the second slash
int i=0;
char * token = strtok( s, delimiters );
while( token && i < 11 )
{
printf( "%s\n", token );
switch( i )
{
case 0:
strncpy( p[i].description, token, MAX_DESC_LEN-1 );
break;
case 1:
p[i].date = atoi( token );
break;
case 2:
p[i].time = atoi( token );
break;
case 3:
p[i].date = atoi( token );
break;
case 4:
p[i].duration = atoi( token );
break;
case 6:
p[i].room = atoi( token );
break;
case 7:
strncpy( p[i].parent, token, MAX_PARENT_LEN-1 );
break;
case 8:
strncpy( p[i].kids[0], token, MAX_KID_LEN-1 );
break;
case 9:
strncpy( p[i].kids[1], token, MAX_KID_LEN-1 );
break;
case 10:
strncpy( p[i].kids[2], token, MAX_KID_LEN-1 );
break;
default:
printf( "unexpected field found: %s\n", token );
break;
}
i++; // was missing trailing semicolon
token = strtok( NULL, delimiters ); // prep for next loop iteration
} // end switch
} // end function: createParty()

Related

C : how to solve the problem between system("clear") and strtok function?

I am working on a calculator in which I want to extract parts from a string in the form: (the underscore represents the space key).
I have a "segmentation fault" problem when I try to flush my terminal display. I think I found the epicenter of the problem which is the line :
ptr = strtok_r(EXPRESSION, " \\n", &context);
but I don't know how I could solve it without redoing the strtok function.
Do you have any solution to propose to me?
#include <stdio.h>
#include <string.h>
#ifndef SWITCH_H
#define SWITCH_H
#define SWITCH(X) for (char* __switch_p__ = X, __switch_next__=1 ; __switch_p__ ; __switch_p__=0, __switch_next__=1) { {
#define CASE(X) } if (!__switch_next__ || !(__switch_next__ = strcmp(__switch_p__, X))) {
#define DEFAULT }}
#endif
int main()
{
char EXPRESSION[22];
char EXP1[10][1];
char EXP2[10][1];
char OPE[2][1];
char* ptr;
char* context = NULL;
if ( fgets(EXPRESSION, sizeof EXPRESSION, stdin) )
{
SWITCH (EXPRESSION)
{
CASE ("quit")
return 0;
break;
CASE ("flush")
system("clear");
break;
DEFAULT
break;
}
ptr = strtok_r(EXPRESSION, " \n", &context);
strcpy(EXP1[0], ptr); // Copy to token list
ptr = strtok_r(NULL, " \n", &context);
strcpy(OPE[0], ptr); // Copy to token list
ptr = strtok_r(NULL, " \n", &context);
strcpy(EXP2[0], ptr); // Copy to token list
printf("%s %s %s\n", EXP1, OPE, EXP2);
}
return 0;
}
I tried to solve the problem with strtok :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef SWITCH_H
#define SWITCH_H
#define SWITCH(X) for (char* __switch_p__ = X, __switch_next__=1 ; __switch_p__ ; __switch_p__=0, __switch_next__=1) { {
#define CASE(X) } if (!__switch_next__ || !(__switch_next__ = strcmp(__switch_p__, X))) {
#define DEFAULT }}
#endif
int main(void)
{
while (1)
{
char EXPRESSION[22],EXP1[10],EXP2[10],OPE[1];
if ( fgets(EXPRESSION, sizeof EXPRESSION, stdin) )
{
static const char DELIMITERS[] = " \n";
int COUNTER = 0;
char *ptr= strtok(EXPRESSION, DELIMITERS);
SWITCH (ptr)
{
CASE ("quit")
return 0;
break;
CASE ("flush")
system("clear");
break;
DEFAULT
break;
}
for(int i=0;i<strlen(ptr);i++)
{
EXP1[i]=ptr[i];
}
COUNTER++;
while ( ptr)
{
ptr= strtok(NULL, DELIMITERS);
if(COUNTER==1)
{
for(int i=0;i<strlen(ptr);i++)
{
OPE[i]=ptr[i];
}
}
if(COUNTER==2)
{
for(int i=0;i<strlen(ptr);i++)
{
EXP2[i]=ptr[i];
}
}
COUNTER++;
}
}
}
But also by using argc , argv (it doesn't answer my initial project but I tried anyway).
I also tried to make my own extract part function, but I quickly gave up the idea because it causes stack overflow and segmentation fault. (sorry, I didn't have the idea to keep this code)

How do I print either string or integer in C?

I have the sturct token_t down below. It has two things in it.
type (enum)
value (union)
The reason why value is union, cz a token can be either a number or string.
The main problem is that I cannot design a proper function that can print this token out for me. Check out my void print_token(token_t* token) function. I know it's terrible. Just becase the printf() prints only either %d (decimal) or %s (string) I cannot print my token out. I want my function to print the token no matter what the value is.
// ===========================================================================
typedef enum token_type_t
{
ID, // Identifier
STR, // String
WHS, // Whitespace
LPR, // Left Parenthesis
RPR, // Right Parenthesis
LCB, // Left Curly Bracket
RCB, // Right Curly Bracket
LSB, // Left Square Bracket
RSB, // Left Square Bracket
EOF, // End Of File
EQL, // Equal Sign
SEM, // Semicolon
} token_type_t;
typedef union token_value_t
{
char* str_value;
int int_value;
} token_value_t;
typedef struct token_t
{
token_type_t type;
token_value_t value;
} token_t;
// ===========================================================================
// Here's the problem. I want this function to print the token no matter what type
// the value is, I want it to be dynamic. Is there any way to do that?
void print_token(token_t* token)
{
printf("Token { type: %d, value: %s }\n", token->type, token->value);
}
How do I print either string or integer in C?
Use a different printf() depending on type.
void print_token(const token_t* token) {
printf("Token { type: %d, value: ", token->type);
switch (token->type) {
case ID: printf("%d", token->value.int_value); break;
case STR: printf("\"%s\"", token->value.str_value); break;
// TBD code for other cases
}
printf(" }\n");
}
One solution is to print only a string, but convert the integer to a string conditionally:
For example:
void print_token( const token_t* token )
{
char buf[21] ;
printf( "Token { type: %d, value: %s }\n",
token->type,
token->type == ID ? itoa( token->value.int_value, buf, 10 ) :
token->value.str_value );
}
Noting that itoa() is not a standard function - you might consider that prohibitive if you have to implement your own just for this.
You have not specified which token types are integers and which are strings so if perhaps ID is not the only integer, the condition may be more complex such as:
void print_token( const token_t* token )
{
char buf[21] ;
printf( "Token { type: %d, value: %s }\n",
token->type,
token->type == ID ||
token->type == EOF ? itoa( token->value.int_value, buf, 10 ) :
token->value.str_value );
}
If you have more more integer types than string types you would do better to swap the test.
If the are just one or two of one token type and the rest are of the other, and you have a suitable integer-to-string function, the above solution is succinct, but might get cumbersome if that are more than a few of both types. In that case consider the solution below.
A switch/case using of case "fall-through" cases and a default may be easier to maintain an does not need an integer-to-string fucntion:
void print_token( const token_t* token )
{
printf( "Token { type: %d, value: ", token->type ) ;
switch (token->type)
{
// Stack all the integer token cases here
case ID :
case EOF :
printf("%d", token->value.int_value) ;
break ;
// Everything is a string
default:
printf( "\"%s\"", token->value.str_value ) ;
break;
}
printf(" }\n");
}
Again you might swap the explicit cases and default if there are more string tokens than integer.

can we use switch-case statement with strings in c? [duplicate]

This question already has answers here:
How can I compare strings in C using a `switch` statement?
(16 answers)
Closed 5 years ago.
int a = 0 , b = 0;
char* c = NULL;
int main(int argc , char ** argv){
c = argv[2];
a = atoi(argv[1]);
b = atoi(argv[3]);
switch(c){
case "+": printf(a+b);
break;
}
printf("\n\n");
return 0;
}
No, you can't. Switch is intended to compare numeric types, and for extension char types.
Instead you should use the strcmp function, included in string header:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc != 4) {
puts("Incorrect usage");
return 1;
}
/* You should check the number of arguments */
char * op = argv[1];
int a = atoi(argv[2]);
int b = atoi(argv[3]);
/* You should check correct input too */
if (strcmp(op, "+") == 0)
printf("%d + %d = %d\n", a, b, a + b);
else if (strcmp(op, "-") == 0)
printf("%d - %d = %d\n", a, b, a - b);
/* Add more functions here */
return 0;
}
No you can't. The case labels of a switch need to be compile time evaluable constant expressions with an integral type.
But int literals like '+' satisfy that requirement. (As do enum values for that matter.)
Some folk like to use implementation-defined multi-character literals (e.g. 'eax') as case labels as they claim it helps readability, but at that point, you're giving up consistent behaviour across different platforms.
If you need to branch on the value of a NUL-terminated char array, then use an if block.
There are two cases to the answer ..
Firstly 6.8.4.2 (switch case)
The controlling expression of a switch statement shall have integer
type
Secondly 6.8.4.2 (the case statements)
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
Long story short - you can't use string literal like that. Neither in switch controlling expression nor in case.
You can do the string comparisons using strcmp and then do the if-else conditioning. The context on which you ask this, you can simply pass the character + (argv[2][0]) instead of passing the whole literal. That way you will be passing char to the switch expression and then work accordingly.
Nope, that's not possible.
Quoting C11, chapter §6.8.4.2
The controlling expression of a switch statement shall have integer type.
in your case, you don't seem to need a string but rather the first (and only character) of the string passed in the switch statement, in that case that's possible using character literal (which has integer type) in the case statements:
if (strlen(c)==1)
{
switch(c[0]){
case '+': printf(a+b);
break;
...
}
}
some good other alternatives are described in best way to switch on a string in C when the string has multiple characters.
Not directly. But yes, you can.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// The way you store and search for names is entirely
// up to you. This is a simple linear search of an
// array. If you have a lot of names, you might choose
// a better storage + lookup, such as a hash table.
int find( const char** ss, int n, const char* s )
{
int i = 0;
while (i < n)
if (strcmp( ss[i], s ) == 0) break;
else i += 1;
return i;
}
// A bevvy of little utilities to help out.
char* strupper( char* s )
{
char* p = s;
while ((*p = toupper( *p ))) ++p;
return s;
}
char* zero( char* p ) { if (p) *p = 0; return p; }
#define STRINGIFY(S) STRINGIFY0(S)
#define STRINGIFY0(S) #S
int main()
{
// Our list of names are enumerated constants with associated
// string data. We use the Enum Macro Trick for succinct ODR happiness.
#define NAMES(F) \
F(MARINETTE) \
F(ADRIAN) \
F(ALYA) \
F(DINO)
#define ENUM_F(NAME) NAME,
#define STRING_F(NAME) STRINGIFY(NAME),
enum names { NAMES(ENUM_F) NUM_NAMES };
const char* names[ NUM_NAMES ] = { NAMES(STRING_F) NULL };
#undef STRING_F
#undef ENUM_F
#undef NAMES
// Ask user for a name
char s[ 500 ];
printf( "name? " );
fflush( stdout );
fgets( s, sizeof( s ), stdin );
zero( strchr( s, '\n' ) );
// Preprocess and search for the name
switch (find( names, sizeof(names)/sizeof(*names), strupper( s ) ))
{
case MARINETTE: puts( "Ladybug!" ); break;
case ADRIAN: puts( "Chat Noir!" ); break;
case ALYA:
case DINO: puts( "Best friend!" ); break;
default: puts( "Who?" );
}
}
Keep in mind this works by pure, unadulterated magic tricks, and is not suitable for large collections of text values.
Also, the validity of the match is entirely dependent on the degree to which you pre-process the user’s input. In this example we only ignore case, but a more advanced application might perform some more sophisticated matching.
As others pointed out in C one cannot use a string as argument to a switch, nor to its case-labels.
To get around this limitation one could map each string to a specific integer and pass this to the switch.
Looking up the mapping requires searching the map, which can be done using the Standard C bsearch() function.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int cmp(const void * pv1, const void * pv2)
{
const struct Operation_Descriptor * pop1 = pv1;
const struct Operation_Descriptor * pop2 = pv2;
return strcmp(pop1->name, pop2->name);
}
int main(int argc, char ** argv)
{
size_t s = sizeof operations / sizeof *operations;
/* bsearch() requires the array to search to be sorted. */
qsort(operations, s, sizeof *operations, cmp);
{
struct Operation_Descriptor * pop =
bsearch(
&(struct Operation_Descriptor){argv[1], OP_INVALID},
operations, s, sizeof *operations, cmp);
switch(pop ?pop->op :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
}
If on POSIX one can even use a hash table, which is the fastest way to lookup the mapping.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int main(int argc, char ** argv)
{
if (0 == hcreate(5))
{
perror("hcreate() failed");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < s; ++i)
{
if (!hsearch((ENTRY){operations[i].name, &operations[i].op}, ENTER))
{
perror("hsearch(ENTER) failed");
exit(EXIT_FAILURE);
}
}
{
ENTRY * ep = hsearch((ENTRY){argv[1], NULL}, FIND);
switch(ep ?*((enum Operation *)ep->data) :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
hdestroy(); /* Clean up. */
}

Why can't I get string input?

I was trying to simulate stack concept, and this is my code, blasts errors everywhere, from
the very first scanf,
to everywhere referring char* variables,
and eventually the stack pointer (I named it towerIndicator) doesn't change at all.
And then every typed input is somehow screwed: if I type '+314' to add 314 to the stack, it eventually add 3144, if all the problem above were somehow prevented while compiling.
gcc doesn't inform me any usable error message so I don't get where to go at all. Desperately requiring help here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
const int towerHeight = 32;
int tower[towerHeight];
int towerIndicator = 0;
/*
printf("%i개의 정수를 담을 수 있는 스택을 만들었습니다.\n", towerHeight);
printf("- '+'를 붙여서 정수를 담습니다.\n");
printf("- '-'를 입력해 정수를 빼냅니다.\n");
printf("- '?'를 입력해 스택을 확인합니다.\n");
printf("- '0'를 입력해 작업을 종료합니다.\n");
printf("명령을 입력해주세요.\n================================\n");
*/
char* command;
char* kindOfCommand[1];
char* actualCommand;
while(1) {
printf("> ");
scanf("%s", command);
printf("%s", command);
strncpy(*kindOfCommand, command, 1); kindOfCommand[1] = '\0';puts("#");
strncpy(actualCommand, command+1, strlen(command)-1);puts("$");
switch(**kindOfCommand) {
int i;
case '+':
if(towerIndicator<towerHeight) {
tower[towerIndicator] = atoi(actualCommand);
towerIndicator++;
printf("현재 %i개의 값이 있습니다.\n", towerIndicator);
} else printf("더 이상 넣을 곳이 없습니다.\n");
break;
case '-':
if(towerIndicator>0) {
towerIndicator--;
printf("%i\n", tower[towerIndicator]);
printf("현재 %i개의 값이 있습니다.\n", towerIndicator);
} else printf("더 이상 빼낼 값이 없습니다.\n");
break;
case '?':
default:
printf("[");
for(i=0; i<towerIndicator; i++) {
if(i==towerIndicator) printf("[%i]", tower[i]);
else printf("%i", tower[i]);
if(i!=towerIndicator-1) printf(" ");
}
printf("]\n");
break;
}
if(**kindOfCommand=='0') break;
}
}
There are quite a few modifications required here
loosely fixed may be in for a lot more fixes
// char* command; // <-- initialize this, failure in scanf other wise
char command[120] ;
assuming you are looking for a single character, don't complicate code
// char* kindOfCommand[1]; pointer not required
char kindOfCommand;
since you are using strncpy down somewhere
// char* actualCommand; // <-- initialize this
char actualCommand[126];
and the kindOfCommand code change
// strncpy(kindOfCommand, command, 1);
kindOfCommand = *command;// since you are taking single character
puts("#");
some more at switch
switch( kindOfCommand ) {
and while breaking
if( kindOfCommand == '0' ) break;
Also return before end
return 0;
I applied changes from kkk's answer, and getting input now works well.
char command[11];
char kindOfCommand;
char actualCommand[10];
while(1) {
printf("> ");
scanf("%s", command);
kindOfCommand = *command;
memset(actualCommand,0,sizeof(actualCommand));
strncpy(actualCommand, command+1, strlen(command)-1);
switch(kindOfCommand) { ... }
...
if(kindOfCommand=='0') break;
}
return 0;
}
I needed to solve the input getting screwed. It was because when actualCommand receives a new string from command and it's shorter than previous received string, the last few characters of the string was still remaining in actualCommand. So I put a memset to reset the variable every time the while loop loops. It's not a pointer, so sizeof() could do the work. Otherwise I should've to use strlen() to tell memset the length.

Switch statement using string on an array

#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?
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);
...
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!");
}
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));
}
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.
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.
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;
}
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.
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

Resources