Thread: Struc and Switch case

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    91

    Struc and Switch case

    So, in one of my programs I have to ask the user to type in a month, and I was wondering how I can compare all the twelve months with what the user typed in. i.e. User types in: "JaNuAry", how would I compare the strings with a regular "January" and other ways to type it, also with all the other 11 months?

    I was thinking something with a struc, so I can get the days in there and so that the days can't exceed beyond 31, except for February. And also using a switch case, so I can test them all out, but I have no idea how to compare both the strings from the user and from the code, and how to do it in a switch case, if possible, if there is a easier way, please let me know. Thanks a bunch

  2. #2
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Well, for the first problem, strcmp()'ll be your best bet. Use tolower() if you like, to convert the string to lowercase.

    In order to stick everything into a struct, you could go something like this:

    Code:
    struct date {
        unsigned day:5;
        char month[16];
    }
    . . . but I wouldn't. Just use ints for the dates, more like:

    Code:
    struct date {
        int day;
        char month[16];
    }
    That's assuming the months entered are never more than 15 chars long (15 + 1 for the null).

    For a switch statement, in this case, it's kinda difficult I think, but you could go something like . . .

    Code:
    if(!strcmp(month, "january")) { /* it's january . . . */ }
    else if(!strcmp(month, "february")) { /* it's february . . . */ }
    /* . . . */
    Note that strcmp() will return NULL if the strings are the same.
    Last edited by Nightowl; 11-21-2008 at 01:05 PM. Reason: Fixed broken link to man page for tolower().

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    There are two distinct questions here:
    1. How to compare strings, ignoring case. Many C libraries have a function called either stricmp or strcasecmp which does this. Alternatively, convert the string to all lowercase using a loop and tolower (or uppercase and toupper).

    2. How to know how many days in a month, which is a bit trickier than what you describe: The months, in order from January to December have 31, 28 (29), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 days. You can do this using a switch based on month, or an array based on month, but both require that month is a number rather than a string.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Perhaps something like so for leap years . . .?

    Code:
    int monthlength[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(!(year % 4) && !(year % 400)) monthlength[1] = 29;
    Or something similar . . .

    See Wikipedia for the details on leap years, if you need to.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Changing the case of characters involves their ascii values.

    Code:
    #include <stdio.h>
    #include <string.h>
    
    void ToLower (char *string) {
    	int i;
    	for (i=0;i<strlen(string);i++) 
    		if ((string[i] > 64) && (string[i] < 91)) string[i]+=32;
    }
    
    int main () {
    	char this[]="jaNuaRy";
    	ToLower(this);
    	printf("%s\n",this);
    	return 0;
    }
    It switches case, but sorry, there's no switch case
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Registered User
    Join Date
    Oct 2008
    Posts
    91
    Quote Originally Posted by Nightowl View Post
    Well, for the first problem, strcmp()'ll be your best bet. Use tolower() if you like, to convert the string to lowercase.

    In order to stick everything into a struct, you could go something like this:

    Code:
    struct date {
        unsigned day:5;
        char month[16];
    }
    . . . but I wouldn't. Just use ints for the dates, more like:

    Code:
    struct date {
        int day;
        char month[16];
    }
    Thanks for responding quickly.

    I understand what you did in the first two codes and why you chose them, the third code, i don't really undrestand the if(!strcmp). why did you use "!"? I did almost the exact same thing. Here is my struct code.

    Code:
    struct month{
      char monthEng[10]; //the month in english
      char monthSpan[11]; //the month in spanish
      int order; //extra, just in case...
      int numberDays; //the day of the month
    };
    And you said the switch case here is not really good... is there a easier way or another way around it?

  7. #7
    Registered User
    Join Date
    Oct 2008
    Posts
    91
    Quote Originally Posted by matsp View Post
    There are two distinct questions here:
    1. How to compare strings, ignoring case. Many C libraries have a function called either stricmp or strcasecmp which does this. Alternatively, convert the string to all lowercase using a loop and tolower (or uppercase and toupper).

    2. How to know how many days in a month, which is a bit trickier than what you describe: The months, in order from January to December have 31, 28 (29), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 days. You can do this using a switch based on month, or an array based on month, but both require that month is a number rather than a string.

    --
    Mats
    Thanks for responding quickly as well. I was thinking about that, so I can just convert the months into a lowercase, which would be a lot easier. And you were talking about array based on the month, I did months[12], since there are 12 months, but the number of days in the month, how would i add that in each month? Sorry I'm very new to programming, well sort of... well yeah compared to you guys I'm like a student . But I really do have a passion for learning programming. Thanks for helping all of you, I really appreciate this.

  8. #8
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Read what I said above . . . "Note that strcmp() will return NULL if the strings are the same.".

    I mean that switch statements (for C, anyhow) won't work here very well, because you'd end up doing something like

    Code:
    switch(strcmp(month.monthEng, "january") {
    case 0: /* They're the same . . . */ break;
    default: /* They're not the same */ break;
    }
    
    switch(strcmp(month.monthEng, "february") {
    case 0: /* They're the same . . . */ break;
    default: /* They're not the same */ break;
    }
    . . . and so on. Not exactly optimal, if you get my meaning. Basically if statements, except more clunky and less readable.

  9. #9
    Registered User
    Join Date
    Oct 2008
    Posts
    91
    Quote Originally Posted by Nightowl View Post
    Read what I said above . . . "Note that strcmp() will return NULL if the strings are the same.".

    I mean that switch statements (for C, anyhow) won't work here very well, because you'd end up doing something like

    Code:
    switch(strcmp(month.monthEng, "january") {
    case 0: /* They're the same . . . */ break;
    default: /* They're not the same */ break;
    }
    
    switch(strcmp(month.monthEng, "february") {
    case 0: /* They're the same . . . */ break;
    default: /* They're not the same */ break;
    }
    . . . and so on. Not exactly optimal, if you get my meaning. Basically if statements, except more clunky and less readable.
    Ahh I see now. Hmm so I guess switch case statements here are not good.. hmm, should I just write if statements like
    Code:
    if(strcmp(month.monthEng, "january"))
    {
        printf("You typed in %s", month.monthEng);
    }
    else
        printf("Please type in all lower case");
    Something like that?

  10. #10
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Yes, but you'll want something more like

    Code:
    if(!strcmp(month.monthEnd, "january")) printf("You typed in january.\n");
    else if(!strcmp(month.monthEnd, "february")) printf("You typed in february.\n");
    /* . . . */
    else {printf("Please type the month in all lowercase.\n");
    . . . in all likelihood. What you typed won't work for *any* months other than January.

    EDIT: Note the ! before the strcmp() . . . it's required. strcmp() will return NULL if the strings match, and since you're checking for a match, you want to actually check for a NULL.

  11. #11
    Registered User
    Join Date
    Oct 2008
    Posts
    91
    Quote Originally Posted by Nightowl View Post
    Yes, but you'll want something more like

    Code:
    if(!strcmp(month.monthEnd, "january")) printf("You typed in january.\n");
    else if(!strcmp(month.monthEnd, "february")) printf("You typed in february.\n");
    /* . . . */
    else {printf("Please type the month in all lowercase.\n");
    . . . in all likelihood. What you typed won't work for *any* months other than January.

    EDIT: Note the ! before the strcmp() . . . it's required. strcmp() will return NULL if the strings match, and since you're checking for a match, you want to actually check for a NULL.
    OoO I see what your saying, do the if, else if ... (continuing until december), and then at the end do the else to finalize to type in lower case. I understand now.

    hmm, i was just wondering, are we able to compare 3 strings with each other? Like, the one from the user, month in english and month in spanish? Or is this totally different?

  12. #12
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by dlwlsdn View Post
    Ahh I see now. Hmm so I guess switch case statements here are not good.. hmm, should I just write if statements like
    Code:
    if(strcmp(month.monthEng, "january"))
    {
        printf("You typed in %s", month.monthEng);
    }
    else
        printf("Please type in all lower case");
    Something like that?
    You might as well convert to numbers using an array, then a for loop which checks against the numbers. If you use a global const char array (month[0]=january, etc.) and two short functions (one which accepts a char* and returns an int, and one which accepts an int and returns a char*) the conversion will be quick and painless both ways. That makes the for loop pretty simple too.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  13. #13
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Quote Originally Posted by MK27 View Post
    You might as well convert to numbers using an array, then a for loop which checks against the numbers. If you use a global const char array (month[0]=january, etc.) and two short functions (one which accepts a char* and returns an int, and one which accepts an int and returns a char*) the conversion will be quick and painless both ways. That makes the for loop pretty simple too.
    Very good point.

    Something like . . .

    Code:
    const char monthchars[12][] = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"};
    
    int get_month_as_int(char *monthstr) { /* could also pass your struct into here . . . */
        if(!strcmp(monthstr, monthchars[0])) return 0;
        if(!strcmp(monthstr, monthchars[1])) return 1;
        if(!strcmp(monthstr, monthchars[2])) return 2;
        /* or make this into a for() loop . . . simpler, like so . . . */
        for(x = 0; x < 12; x ++) {
            if(!strcmp(monthstr, monthchars[x])) return x;
        }
        printf("Please type the month in lowercase . . .\n");
        return -1;
    }
    
    char *get_month_as_str(int monthint) {
        return months[monthint]; /* check that monthint is >= 0 && < 12 . . . */
    }
    Remember to experiment . . . can't go wrong, unless you don't make a backup beforehand.

  14. #14
    Registered User
    Join Date
    Oct 2008
    Posts
    91
    Quote Originally Posted by MK27 View Post
    You might as well convert to numbers using an array, then a for loop which checks against the numbers. If you use a global const char array (month[0]=january, etc.) and two short functions (one which accepts a char* and returns an int, and one which accepts an int and returns a char*) the conversion will be quick and painless both ways. That makes the for loop pretty simple too.
    Thanks for the insight. I'll try rewriting this program again, in different ways, I think thats the best way to learn as well. But right now, i want to get used to structs and strings. But thats a great way of doing this, I wouldn't have thought of that in like ages. But you were saying char* and returns a int. Is that even possible? I was reading the online lesson on cprogramming.com, I can't recall anything about a char* returning a int, would be something like
    Code:
    month[0] = "january";
    month[1] = "february";
    // .....
    char *pointer1;
    int i=0, x;
    
    for(i=0;i<11;i++)
    {
         x = *(pointer1 + i);
    }
    
    return x;
    Or am I totally off on my pointers? I really appreciate your help though, you guys are awesome ^^, seriously.

  15. #15
    Registered User
    Join Date
    Oct 2008
    Posts
    91
    Quote Originally Posted by Nightowl View Post
    Very good point.

    Something like . . .

    Code:
    const char monthchars[12][] = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"};
    
    int get_month_as_int(char *monthstr) { /* could also pass your struct into here . . . */
        if(!strcmp(monthstr, monthchars[0])) return 0;
        if(!strcmp(monthstr, monthchars[1])) return 1;
        if(!strcmp(monthstr, monthchars[2])) return 2;
        /* or make this into a for() loop . . . simpler, like so . . . */
        for(x = 0; x < 12; x ++) {
            if(!strcmp(monthstr, monthchars[x])) return x;
        }
        printf("Please type the month in lowercase . . .\n");
        return -1;
    }
    
    char *get_month_as_str(int monthint) {
        return months[monthint]; /* check that monthint is >= 0 && < 12 . . . */
    }
    Remember to experiment . . . can't go wrong, unless you don't make a backup beforehand.
    const char monthschar[12][], why did you do a 2-dimension... I don't know 2-dimensions at all, or when to use them. haha, but i understand everything you wrote, except the 2-dimensions. Is it cause we are making it 12 elements long, and each element will have, the months you wrote?

Popular pages Recent additions subscribe to a feed