Comparing character arrays is not working - c++

I have found a problem while trying to use "character arrays" in an if condition. It should be true with my input, but it is not.
Here is my code:
#include <iostream>
using namespace std;
int main()
{
char a[20];
cin.get(a,15, '\n'); // for input
cout << a << endl; // output
if (a == "hello world") { // checking if condition
cout << "how are you?" << endl;
}
}

You should be using std::string, not some char[].
Then the equality will work as you expect.
This char[20], strcmp nonsense is archaic and error-prone. There is no place for it here.

You need strcmp() ( include the header <cstring> ) to check equality of character arrays.
Try
if( !strcmp(a,"hello world"))
BTW, since you are on c++, it's better to use std::string, so you can easily do
std::string a;
getline( std::cin , a );
if(a=="hello world") //checking if condition
{
std::cout<<"how are you";
}

Related

Why string receives numbers in this while loop?

A string is a variable-length sequence of characters. Why does it receive anything and prints it out?
#include <iostream>
#include <string>
using namespace std;
int main (){
string word;
while (cin >> word){
cout << word << endl;
}
return 0;
}
In this program, we read into a string, not an int. How can I fall out of this while loop i.e hit an invalid input?
Reading into a string will not fail, all input is valid. You may add any validation you like once the string is read.
Your question is a little vague, but if you're asking how to end the loop you can do it with an end-of-file. On Linux this you can generate one from the console with Control-D, and on Windows with Control-Z plus Enter.
Because you are taking the input in a string and string is a sequence of characters .so it takes anything you input from the keyboard either it is number or alphabet or any special character .
How can I check for invalid input?
If you could define what you consider to be "invalid input" you can filter for it in one of the std::string helper methods. In your example you eluded to numbers not being strings... so if you want to do something with pure numbers...
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main (){
string word;
while (cin >> word){
bool isNumber = (word.find_first_not_of("0123456789") == std::string::npos);
if (isNumber){
cout << "it's a number! " << word << endl;
}else{
cout << word << endl;
}
}
return 0;
}

How do I check for stored "\t" in a string?

Can someone explain to me how to properly search for a "tab" character stored in a string class?
For example:
text.txt contents:
std::cout << "Hello"; // contains one tab space
User enters on prompt: ./a.out < text.txt
main.cpp:
string arrey;
getline(cin, arrey);
int i = 0;
while( i != 10){
if(arrey[i] == "\t") // error here
{
std::cout << "I found a tab!!!!"
}
i++;
}
Since there is only one tab space in the textfile, I am assuming it is stored in index [0], but the problem is that I can't seem to make a comparison and I don't know any other way of searching it. Can someone help explain an alternative?
Error: ISO C++ forbids comparison between pointer and integer
First of all, what is i? And secondly, when you use array-indexing of a std::string object, you get a character (i.e. a char) and not a string.
The char is converted to an int and then the compiler tries to compare that int with the pointer to the string literal, and you can't compare plain integers with pointers.
You can however compare a character with another character, like in
arrey[i] == '\t'
std::string::find() might help.
Try this:
...
if(arrey.find('\t') != string::npos)
{
std::cout << "I found a tab!!!!";
}
More info on std::string::find is available here.
Why not using what C++ library provides? You could do it like this:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string arrey;
getline(cin, arrey);
if (arrey.find("\t") != std::string::npos) {
std::cout << "found a tab!" << '\n';
}
return 0;
}
The code is based on this answer. Here is the ref for std::find.
About your edit, how are sure that the input is going to be 10 positions? That might be too little or too big! If it is less than the actual size of the input, you won't look all the characters of the string and if it is too big, you are going to overflow!
You could use .size(), which says the size of the string and use a for loop like this:
#include <iostream>
#include <string>
using namespace std;
int main() {
string arrey;
getline(cin, arrey);
for(unsigned int i = 0; i < arrey.size(); ++i) {
if (arrey[i] == '\t') {
std::cout << "I found a tab!!!!";
}
}
return 0;
}

How to use cin with unknown input types?

I have a C++ program which needs to take user input. The user input will either be two ints (for example: 1 3) or it will be a char (for example: s).
I know I can get the twos ints like this:
cin >> x >> y;
But how do I go about getting the value of the cin if a char is input instead? I know cin.fail() will be called but when I call cin.get(), it does not retrieve the character that was input.
Thanks for the help!
Use std::getline to read the input into a string, then use std::istringstream to parse the values out.
You can do this in c++11. This solution is robust, will ignore spaces.
This is compiled with clang++-libc++ in ubuntu 13.10. Note that gcc doesn't have a full regex implementation yet, but you could use Boost.Regex as an alternative.
EDIT: Added negative numbers handling.
#include <regex>
#include <iostream>
#include <string>
#include <utility>
using namespace std;
int main() {
regex pattern(R"(\s*(-?\d+)\s+(-?\d+)\s*|\s*([[:alpha:]])\s*)");
string input;
smatch match;
char a_char;
pair<int, int> two_ints;
while (getline(cin, input)) {
if (regex_match(input, match, pattern)) {
if (match[3].matched) {
cout << match[3] << endl;
a_char = match[3].str()[0];
}
else {
cout << match[1] << " " << match[2] << endl;
two_ints = {stoi(match[1]), stoi(match[2])};
}
}
}
}

C++ comparing the index of a string to another string?

How can I compare a single character from a string, and another string (which may or may not be greater than one character)
This program gives me almost 300 lines of random errors. The errors don't reference a specific line number either, just a lot of stuff about "char* ", "", or "std::to_string".
#include <iostream>
#include <string>
using std::cout;
using std::string;
int main() {
string str = "MDCXIV";
string test = "D";
if (test == str[4]) { // This line causes the problems
cout << test << endl;
}
return 0;
}
str[4] is a char type, which will not compare with a string.
Compare apples with apples.
Use
test[0] == str[4]
instead.
You need to convert str[4] (which is a char) to a string before you can compare it to another string. Here's a simple way to do this
if (test == string(1, str[4])) {
You're comparing a char to a std::string, this is not a valid comparison.
You're looking for std::string::find, as follows:
if( test.find( str[4] ) != std::string::npos ) cout << test << "\n";
Note that this will return true if test contains str[4].
You're mixing types. It doesn't know how to compare a string (test) to a char (str[4]).
If you change test to a char that will work fine. Or reference the specific character within test you want to compare such as if (test[0] == str[4]) it should compile and run.
However, as this is merely an example and not really the true question what you'll want to do is look at the functionality that the std::string class supplies
Also you need "D" to be a char value not a string value if you are comparing it like that.
std::string myString = "Hello World";
const char *myStringChars = myString.c_str();
You have to turn it into a char array before can access it. Unless you do.
str.at(i);
which you can also write as
str[i] <-- what you did.
Essentially, this all boils down to test needs to initialized like char test = 'D';
Final Output..
#include <iostream>
#include <string>
using std::cout;
using std::string;
int main() {
string str = "MDCXIV";
char test = 'D';
if (test == str[4]) { // This line causes NO problems
cout << test << endl;
}
return 0;
}
I think you might be mixing python with c++. In c++ 'g' refers to a single character g not a string of length 1. "g" refers to an array (string) which is 1 character long and looks like ['g']. So as you can see, if you compare a single character to an array of characters no matter if the array is a single character long, this operation is not defined.
This will work if define it yourself by building a class which is able to compare string of one character long to a single character. Or just overload the == operator for doing just that
Example:
#include <iostream>
#include <string>
using std::cout;
using std::string;
using std::endl;
bool operator == ( const string &lh, const char &rh) {
if (lh.length() == 1) return lh[0] == rh;
return 0;
}
int main() {
string str = "MDCXIV";
string test = "D";
if (test == str[4]) {
cout << test << endl;
}
else cout << "Not a match\n";
return 0;
}

Counting occurrences of letter in a file

I'm trying to count the number of times each letter appears in a file. When I run the code below it counts "Z" twice. Can anyone explain why?
The test data is:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
#include <iostream> //Required if your program does any I/O
#include <iomanip> //Required for output formatting
#include <fstream> //Required for file I/O
#include <string> //Required if your program uses C++ strings
#include <cmath> //Required for complex math functions
#include <cctype> //Required for letter case conversion
using namespace std; //Required for ANSI C++ 1998 standard.
int main ()
{
string reply;
string inputFileName;
ifstream inputFile;
char character;
int letterCount[127] = {};
cout << "Input file name: ";
getline(cin, inputFileName);
// Open the input file.
inputFile.open(inputFileName.c_str()); // Need .c_str() to convert a C++ string to a C-style string
// Check the file opened successfully.
if ( ! inputFile.is_open())
{
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
while ( inputFile.peek() != EOF )
{
inputFile >> character;
//toupper(character);
letterCount[static_cast<int>(character)]++;
}
for (int iteration = 0; iteration <= 127; iteration++)
{
if ( letterCount[iteration] > 0 )
{
cout << static_cast<char>(iteration) << " " << letterCount[iteration] << endl;
}
}
system("pause");
exit(0);
}
As others have pointed out, you have two Qs in the input. The reason you have two Zs is that the last
inputFile >> character;
(probably when there's just a newline character left in the stream, hence not EOF) fails to convert anything, leaving a 'Z' in the global 'character' from the previous iteration. Try inspecting inputFile.fail() afterwards to see this:
while (inputFile.peek() != EOF)
{
inputFile >> character;
if (!inputFile.fail())
{
letterCount[static_cast<int>(character)]++;
}
}
The idiomatic way to write the loop, and which also fixes your 'Z' problem, is:
while (inputFile >> character)
{
letterCount[static_cast<int>(character)]++;
}
There are two Q's in your uppercase string. I believe the reason you get two counts for Z is that you should check for EOF after reading the character, not before, but I am not sure about that.
Well, others already have pointed out the error in your code.
But here is one elegant way you can read the file and count the letters in it:
struct letter_only: std::ctype<char>
{
letter_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['A'], &rc['z'+1], std::ctype_base::alpha);
return &rc[0];
}
};
struct Counter
{
std::map<char, int> letterCount;
void operator()(char item)
{
if ( item != std::ctype_base::space)
++letterCount[tolower(item)]; //remove tolower if you want case-sensitive solution!
}
operator std::map<char, int>() { return letterCount ; }
};
int main()
{
ifstream input;
input.imbue(std::locale(std::locale(), new letter_only())); //enable reading only leters only!
input.open("filename.txt");
istream_iterator<char> start(input);
istream_iterator<char> end;
std::map<char, int> letterCount = std::for_each(start, end, Counter());
for (std::map<char, int>::iterator it = letterCount.begin(); it != letterCount.end(); ++it)
{
cout << it->first <<" : "<< it->second << endl;
}
}
This is modified (untested) version of this solution:
Elegant ways to count the frequency of words in a file
For one thing, you do have two Q's in the input.
Regarding Z, #Jeremiah is probably right in that it is doubly counted due to it being the last character, and your code not detecting EOF properly. This can be easily verified by e.g. changing the order of input characters.
As a side note, here
for (int iteration = 0; iteration <= 127; iteration++)
your index goes out of bounds; either the loop condition should be iteration < 127, or your array declared as int letterCount[128].
Given that you apparently only want to count English letters, it seems like you should be able to simplify your code considerably:
int main(int argc, char **argv) {
std::ifstream infile(argv[1]);
char ch;
static int counts[26];
while (infile >> ch)
if (isalpha(ch))
++counts[tolower(ch)-'a'];
for (int i=0; i<26; i++)
std::cout << 'A' + i << ": " << counts[i] <<"\n";
return 0;
}
Of course, there are quite a few more possibilities. Compared to #Nawaz's code (for example), this is obviously quite a bit shorter and simpler -- but it's also more limited (e.g., as it stands, it only works with un-accented English characters). It's pretty much restricted to the basic ASCII letters -- EBCDIC encoding, ISO 8859-x, or Unicode will break it completely.
His also makes it easy to apply the "letters only" filtration to any file. Choosing between them depends on whether you want/need/can use that flexibility or not. If you only care about the letters mentioned in the question, and only on typical machines that use some superset of ASCII, this code will handle the job more easily -- but if you need more than that, it's not suitable at all.