Typecasting, ints and chars in c++ - c++

I'm trying to write a function to detect separators as defined by an assignment and I know it is not good programming style to
#define EXCLAMATION_POINT 33, but to instead do #define EXCLAMATION_POINT '!'
This is my code:
#include <iostream>
#include <ostream>
using namespace std;
#define PERIOD '.'
#define QUESTION_MARK '?'
#define EXCLAMATION_POINT '!'
#define COMMA ','
#define COLON ':'
#define SEMICOLON ';'
inline bool IsSeparator(int x)
{
if (isspace(x) ||
x == PERIOD ||
x == QUESTION_MARK ||
x == EXCLAMATION_POINT ||
x == COMMA ||
x == COLON ||
x == SEMICOLON) {
return true;
}
else {
return false;
}
}
int main (int argc, char * const argv[]) {
int input;
cout << "Enter characters: \n";
input = cin.get();
if (!IsSeparator(input))
cout << "true";
else {
cout << "false";
}
return 0;
}
But in my IsSeparator(), how do I typecast that int to a char to be compared to '!'. I thought if I did something like (char)EXCLAMATION_POINT that would work, but it does not and the value is left at an int. What am I doing wrong here? Thanks!

You don't need any cast, but:
if (!IsSeparator(input))
should be:
if (IsSeparator(input))
Also, your prompt:
cout << "Enter characters: \n";
implies you can enter multiple characters. So you can, but cin.get() will only read one.
Regarding giving symbolic names to things. Suppose you are parsing a file where the separator is a colon. It then makes sense to say:
const char SEPARATOR = ':';
because you can then change it when the file format changes, for example to:
const char SEPARATOR = '|';
but it doesn't normally make sense to give your own names to the members of the ASCII (or whatever) character set.
In your code, it might make sense to create an array of separators (I'm not showing all the ones you use for my ease of typing):
const char SEPARATORS[] = {':', '|', '!', 0 };
and then have your validation function iterate over the array. Note in this case, the array could also have been expressed as a string literal:
const char * const SEPARATORS = ":|!";

What gives you the idea that those #defines are a good practice at all? Are you required to handle the great Exclamation Mark Redefinition of 2015?
It is probably safe to assume that an exclamation mark is going to be represented by '!' now and forever. Just like the constant one is going to be represented by 1 tomorrow as well.
You don't need to define EXCLAMATION_MARK any more than you need to define ONE or MINUS or INT.

Related

Counting words that start with Capital Letters C++ [Help]

Hey everyone I'm a newbie to C++ and could use some help.
I'm trying to code a program which counts only the words that start with Capital Letters.
int countLegalWords(char str[])
int counter = 0; // counts the legal words
for (int i = 0; i < MAXSIZE; i++)
{
if (str[i] >= 'A' && str[i] <= 'Z')
{
if (str[i + 1] >= 'a' && str[i + 1] <= 'z')
{
counter++;
}
else if (str[i] == ' ')
i++;
}
}
return counter;
Example:
Input:
I liKE Ice Cream H
Output:
4 words with capital letters at the beginning of the word.
There are several problems with your code
In C++, std::string is used for strings. Things like ´char*´ or ´char[]´ are not used in C++ They are used in C. But C and C++ are 2 different languages
You use a C-Style array (char str[]). In C++, C-Style arrays are not used
There is a magic constant MAXSIZE, which has nothing to do with the length of the string. If MAXSIZE is 100 but the your string is smaller, then you compare out of bounds values in the for loop. This is a severe bug.
You need to understand that C-style strings are 0-terminated. The last charcter is a '\0'. You must not operate past the terminating 0.
Your logic in detecting words and word begin is wrong. You check any character for uppercase and then the next for lowercase. But this can happen also within a word. See your sentence with "liKe" in it.
You do not want to switch to C++. You have written in the comment that you want to use strcmp and such, which is a C-function
If you would write comments and use meaningful variable names, then you would find all errors by yourself.
OK, that were the problems. Now a possible solution, using your programming style.
#include <iostream>
int countLegalWords(char myString[]) {
// Here we will store the number of words which start with a capital letter
int countOfLegalWords = 0;
// We will iterate over the complete string and check all characters
unsigned int indexInString = 0;
// Check all characters of the string until we hit the terminating 0
while (myString[indexInString] != '\0') {
// Search for the begin of a word. This is the first non-space character
while (myString[indexInString] == ' ')
++indexInString;
// OK, Now we found the begin of a word. Check, if the first character is upper case
if ((myString[indexInString] >= 'A') and (myString[indexInString] <= 'Z')) {
// Yes, uppercase, count up
++countOfLegalWords;
}
// Now search for the end of the word or for the end of the complete string
while ((myString[indexInString] != '\0') and (myString[indexInString] != ' '))
++indexInString;
}
// And return the count of legal words to ther calling program
return countOfLegalWords;
}
int main() {
char myString[] = "I liKE Ice Cream H";
std::cout << "\nCount of legal words: " << countLegalWords(myString) << '\n';
}
in C++ all this would be done with a one liner:
#include <iostream>
#include <string>
#include <iterator>
#include <regex>
// Regex for a word starting with a capital letter
const std::regex re{ R"(\b[A-Z]\w*)" };
// Main program
int main() {
std::string myString{ "I liKE Ice Cream H" };
std::cout << "\nCount of legal words: " << std::distance(std::sregex_token_iterator(myString.begin(), myString.end(),re), {}) << '\n';
}

Problem with comparison between pointer and integer C++

I've been getting error messages saying
[Error] ISO C++ forbids comparison between pointer and integer [-fpermissive]
and don't know how to fix it.
I've searched stackoverflow for people with same issues, but only came up with this: c++ compile error: ISO C++ forbids comparison between pointer and integer which didn't answer my question. What also confused me is that the error is on line indicated by the HERE comment, which is the if statement, but I don't see any integers in the condition part.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int main() {
char in[100];
gets(in);
int len = strlen(in);
std::string s(in);
int count = 0;
for (int i = 0; i < len; i++) {
if (s.at(i) == " ") { // <-- HERE
count += 1;
}
}
cout << count;
}
Say the input is Hello World, I am expecting output to be 1, but I didn't get any output.
The expression " " is a string literal with type const char [2].
The expression s.at(i) returns a char&.
So, s.at(i) == " " is trying to find an equality operator taking
char& on the left and a reference to the literal array const char(&)[4] on the right.
It finds one or more candidates for operator==, but the argument types don't match any exactly, so next it tries the implicit conversion sequences - this is where the char& undergoes integral promotion to int, and the array decays to const char*.
It still doesn't find a match with these, and gives up, but that explains why it has int and const char * arguments when the error is emitted.
All that is a long way of saying that you write character literals like ' ' in C++. They're not just a string of length 1 as in some other languages (and you can't write strings with single quotes at all).
Change the if statement
if (s.at(i) == ' ') {
count += 1;
}
since s.at(i) returns char&, " " is a string, and ' ' is a char.
The problem is that " " is a string literal not a character! A character literal would be ' '.
The error is a bit misleading, because " " is acutally a const char*.
C++ differentiates between character strings and single characters in the literals by different quoting symbols (" vs '). The " " in your code is the string literal that contains one space, a single space character would be written as ' '. The function std::string::at returns a single character.
A small example will show you how the compiler looks on that
#include <iostream>
#include <string>
#include <typeinfo> // for typeid
using namespace std;
int main() {
string s = "Hello, world!";
cout << typeid(" ").name() << endl;
cout << typeid(' ').name() << endl;
cout << typeid(s.at(0)).name() << endl;
return 0;
}
see online demo of above code.
But, to be precise, identical types aren't required for comparisons in C++, but the types need to be compatible. Pointers (string literals are considered constant pointers to characters, in fact pointing to the first character in the literal) and integers (to which char is promoted in your case) are not compatible. To "fix" your problem quickly, change s.at(i) == " " to s.at(i) == ' ', but your program will remain problematic: it still contains a lot of C code that's problematic in it self, too. A possible C++ version could be this:
#include <iostream>
#include <string>
using namespace std;
int main() {
int count = 0;
string line;
std::getline(cin, line);
for (const auto c: line) {
if (c == ' ') {
count++;
}
}
cout << "Your input \""<< line << "\" contains " << count << " space(s)." << endl;
return 0;
}

Converting input from lowercase to uppercase using ASCII codes in C++

This is my first question here, so I've done my best to make this a good question.
I am creating a program that essentially takes user input and converts all characters to uppercase. I am using a for-loop to scan for lowercase characters using corresponding ASCII codes.
I am able to do this just fine using a character array that is assigned a string in-code: char text[] = "Text".
I want to be able to take user input and use it in the character array. I tried using getline(cin,myString) and assigning the character array with that, but it says array must be initialized with a brace enclosed initializer.
I kept the character array uninitialized because sizeof(text) isn't giving the correct size when the array is initialized. I was reading about using pointers but I'm still a bit fresh on that topic. Below is the code I wrote:
int main() {
// User input as a string
char textConvert[] = "This text will be converted to uppercase.";
cout << textConvert << endl;
int endChar = sizeof(textConvert); //Only gives correct size when array is uninitialized
for (int i = 0; i < endChar; i++) {
if (textConvert[i] >= 97 && textConvert[i] <= 122) {
textConvert[i] = textConvert[i] - 32;
}
}
cout << textConvert;
return 0;
}
Question:
I tried using getline(cin,myString) and assigning the character array with that, but it says array must be initialized with a brace enclosed initializer
Here the compiler works out the size of the array needed.
char textConvert[] = "This text will be converted to uppercase.";
If you want user input you need to allocate an array and specify size.
char textConvert[50];
Now you can read a line and copy it into the array:
std::string myString;
std::getline(std::cin , myString);
// Should check that the string is not more than 50 characters.
std::copy(std::begin(myString), std::end(myString), textConvert);
But really there is no need to do this at all. Just use the std::string and loop over the string. Best to avoid C constructs like arrays and use the C++ constructs that stop you making errors.
Size of String
This is not a good idea.
int endChar = sizeof(textConvert);
This measures the size of the array (not the size of the string). There is also an issue that arrays will very easily decay into pointers. When this happens sizeof() will give you the size of the pointer (probably 4 or 8) not the size of the array.
To get the size of a string use std::strlen() (include <cstring>).
But really you should be using std::string the C++ version of string that does its own memory management and re-sizes as required.
Magic Numbers
Prefer not to use magic numbers:
if (textConvert[i] >= 97 && textConvert[i] <= 122) {
textConvert[i] = textConvert[i] - 32;
}
These magic numbers make the code hard to read. You can use character constants instead.
if (textConvert[i] >= 'a' && textConvert[i] <= 'z') {
textConvert[i] = textConvert[i] - ('a' - 'A');
}
Prefer the standard Library
But doing this manually is not recommended. You should use the standard library routines.
std::islower() . // Check if a character is lower case.
std::toupper() . // Convert a lowercase character to upper.
// include <cctype>
C++ Example
Try this:
#include <iostream>
#include <string>
#include <cctype>
int main()
{
std::string myString;
while(std::getline(std::cin, myString)) {
std::cout << "User Input: " << myString << "\n";
for(auto& c: myString) {
c = std::toupper(c);
}
std::cout << "Upper Case: " << myString << "\n";
}
}
Since you are dealing with ASCII, you can just use std::toupper.
No need to write custom code to do it, the standard library has you covered.

Trying to check entered text versus my own custom answers

here is what I attempted to throw together, unfortunately it's not doing what I want it to. What I want it to be doing is checking the entered text vs a few words that I consider correct. So, for example, if I want the only correct answers to be "thanks" or "please", how would I make the program check if the word the user entered is either "thanks" or "please"?
I have a feeling I can't just write B == 'funs etc.
help me out please:
#include <iostream>
using namespace std;
int main ()
{
string B;
for (;;)
{cout << "enter text here" << '\n' ;
cin >> B ;
if (B == 'fUNS'|| B == 'funs' || B == 'funzies')
{
cout << "correct!!!!!!" << endl;
break;
}
else
{
cout << "sorry, please try again" << endl;
continue;
}
}
return 0;
}
Unlike some languages using ' or " to enclose a sequence of characters produces very different results.
A single quote defines a single character literal e.g:
char a = 'A';
You can use multiple characters to define the value of an integer (although this is non-standard):
int a = 'ABCD';
A double quote defines a string literal which is a sequence of characters in an array:
const char str[5] = "ABCD";
Note the literal has a hidden null character at the end which is why it has 5 elements rather than 4. String literals are comparable and assignable with std::string:
std::string test( "ABCD" );
std::cout << test == "ABCD";
test = "EFGH";
std::cout << test == "ABCD";
I have a feeling I can't just write B == 'funs etc.
Yes, you can, since B is a std::string, which has an operator== defined. You just need to use " (which is used to define string literals) instead of ' (which is used to define character literals), eg:
if (B == "fUNS" || B == "funs" || B == "funzies")

`const char*' to `char'

I am new to programming and attempted to improve on my basic countdown timer. I don't know why I'm getting this error and other questions are in different situations and therefore don't suit my program.
//countdown timer using while loops, if else, strings and sleep
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
int main ()
{
char progend[5];
float a; /* a will be floating point */
cout << "Enter start the the number you want to count down from" << ".\n";
while (a>-1) { /* the main program is located here */
cin >> progend[5];
if (progend[5] = "end") /* if the user inputs end the program ends */
{
a = -1;
}
else if (progend [5] = "start")
{
cin >> a;
while (a>0) { /* the actual countdown timer*/
Sleep(100);
a = a - 0.1;
cout << a;
}
cout << "Finished!" << ".\n" << "Enter start then enter another number to count down from or enter end to close the program" << ".\n";
}
else
{
cout << "Enter yes or end";
}
}
return 0;
}
Any help would be appreciated.
char progend[5];
...
if (progend [5] = "start")
tries to assign string literal "start" to 6th character of progend array (which doesn't even exist). Note that even if this code tried to assign a character, writing into the array after its end would cause undefined behavior.
You could either use C-style strcmp:
if (strcmp(progend, "start") == 0)
or yet even better: since this is C++, use std::string objects instead:
std::string progend;
...
if (progend == "start") ... // <-- this will use std::string::operator==
You're trying to assign a char* to char, I'm assuming you want to compare .
So use strstr
if (strstr(progend,"end" )){
//...
}
Similarly all other places
But why not use std::string , when using C++
std::string progend;
if(progend.find("end") != std::string::npos)
{
}
You are assigning a const char * to a char variable in
if (progend[5] = "end")
progend[5] is an element of a char array that holds a char value. "end" cannot be assigned to it.
You can use std::string. Then compare it like
std::string progend;
...
if(progend == "end")
{
//your code
You made a number of different errors.
cin >> progend[5];
Here, you ask for a character input, instead of a string. What is more, index 5 is out of the bounds of the array (we start counting from 0).
progend[5] = "start"
Here, there are two errors. To compare for equality, you sholud use == instead of =. What you actually did is try to assign a value. What is more, "start" is a C-type String, or better a pointer to the first character of the String.
Why don't you simply use a String from the C++ STL?
#include <string>
using namespace std;
// etc.
String progend;
Also, replace all instances of progend[5] with progend, you are not refering to a specific position. Equality check must also be ==.
I hope this helps!!! :D