I have the following if-statements:
if (strcmp(registerName, "zero"))
return 00000;
else if (strcmp(registerName, "at"))
return 00001;
else if (strcmp(registerName, "v0"))
return 00010;
else if (strcmp(registerName, "v1"))
return 00011;
It's actually really long - about 20 if-statements. Therefore, I would like to use a switch. How would I convert that to switch when each statement has a different condition?
I tried something as the code below, but it does not work:
int registerAddress;
switch(registerAddress) {
case 1 (strcmp(registerName, "zero")):
regsiterAddress = 00000;
break;
case 2 (strcmp(registerName, "at")):
registerAddress = 00001;
break;
}
You can't — switch statements in C only work on primitive types, not on strings. You could use, say, a hash table or a search tree to optimize the matching, but for only 20 options that may not be worth the trouble.
What you could do, to clean up the code, is set up a mapping table:
struct str2Num {
char *str;
int num;
};
const struct str2Num registerMap[] = {
{ "zero", 00000 },
{ "at", 00001 },
{ "v0", 00010 },
{ "v1", 00011 },
{ NULL, 0 } /* end marker */
};
and do your matching like this:
int i;
for (i = 0; registerMap[i].str != NULL; i++) {
if (strcmp(registerName, registerMap[i].str) == 0) {
return registerMap[i].num;
}
}
/* handle no-match case here */
In fact, if you sorted the table alphabetically, you could even use bsearch() for fast matching.
You can only switch on integers, so this will not work.
If all you're doing is converting a string to an int, store the info in an array and look through it.
struct {
const char *name;
int value;
} fooMapping[] = {
{"zero",0},
{"at",1}
....
};
int foo2value(const char *name)
{
size_t i;
for(i = 0; i < sizeof fooMapping/sizeof fooMapping[0]; i++) {
if(strcmp(name, fooMapping[i].name) == 0)
return fooMapping[i].value;
}
return -1;
}
In a switch,
switch(number) {
case 1;
case 2;
case 7;
}
you are basically saying, if number = 1, then case 1. If number = 7, case 7. So what you need to do is assign each text value, in your case "zero""at""v0" and "v1", you would need to put these into an array, and in the switch statement, instead of switch(number) you would switch an integer that would correspond with the index number of whichever text you had. So if array[3] was = "v0", you would assign an integer to the index number (3) and then switch(integer). Hope this helped.
Why not use the ? operator like so:
return
strcmp(registerName, "zero")? 00000:
strcmp(registerName, "at") ? 00001:
strcmp(registerName, "v0") ? 00010:
strcmp(registerName, "v1") ? 00011:
...
Since switch-case only works with numbers or single chars, I would use a tool like GNU's gperf to create a perfect hash and switch on that value (followed by a strcmp() to be certain of an exact match). That ought to give you the desired performance improvement.
Related
I want to use enums and structs (without using object oriented) to make my program 'translate' the following integers into the specified strings:
1 = "small"
2 = "medium"
3 = "large"
I want something like this: (the known part will be an integer, that has to be translated into the matching string)
size.num = 3;
printf("%s", size.size);
and the output would be large.
I tried to do it with two structs:
struct Size {
int num;
char* type;
}size_map[] = {
{ 1, "small" },
{ 2, "medium" },
{ 3, "large" },
};
struct outfit {
char* ...;
char** ....;
struct Size size;
}T_shirt;
T_shirt.size.num = 3;
so when I have only a size in number, I can iterate over the size_map to find the matching size (in words) I need.
But is there a simple way to make it automatically 'know' that without the use of size_map? (an enum would be also a problem- I will have to use it the opposite way..)
Why not use simple switch as below?
char *sizeInWord = NULL;
switch(size) {
case 1:
sizInWord = "small";
break;
case 2:
sizInWord = "medium";
break;
case 3:
sizInWord = "large";
break;
default:
sizInWord = "InvalidSize";
break;
}
Could some give me a hint at this problem :
An expression is correct only if it contains parentheses and braces properly closed and no other character, even space. For example, () ({} () ({})) is a correct expression, whereas ({)} is not a correct expression or {} ({})). An empty expression (which does not contain any character) is correct.
Given a string expression determine if the expressions is correct and if is determine the maximum level of nesting. Maximum level of nesting parentheses is the maximum number of one another.
Examples
{}({}){{(({}))}}
answer : 5
{}({})) -1 (because the expression is incorrect)
That's what I've did so far.
#include <stdio.h>
#include <stdlib.h>
FILE *fi, *fo;
int first, er;
void X();
void Y();
void S() {
X();
Y();
}
void X() {
if(first=='{') {
first=fgetc(fi);
X();
if(first=='}')
first=fgetc(fi);
else
er=1;
S();
}
}
void Y() {
if(first=='(') {
first=fgetc(fi);
Y();
if(first==')')
first=fgetc(fi);
else
er=1;
S();
}
}
int main()
{
fi = fopen("brackets.in","r");
fo = fopen("brackets.out","w");
first=fgetc(fi);
S();
if(first!='\n')
er=-1;
fprintf(fo,"%d",er);
fclose(fi);
fclose(fo);
return 0;
}
First off, it helps to think of your problem as a formal grammar.
S = The Language you are testing for
S->
NUL // Empty
SS // S followed by itself.
[ S ] // Case 1
( S ) // Case 2
{ S } // Case 3
Since this grammar only has one symbol (S), you only need one parsing method.
The following code is incomplete but hopefully it gets the idea across.
char curr_char;
int main (void)
{
curr_char = getc();
result = parse_s();
return 0;
}
// Parse the S pattern off input. When this method completes, curr_char points to the character AFTER S.
// Returns recursion count or -1 on fail.
int parse_s()
{
max_count = 0;
while(true)
{
int curr_count = 0;
switch 'curr_char':
{
case '[': // [
int count = parse_s(); // S
if (count == -1) return -1; // The S must be valid
if (curr_char != ']') return -1; // ]
curr_char = getc(); // Advance past the ]
curr_count = count + 1; // This expression is 1 nest greater than its contained S
break;
case '(':
// XXX
break;
case '{':
// XXX
break;
default:
// This is either the SS (find the max of the two), the NUL case (return 0), or an error (return -1)
break;
}
// In the SS case you're gonna have to loop and do something here.
}
return max_count;
}
I'm just starting to learn C from Head First C, but I'm having difficulty understanding how refactor my code into multiple functions, more specifically, I don't know how to get functions to work and am confused how to take user input.
How would I incorporate a function like the one below into the main function? What are some other function examples I could use to refactor? Thank you so much!
void get_card_name(char *prompt, char *card_name)
Main function
int main()
{
char card_name[3];
int count = 0;
while ( card_name[0] != 'X' ) {
puts("Enter the card_name: ");
scanf("%2s", card_name);
int val = 0;
switch(card_name[0]) {
case 'K':
case 'Q':
case 'J':
val = 10;
break;
case 'A':
val = 11;
break;
case 'X':
continue;
default:
val = atoi(card_name);
if ((val < 1) || (val > 10)) {
puts("I dont understand that value!");
continue;
}
}
if ((val > 2) && (val < 7)) {
count++;
} else if (val == 10) {
count--;
}
printf("Current count: %i\n", count);
}
return 0;
}
The generic answer when it comes to refactoring is "If it looks complicated or hard to read, try to break it down into smaller pieces that are easier to read (and understand).".
In your case you have this:
int main() {
/* Initial state needed later on */
/* Do some complicated stuff */
}
To refactor this, you need to find out what parts of the initial state you need to keep close to whatever you are going to move away into its own function. In your example, card_name and count are both used inside the complicated bit, and nowhere else. So you can, and should, keep those close the complicated bits:
void do_card_stuff() {
char card_name[3];
int count = 0;
/* Do some complicated stuff */
}
int main() {
do_card_stuff();
}
And, lo and behold, you've refactored your code. If you still think that the card stuff looks complicated, try to break it up into more pieces:
int get_card_value(char card) {
/* Do some complicated stuff */
return value;
}
int do_card_stuff() {
char card_name[3];
int count = 0;
int value;
/* Loop */
/* Get card value from user */
value = get_card_value(card_name[0]);
}
int main() {
do_card_stuff();
}
Just keep at it until it's just silly to break it into smaller bits and you're done. Also, try to keep in mind that the code you break out should be as generic as possible since this will let you re-use this code later on (potentially in other projects).
I am working on certain script language. Values containing structure is
struct myvar
{
char name[NAMELEN];
int type;
void* value;
}
type = 0 --> int* value
type = 1 --> char* value
type = 2 --> float* value
I faced some problem with arithmetic operations. It seems that I need to commit all sorts of type conversions over every single operation, that develops into writing a whole bunch of code for each of them, as in:
case 0: // "="
if(factor1.name)
{
if((factor1.type == 1) && (factor2.type==1))
{
free(factor1.value);
int len = (strlen((STRING)factor2.value)+1)*sizeof(char);
factor1.value = malloc(len);
memcpy(factor1.value,factor2.value,len);
}
else if((factor1.type == 2) && (factor2.type==2))
*(FLOAT*)factor1.value = *(FLOAT*)factor2.value;
else if((factor1.type == 0) && (factor2.type==0))
*(INTEGER*)factor1.value = *(INTEGER*)factor2.value;
else if((factor1.type == 0) && (factor2.type==2))
*(INTEGER*)factor1.value = *(FLOAT*)factor2.value;
else if((factor1.type == 2) && (factor2.type==0))
*(FLOAT*)factor1.value = *(INTEGER*)factor2.value;
else
GetNextWord("error");
}
break;
Is there some way to avoid this tiresome procedure? Otherwise I have no choice but to copy-paste this piece of code for each of "=","~","+","-","*","/","%",">","<",">=","<=","==","~=","AND","OR"
Use a union instead of a struct for the values:
struct myvar {
enum {
STRING, INT, FLOAT,
} type;
union {
char strval[NAMELEN];
int intval;
float fltval;
} val;
};
and then in executing the assignment operator in your scripting language you just do:
factor1 = factor2;
To fetch the right value based on the type you would do:
switch (operand.type) {
case STRING:
printf("%s", operand.val.strval);
break;
case INT:
printf("%d", operand.val.intval);
break;
case FLOAT:
printf("%f", operand.val.fltval);
break;
}
What about writing 3 toType functions:
char* toType0(myvar* from)
{
if (from->type == 0) return (char*)(from->value);
else if (from->type == 1) return itoa((int*)from->value);
else...
}
int toType1(myvar* from)
{
//convert to int...
}
Then in your conversion routines you can do:
switch (factor1.type)
{
case 0:
{ char* other = toType0(&factor2);
//assign or add or whatever....
};
break;
case 1:
{ int other = toType1(&factor2);
//assign or add or whatever....
};
break;
...
}
I would propose the following: when applying an operation, you should first coerce the operand types. E.g., if your operand types are int and float, you should coerce int value to a float one, and continue with the float version of the operation. The coercion is the same (or almost the same) for all the operations. With such an approach, you have much less cases to consider.
Is there a way (in C) to write a construct like the switch statement, but for strings? Is there a way to write a C construct at all in C?
By C construct I mean a statement with braces ... like an if statement has braces, and it's a C construct... right?
The simplest approach is an if-else chain using strcmp to do the comparisons:
if (strcmp(str, "String 1") == 0)
// do something
else if (strcmp(str, "String 2") == 0)
// do something else
else if (strcmp(str, "String 3") == 0)
// do something else
...
else
printf("%s not found\n", str);
A more complicated approach is to use a lookup table, keyed by the string:
struct lookup {const char *key; int value};
struct lookup LookupTable[] = {
{"String 1", 1},
{"String 2", 2},
{"String 3", 3},
...
{NULL, -1}
};
int lookup(const char *key)
{
size_t i = 0;
while (LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].value;
else
i++;
return -1;
}
...
switch(lookup(str))
{
case 1: ...
case 2: ...
case 3: ...
...
default: printf("%s not found\n", str); break;
}
If you want to get really fancy, you could modify the lookup table so that the value is a pointer to a function:
void String1Cmd(void) { ... }
void String2Cmd(void) { ... }
void String3Cmd(void) { ... }
...
void BadCmd(void) { printf("Key not found!\n"); }
struct lookup {char *key, void (*cmd)(void); };
struct lookup LookupTable[] = {
{"String 1", String1Cmd},
{"String 2", String2Cmd},
{"String 3", String3Cmd},
...
{NULL, BadCmd}
};
void (*lookup(const char *str))(void)
{
size_t i = 0;
while(LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].cmd;
else
i++;
return BadCmd;
}
...
void (*f)(void) = lookup(str); // retrieve the function for the given string
f(); // execute the function
In the last example, if str == "String 1", then String1Cmd will be executed. If str is a string not found in the lookup table, then BadCmd will be executed. This method is very flexible, and depending on your design, allows you to add behavior at runtime (sort of a plug-in architecture).
However, note that we've just deferred the main problem - branching on a string value - to the lookup function, and that the lookup function is back to just doing strcmp against each value in the table. We could speed that part of the process up by using a hash table or a tree to minimize the number of comparisons. Depending on how many strings you're branching on, that may or may not be worth the additional effort.
No, you have to do it yourself. There are many variants:
if (strcmp(str, "toto") == 0)
{
// ...
}
else if (strcmp(str, "tata") == 0)
{
// ...
}
else
{
// ...
}
If the number of strings is expected to grow, then a dispatch table with function pointers
struct dispatch_entry
{
const char *key;
void (*action)(void);
};
// Make sure it is sorted !
dispatch_entry dispatch_table[] =
{
{ "tata", &action_tata },
{ "toto", &action_toto },
};
coupled with binary search:
int dispatch_compare(const void *x, const void *y)
{
const dispatch_entry *xx = x, *yy = y;
return strcmp(xx->key, yy->key);
}
// Return -1 on failure
int dispatch(const char *str)
{
static const size = sizeof(struct dispatch_entry);
static const n = sizeof(dispatch_table) / size ;
dispatch_entry tmp = { str, NULL };
dispatch_entry *what = bsearch(tmp, dispatch_table, n, size, &dispatch_compare);
if (what == NULL) return -1;
(*what->action)();
return 0;
}
will do. Hash table based approaches are OK as well.
if you have the function lfind in your lib (POSIX or gcc) you can use it like:
enum { NOTFOUND, HELLO, WORLD, FOO, BAR };
char list[][100]={"hello","world","foo","bar"};
size_t r, siz = sizeof*list, num = sizeof list/siz;
char *tosearch = "foo";
switch ( (r=lfind(tosearch,list,&num,siz,strcmp))?
(r+siz-(size_t)list)/siz:0 ) {
case HELLO: puts("hello");break;
case WORLD: puts("world");break;
case FOO: puts("foo"); break;
case BAR: puts("bar"); break;
case NOTFOUND:puts("not found");
}
each string in the array must have the same size and should not be a pointer
a hashtable if you have a large number of strings and speed is an issue
No, since the switch may only be used with integral types, or a type convertible to an integral type
No, switch works on an integer value (I think floats/doubles are not even allowed). You can emulate that with if/else if/else doing strcmp.
if (strcmp(mystr, "this") == 0) {
//mystr == "this"
}
else if (strcmp(mystr, "that") == 0) {
//mystr == "that"
}
else {
//mystr is not "this" or "that"
}
Yes, and the way is - long if-else-if statement. (for reference: Why switch statement cannot be applied on strings? )
And what do you mean by "a C construct at all in C" o.O ? I'll edit my post, when you answer :)
Sure, depending on how much work you are willing to do.
You can use a preprocessor and some macros to map strings to integral identifiers, giving you a syntax like:
switch (SOSID_LOOKUP (sample_string)) {
case SOSID (hello): printf ("Hello "); break;
case SOSID (world): printf ("World! "); break;
case 0: default: printf ("unknown "); break;
}
If you can use C++ instead of C, you can use litb's template-based string switcher, giving you syntax like:
sswitch(s) {
scase("foo"): {
std::cout << "s is foo" << std::endl;
break; // could fall-through if we wanted
}
// supports brace-less style too
scase("bar"):
std::cout << "s is bar" << std::endl;
break;
// default must be at the end
sdefault():
std::cout << "neither of those!" << std::endl;
break;
}