-3

I'm having trouble with using multiple If else If statements... this is my code so far and all I need to do is ask for lower case vowels and the users favorite animal (cat or dog ). Then ask for any capital letter. Please dont judge to hard, but when I run my code I can answer the vowels perfectly but then its answers the favorite animal part without letting me put in my input of either cat or dog. Please help :c

int main()
{
    //set variables 
    char letter;
    
    //ask for lower case vowles 
    cout << "Give me a lowercase vowel - ";
    cin >> letter;
        
    //set vowles 
    if  (letter=='a' || letter=='e' ||  letter=='i' || letter=='o' || letter=='u' || letter=='y' )
    {
        cout << "Thank you! ";
    }
    else if  (letter=='A' || letter=='E' ||  letter=='I' || letter=='O' || letter=='U' || letter=='Y' )
    {
        cout << "Your stupid .... I said lowercase vowel.  ";
    }
    else 
    {
        cout <<  "Error Not A Vowel ";
    }
            
    //favorite animal
    cout << "what is your favorite animal? " << endl;
    
    //set animal 
    char animal;
    
    //if cat or dog good anything else bad 
    if  (animal == 'cat' || animal == 'Cat' || animal == 'dog' || animal == 'Dog' )
    {
        cout << " Omg I love that tooo!!! " ;
    }
    else  
    {
        cout << "Oh.. Thats your favorite animal ";
    }
    //any capital letter // pause its not working ... uh oh
        
    //end the program 
    cout << endl << endl;
    system("pause");
}                   
user438383
  • 5,716
  • 8
  • 28
  • 43
ONION
  • 9
  • 1
  • A char can hold only one character, to be able to store dog or cat you need something that can hold more then one character. – Pepijn Kramer Sep 21 '21 at 03:20
  • There is a big difference between a [character literal](https://en.cppreference.com/w/cpp/language/character_literal) and a [string literal](https://en.cppreference.com/w/cpp/language/string_literal). Is `'cat'` supposed to be a character literal or a string literal? If you want it to be a string literal, then you must write `"cat"` instead of `'cat'`. However, you cannot compare string literals with individual characters, so `animal == 'cat'` does not make sense, even if you change the `'` to `"`. – Andreas Wenzel Sep 21 '21 at 03:26
  • @Andreas I’m not sure what either of those are… I’m sorry. My professor said we need to ask the user for a favorite animal and if it’s cat or dog congratulate them and if it’s any other animal say something rude. So I was trying to do it how I did with the vowels. – ONION Sep 21 '21 at 03:32
  • `char animal;` is only able to hold a single character of input. You should use [`std::string`](https://en.cppreference.com/w/cpp/string/basic_string) instead, if you want to hold more than one character of input. If you do that, then you can write `animal == "cat"` and it would make sense. – Andreas Wenzel Sep 21 '21 at 03:38
  • 1
    Instead of checking for "Cat" and "cat" (and missing "cAt", "cAT", "CaT", etc.), just make the whole word all lowercase instead. Also, "you're" and not "your". If you are actually expected to be rude, you probably shouldn't be as 'stupid' as the user. – sweenish Sep 21 '21 at 03:41
  • See also: https://stackoverflow.com/questions/7755202/multi-character-constant-warnings – zkoza Sep 28 '21 at 10:06

1 Answers1

2

As noted in the comments, you are confusing characters and strings. This can be a pain point when C++ is your first language. A char is a single character, and is surrounded by single quotes, like
char letter = 'a';.

A string can consist of zero to many characters and is surrounded by double quotes.
std::string str = "Hello";

An animal name would definitely be a string and not a character. This is usually further confused by the fact that a C-string is a special array of characters. char str[] = "Hello"; is valid code and the elements of the character array are 'H', 'e', 'l', 'l', 'o', '\0'.

The code 'cat' is just going to end in a bad time. The single quotes imply a character, but you've stuffed multiple characters in there. Compiling with warnings enabled would have likely caught this, use -Wall -Wextra at a minimum.

Below is an example of the favorite animal portion using std::string:

#include <cctype>
#include <iostream>
#include <string>

void string_to_lower(std::string& str) {
  for (auto& l : str) {
    l = std::tolower(static_cast<unsigned char>(l));
  }
}

int main() {
  std::string input;
  std::cout << "What's your favorite animal? ";
  std::getline(std::cin, input);

  string_to_lower(input);

  if (input == "cat" || input == "dog") {
    std::cout << "Cool.\n";
  } else {
    std::cout << "That's unfortunate.\n";
  }
}

Some output:

~/tmp 
❯ ./a.out 
What's your favorite animal? CAT
Cool.

~/tmp 
❯ ./a.out 
What's your favorite animal? cAt
Cool.

~/tmp took 4s 
❯ ./a.out 
What's your favorite animal? axolotl
That's unfortunate.

Note that by lower-casing the input after getting it, I only have to check against "cat" and "dog", and I catch all possible ways of writing them. Your code misses both of the inputs I used, and a lot of others.

If you cannot use std::string (which I think is silly), your comparison using C-strings is a bit weirder and the code is generally a bit clunkier.

#include <cctype>
#include <cstring>
#include <iostream>

void string_to_lower(char str[], int sz) {
  for (int i = 0; i < sz; ++i) {
    str[i] = std::tolower(static_cast<unsigned char>(str[i]));
  }
}

int main() {
  constexpr int strsz = 256;
  char input[strsz] = {0};
  std::cout << "What's your favorite animal? ";
  std::cin.getline(input, strsz - 1);

  // Unnecessary ternary, but it can catch issues and shorten the execution time
  // of the function
  string_to_lower(input, strlen(input) < strsz ? strlen(input) : strsz);

  if (!std::strcmp(input, "cat") || !strcmp(input, "dog")) {
    std::cout << "Cool.\n";
  } else {
    std::cout << "That's unfortunate.\n";
  }
}

Some outputs:

~/tmp 
❯ ./a.out 
What's your favorite animal? CAT
Cool.

~/tmp 
❯ ./a.out 
What's your favorite animal? doG
Cool.

~/tmp took 6s 
❯ ./a.out 
What's your favorite animal? axolotl
That's unfortunate.

In both code examples, I use a getline method instead of a direct std::cin. By doing this, I can capture multi-word inputs without the program getting weird. Note that I have to use a different method to grab a line for std::string and C-strings.

I have also recently edited in some static_casts to the string_to_lower() functions. They are needed to avoid undefined behavior if, for example, someone attempts to type in an accented character or a letter that is not found in the English alphabet. One takeaway from the comments to this answer should be that validating input is hard, moreso in C++ due to the lack of built-in support that exists.

sweenish
  • 4,793
  • 3
  • 12
  • 23
  • 1
    There is one small issue: [`std::tolower`](https://en.cppreference.com/w/cpp/string/byte/tolower) will invoke undefined behavior for most negative arguments. The proper way to call that function is to cast the argument to `unsigned char`. See [this answer](https://stackoverflow.com/a/45007070/12149471) to another question for the reason behind this. – Andreas Wenzel Sep 21 '21 at 04:37
  • Is it possible for user input to be interpreted as a negative valued char? – sweenish Sep 21 '21 at 04:49
  • The linked answer says that `EOF` is basically any negative value. Casting a negative value to unsigned will get you a bogus value anyway. I'm not fully convinced that the cast would help anything. – sweenish Sep 21 '21 at 04:55
  • In one of your previous comments, you wrote: `"Is it possible for user input to be interpreted as a negative valued char?"` -- Yes, on platforms on which `char` is 8-bit signed (which is most platforms), then entering character codes between `128` and `255` will result in values between `-128` and `-1`. – Andreas Wenzel Sep 21 '21 at 04:58
  • The macro `EOF` must evaluate to a negative value. On most implementations, it evaluates to `-1`. In that case, any value between `-128` and `-2` will invoke undefined behavior. The value `-1` will not invoke undefined behavior, but possibly unintended behavior, as the function will interpret it as `EOF` and not as a character with the character code `255`. – Andreas Wenzel Sep 21 '21 at 05:01
  • Okay, I think that gets into non-ASCII or extended ASCII type stuff. At that point I'm not bothering with `` at all. I'm either going with `` or a Unicode library and if I'm being honest it'll be the third-party library. I doubt this answer needs that level of checking. I do appreciate the note, and it is good knowledge to possess, but by the time that cast becomes a necessity, `` is just not the right tool for the job anymore. – sweenish Sep 21 '21 at 05:04
  • Most implementations, such as glibc and the Microsoft runtime library also allow values between `-128` to `-2`. However, it is still impossible for them to distinguish between the value `EOF` and the character with the character code `255`, if you do not perform the cast to `unsigned char`. Therefore, even on these platforms, it is still advisable to perform the cast. – Andreas Wenzel Sep 21 '21 at 05:07
  • But what does that input look like? At that point, is it really just someone typing international characters, or is it someone purposefully trying to break the program? How do I type a bogus value in? This is obviously naive text-checking as found in a beginner-level course. And while I usually preach about maintaining best practices at all levels of learning, this reaches a point where I think it's not needed because I wouldn't be wasting my time with `` in production. Unless a goal in production is to purposefully exclude 3/4(+) of the world. – sweenish Sep 21 '21 at 05:13
  • And from https://quuxplusone.github.io/blog/2019/02/03/on-teaching-unicode/ , if the question came up in a class, I'd paraphrase the final paragraph and move on. – sweenish Sep 21 '21 at 05:15
  • English speaking users will probably only be using 7-bit ASCII, which are the character codes `0` to `127`. However, it is very common for non-English speakers to use the character codes `128` to `255`, which will cause undefined behavior with your code. For example, the French use `é`, `à` and `ô`, the Germans use `ä`, `Ü` and `ß`. People who speak these languages normally have those keys on their keyboard, so input is easy. All of the mentioned characters have codes above `128`, which means that they will have negative values when stored in a `char` (on platforms on which `char` is signed). – Andreas Wenzel Sep 21 '21 at 05:33
  • I fully agree that Unicode is the best way to go and that we should try to move away from the single-byte fixed-width character encoding. However, it will still be in use for the next few decades, so mastering both is important. – Andreas Wenzel Sep 21 '21 at 05:43
  • Thank you for the concrete examples. I'll edit in the casts and add a blurb. – sweenish Sep 21 '21 at 14:27