#1
  1. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    7
    Rep Power
    0

    problem with strcmp & if statement


    I am trying to get a result if one character is entered, and another result if another character is entered. I am using the "strcmp" funtion.

    Could you please "bump" me in the right direction? It's probably quite simple. Thanks in advance for your help.

    Kathy


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


    struct info
    {

    char full_name[30];
    char street[30];
    char city[20];
    char state[3];
    long zip ;
    int age;
    char gender[1];

    };

    void main (void)

    {
    struct info people[2];

    int x;




    for (x=0; x < 2; x++)

    {
    printf("Enter name: ");
    gets(people[x].full_name);

    printf("Enter street address: ");
    gets(people[x].street);

    printf("Enter city: ");
    gets(people[x].city);

    printf("Enter state: \0");
    scanf("%s",people[x].state);

    printf("Enter zip code: ");
    scanf("%ld",&people[x].zip);

    printf("Enter age: ");
    scanf("%i",&people[x].age);


    printf("Enter gender (M or F): ");
    scanf("%c\n",&people[x].gender);

    fflush(stdin);


    puts("The information you entered is: \n");

    puts(people[x].full_name);

    puts(people[x].street);

    printf("%s, %s %ld \n", people[x].city, people[x].state, people[x].zip);



    if (strcmp(people[x].gender,"M") || (strcmp(people[x].gender,"m")==0))

    {
    printf("He is %i years old\n\n", people[x].age);

    }

    if (strcmp(people[x].gender,"M") || (strcmp(people[x].gender,"m")!=0))

    {
    printf("She is %i years old\n\n", people[x].age);

    }


    continue;


    }


    }
  2. #2
  3. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    You are only comparing characters (i.e. a 1-character string), so just compare them directly, like so:

    char a = 'X';
    if (a == 'Y') printf("A = 'Y'") else printf("A != 'Y'");


    But you have a problem with the way you are using the result from strcmp. First of all, your code here:

    if (strcmp(people[x].gender,"M") || (strcmp(people[x].gender,"m")==0))
    if (strcmp(people[x].gender,"M") || (strcmp(people[x].gender,"m")!=0))


    is the same as this:

    if
    (
    strcmp(people[x].gender,"M")
    ||
    ( strcmp(people[x].gender,"m")==0 )
    )

    if
    (
    strcmp(people[x].gender,"M")
    ||
    ( strcmp(people[x].gender,"m")!=0 )
    )


    Why are you comparing the result of strcmp to an integer for only one of the cases each time? Without knowing anything about the function strcmp, this seems like improper code. You should either compare the result to an integer for all cases or none of them, so the code is more readible.

    strcmp returns 0 if the strings are the same. So, why do you compare the result to 0 (to see if it is equal to it) in one case, and then compare the result to 0 (to see if it is not equal to it) in the other? This is probably your problem.
  4. #3
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    Basically, it's the old apples-and-oranges trick. strcmp works on strings and you're giving it a character instead.

    In C, strings are arrays of characters that end with a null (ASCII value of 0, written in C as '\0'). You have declared gender as
    Code:
    char gender[1];
    which leaves out the null-terminator character. Whenever you declare a char array for a string, you always have to make it one character larger, plus make sure that it gets a null-terminator. Otherwise, attempts to process that string will continue on until a null-terminator is found, even if it has to go through every single subsequent location in RAM.

    Myself, I would have kept gender as a character:
    Code:
    char gender;
    and done the test as:
    Code:
    if (people[x].gender == 'M' || people[x].gender == 'm')
    But if you really want to use strcmp, then you should make these changes:
    Code:
    char gender[2];  // declare extra char for null-terminator
     ...
    printf("Enter gender (M or F): ");   // pray and hope they only
    scanf("%s\n",&people[x].gender); // entered one single character
     ...
    if (!stricmp(people[x].gender,"M"))
    {
        // "he"
    }
    else
    {
        // "she"
    }
    Please note that if more than one character is entered in for gender, then the input string will write past the end of gender and clobber whatever data follows.

    Also note that I used stricmp(), which does a case-insensitive comparison. Plus, using else keeps you have having to do another if .

    Besides, it doesn't look like the if statement would have worked anyway. Actually, what it will do is different from what I think you intended. The condition will be true if:
    1. gender is not equal to "M"
    or
    2. gender is equal to "m"

    So if the user enters an "F", she gets mistaken for a "he".

    The OR relational operator ( || ) works with values of "true" and "false", which are defined as non-zero and zero respectively. So the evaluated value of the first clause, strcmp(people[x].gender,"M"), is tested first.

    If it is non-zero (true), then the condition is true and if doesn't even try to evaluate the rest. This is called short-circuiting and can cause you problems if the subsequent clauses contain function calls or assignment statements that you are counting on.

    If it is zero (false), then the second clause is evaluated. If it is zero, then the condition is false. If it is non-zero, then the condition is true.

    The strcmp() family complicates things by returning one of three values whose logic is reversed. Here, a zero means they match, a -1 means the first string was "smaller" (ie, of first mismatched characters, the first string's came before the second's in ASCII order; eg, 'F' comes before 'M' and 'M' comes before 'f' -- case matters) and a +1 means the first string was "greater".

    That means that if they entered an "M", then the first strcmp would report a match with a zero, which if would incorrectly interpret as "false". So you need to use the "bang" operator (!) to make strcmp's zero a non-zero -- and inversely its non-zero return values into zeros.

    Now, if there were two strings to test against that differ in more than just case, that would be written:
    Code:
    if (!strcmp(people[x].gender,test_string1) || !strcmp(people[x].gender,test_string2))
    Hope that helps.

    PS
    In ORing, there is also a bitwise OR which is written | . But that is only used in binary operations. I mention it here, because it looked to me like you might have been trying to bitwise OR the return values of the two strcmps, which would not have worked anyway.

    PPS
    That the if statement interprets non-zeros as true can lead to unexpected problems if you perform an assignment within an if statement, whether intentionally or not.
    Code:
    if (x == 5)  // will only be true if x equals 5
    ...
    
    if (x=5)   // assigns a value of 5 to x and evaluates to 5, which if interprets as "true"
    
    // the most common usage of this feature
    if ( (fp = fopen(fname,"rt")) == NULL)  // attempts to open file
    {   // reports error and exits program if attempt failed
        printf("Attempt to open file %s failed\n",fname);
        exit(1);
    }
    It can be a surprisingly common error to forget that second equals sign in a comparison, especially since most other languages only use a single equals.
  6. #4
  7. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    7
    Rep Power
    0

    Thumbs up


    First off..I really appreciate your help

    :D

    I wasn't sure if the strcmp would work. I was under the impression it needed two int or variables to compare, and I knew I was trying to compare different results. Being new to this, I thought I might have misunderstood.

    However, my 'if' statement wasn't working the way I wanted it to. After reading over your post, I made the following adjustments:

    char gender;

    replaced the strcmp with:

    if (people[x].gender == 'M' || people[x].gender == 'm')

    printf("He is %i years old\n\n", people[x].age);


    else if (people[x].gender == 'F' || people[x].gender == 'f')

    printf("She is %i years old. \n\n",people[x].age);

    Pretty simple, huh? Don't know why this didn't work earlier!

    I got the correct results, but is this the 'proper' code? Is there a more precise way of writing this?

    Thanks again,
    Kathy
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    Originally posted by kmr6655
    I wasn't sure if the strcmp would work. I was under the impression it needed two int or variables to compare, and I knew I was trying to compare different results. Being new to this, I thought I might have misunderstood.
    With all due respect, it looked like you were new at it, which is why I over-explained.

    I don't know what development system or OS you're using, but most have either help files or man pages. It's a good idea to look up a library function to see what its arguments and its return values are. I've been working in C/C++ for about 8 years now and I still look up functions. In fact, I'm learning things I never knew before by reading and answering questions posted on this forum.


    After reading over your post, I made the following adjustments:

    char gender;

    replaced the strcmp with:

    if (people[x].gender == 'M' || people[x].gender == 'm')

    printf("He is %i years old\n\n", people[x].age);


    else if (people[x].gender == 'F' || people[x].gender == 'f')

    printf("She is %i years old. \n\n",people[x].age);

    Pretty simple, huh? Don't know why this didn't work earlier!

    I got the correct results, but is this the 'proper' code? Is there a more precise way of writing this?
    Yes, there is a much more concise and preferable way to write it. The if-statement is more expansively known as the if-else statement. If the condition is true, then you execute the following block of code. Else, you execute the block of code following the "else" keyword; thus:
    Code:
      if (people[x].gender == 'M' || people[x].gender == 'm')
           printf("He is %i years old\n\n", people[x].age);
      else
           printf("She is %i years old. \n\n",people[x].age);
    Since there are only two possible conditions (M or F), if they do not indicate "male", then they must be indicating "female".

    But just from a user-interface perspective, what if the user enters an invalid character, ie not "M", "m", "F", nor "f"? Rather than accept indeterminate gender (darn! I promised myself not to use that joke!), we need to inform him/her that he/she had made an error:
    Code:
      if (people[x].gender == 'M' || people[x].gender == 'm')
           printf("He is %i years old\n\n", people[x].age);
      else if (people[x].gender == 'F' || people[x].gender == 'f')
           printf("She is %i years old. \n\n",people[x].age);
      else
           printf("Input error!  %c is not a valid gender designator.\n",people[x].gender);
    In that case, the chaining of "else if" statements is valid and useful, so long as the catch-all "else" is at the end to handle everything that the preceding if's did not catch. Though if the chain grows too large, most programmers will opt for a switch statement.

    BTW, user interfaces and handling erroneous data input can get complicated and very involved. So for the sake of learning C, it should be quite alright to assume correct input data for now.
    Last edited by dwise1_aol; March 29th, 2003 at 01:28 PM.

IMN logo majestic logo threadwatch logo seochat tools logo