c++ count words in array - c++

I need to write a function that gets a string and count how many words there are in the string and how many letters. And then calculate the average of it.
A word in a string is a sequence of letters and numbers separated by one or more spaces.
First of all I have to check if the string is correct. The string must contain only lowercase letters, uppercase letters, and numbers only.
i didnt menage to count all sort of words correctly and also my function doesnt count the last letter.
#include <iostream>
using namespace std;
#include <string.h>
#define SIZE 50
float checkString(char string[]) {
float wordCounter = 0;
float letterCounter = 0;
bool isLegit = true;
int i = 0;
while (isLegit) {
if (((string[i] >= 48 && string[i] <= 57) ||
(string[i] >= 65 && string[i] <= 90) ||
(string[i] >= 97 && string[i] <= 122 ))) {
for (int j = 0; j <= strlen(string); j++) {
if ((string[j - 1] != ' ' && string[j] == ' ' &&
string[i + 1] != ' ')
|| j == (strlen(string) - 1)) {
wordCounter++;
}
else if (string[j] != ' ') {
letterCounter++;
cout << string[j];
}
}
cout << " The avareage is : " << (letterCounter /
wordCounter) << endl;
isLegit = false;
}
else {
return -1;
isLegit = false;
}
}
cout << "Number of words " << wordCounter << endl;
cout << "Number of letters " <<letterCounter << endl;
}
int main() {
char string[SIZE];
cout << "please enter a sentence " << endl;
cin.getline(string, SIZE);
checkString(string);
}

Instead of using char[] for strings, I suggest that you use std::string which can grow and shrink dynamically. It's one of the most common types to use in the standard C++ library. You can also make use of stringstreams which lets you put a string inside it and then you can extract the contents of the stringstream using >>, just like when reading from std::cin.
Example with comments in the code:
#include <iostream>
#include <sstream> // std::stringstream
#include <string> // std::string
// use std::string instead of a char[]
float checkString(const std::string& string) {
// put the string in a stringstream to extract word-by-word
std::istringstream is(string);
unsigned words = 0;
unsigned letters = 0;
std::string word;
// extract one word at a time from the stringstream:
while(is >> word) {
// erase invalid characters:
for(auto it = word.begin(); it != word.end();) {
// Don't use magic numbers. Put the character literals in the code so
// everyone can see what you mean
if((*it>='0' && *it<='9')||(*it>='A' && *it<='Z')||(*it>='a' && *it<='z')) {
// it was a valid char
++it;
} else {
// it was an invalid char, erase it
it = word.erase(it);
}
}
// if the word still has some characters in it, make it count:
if(word.size()) {
++words;
letters += word.size();
std::cout << '\'' << word << "'\n"; // for debugging
}
}
std::cout << "Number of words " << words << "\n";
std::cout << "Number of letters " << letters << "\n";
std::cout << "The average number of letters per word is "
<< static_cast<float>(letters) / words << '\n';
return 0.f; // not sure what you are supposed to return, but since the function
// signature says that you should return a float, you must return a float.
}
int main() {
checkString(" Hello !!! World, now let's see if it works. ");
}

I would like to add an additional answer. This answer is based on "more-modern" C++ and the usage of algorithms. You want to solve 3 tasks:
Check, if string is OK and matched to your expectations
Count the number of words in the given string
Count the number of letters
Calculate the ratio of words/letters
For all this you may use existings algorithms from the C++ standard library. In the attached example code, you will see a one-liner for each task.
The statements are somehow very simple, so that I will not explain much more. If there should be a question, I am happy to answer.
Please see here one possible example code:
#include <iostream>
#include <string>
#include <iterator>
#include <regex>
#include <algorithm>
#include <tuple>
#include <cctype>
std::regex re("\\w+");
std::tuple<bool, int, int, double> checkString(const std::string& str) {
// Check if string consists only of allowed values, spaces or alpha numerical
bool stringOK{ std::all_of(str.begin(), str.end(), [](const char c) { return std::isalnum(c) || std::isspace(c); }) };
// Count the number of words
int numberOfWords{ std::distance(std::sregex_token_iterator(str.begin(),str.end(), re, 1), {}) };
// Count the number of letters
int numberOfLetters{ std::count_if(str.begin(), str.end(), isalnum) };
// Return all calculated values
return std::make_tuple(stringOK, numberOfWords, numberOfLetters, static_cast<double>(numberOfWords)/ numberOfLetters);
}
int main() {
// Ask user to input string
std::cout << "Please enter a sentence:\n";
// Get string from user
if (std::string str{}; std::getline(std::cin, str)) {
// Analyze string
auto [stringOk, numberOfWords, numberOfLetters, ratio] = checkString(str);
// SHow result
std::cout << "\nString content check: " << (stringOk ? "OK" : "NOK") << "\nNumber of words: "
<< numberOfWords << "\nNumber of letters: " << numberOfLetters << "\nRatio: " << ratio << "\n";
}
return 0;
}
Of course there are many more other possible solutions. But, because of the simplicity of this solution, I showed this variant.

Related

Code gets stuck in loop (but loop itself doesn't keep going). C++ string

I am currently self-studying C++ with Schaum's outline book (which covers mostly C contents, or so I've been told, but whatever) and I have encountered some trouble with problem 9.8.
You are supposed to count the number of appearances of every different word in a given c++ string, for which I assumed each word was separated from the next one by a white space, a newline or a dot or coma (followed in these two last cases by another white space).
My code is the following:
#include <iostream>
#include <string>
using namespace std;
int main()
{ string s;
cout << "Enter text (enter \"$\" to stop input):\n";
getline(cin,s,'$');
string s2 = s, word;
int ini = 0, last, count_word = 0;
int count_1 = 0, count_2 = 0, count_3 = 0;
cout << "\nThe words found in the text, with its frequencies, are the following:\n";
for (ini; ini < s.length(); )
{ // we look for the next word in the string (at the end of each iteration
// ini is incremented in a quantity previous_word.length()
last = ini;
cout << "1: " << ++count_1 << endl;
while(true)
{ if (s[last] == ' ') break;
if (s[last] == '\n') break;
if (s[last] == ',') break;
if (s[last] == '.') break;
if (last > s.length()-1 ) break;
++last;
cout << "2: " << ++count_2 << endl;
}
--last; // last gives the position within s of the last letter of the current word
// now me create the word itself
word = s.substr(ini,last-ini+1); //because last-ini is word.length()-1
int found = s2.find(word);
while( found != s2.length() ) // the loop goes at least once
++count_word;
s2.erase(0,found+word.length()); // we erase the part of s2 where we have already looked
found = s2.find(word);
cout << "3: " << ++count_3 << endl;
cout << "\t["<<word<<"]: " << count_word;
++last;
s2 = s;
s2.erase(0,ini + word.length()); // we do this so that in the next iteration we don't look for
// the new word where we know it won't be.
if (s[last] == ' ' || s[last] == '\n') ini = last + 1;
if (s[last] == ',' || s[last] == '.') ini = last + 2;
count_word = 0;
}
}
When I ran the program nothing was sshown on screen, so I figured out that one of the loops must had been stuck (that is why I defined the variables count_1,2 and 3, to know if this was so).
However, after correctly counting the number of iterations for the fist word to be found, nothing else is printed and all I see is the command prompt (I mean the tiny white bar) and I cannot even stop the program by using ctrl z.
This is a very complicated method for a very simple problem. You can just use a stringstream to extract each word seperated by a white space. You then just take the extracted word and increment the word counter using a std::map<std::string, int>.
My take on this:
#include <iostream>
#include <map>
#include <string>
#include <sstream>
int main() {
std::map<std::string, int> word_to_count;
std::string in;
std::getline(std::cin, in);
std::stringstream s(in);
std::string temp_word;
while (s >> temp_word) {
word_to_count[temp_word]++;
}
for (const auto& x : word_to_count) {
std::cout << x.first << ": " << x.second << std::endl;
}
return 0;
}
input
hello world hello world test
Output
hello: 2
test: 1
world: 2
Keep in mind this is just one of many possible solutions, so just take this as inspiration :).

Trouble with strings and arrays

My goal is to make a program that inputs a phone number and outputs it in a standard format. It skips over any non-number characters, will output if there are not enough digits, and will also skip over any digits after the first ten digits. My raptor worked without a hitch, but it's been difficult to translate it to C++.
I am using Microsoft Visual Studio.
The problem is it is not running. If I put in anything more then one number in, I receive a fail error.
I am having some difficulty running this code.
Any and all help and advice would be greatly appreciated.
#include <iostream>
#include <string>
using namespace std;
void format(char outArray[], string inNumber)
{
outArray[0] = '(';
outArray[4] = ')';
outArray[5] = ' ';
outArray[9] = '-';
outArray[1] = inNumber[0];
outArray[2] = inNumber[1];
outArray[3] = inNumber[2];
outArray[6] = inNumber[3];
outArray[7] = inNumber[4];
outArray[8] = inNumber[5];
outArray[10] = inNumber[6];
outArray[11] = inNumber[7];
outArray[12] = inNumber[8];
outArray[13] = inNumber[9];
}
int main()
{
string phone, inNumber;
cout << "Please enter a phone number: ";
cin >> phone;
int index = 0;
int num = 0;
char outArray[14];
for (index; phone[index] >= '0' && phone[index] <= '9'; index++)
{
inNumber[num] = phone[index];
num++;
}
if (inNumber.size() > 10)
{
format(outArray, inNumber);
cout << "The properly formatted number is: ";
cout << outArray;
}
else {
cout << "Input must contain at least 10 digits." << endl;
}
system("pause");
return 0;
}
A few things to note:
Use std::string instead array of char array.
You do not need to check charters using a for loop unless you are not sure about the input(phone). However, if that's the case, use std::getline() to get the input and parse as follows using a range-based for loop.
You can use std::isdigit to check the character is a digit.
My goal is to make a program that inputs a phone number and outputs it
in a standard format. It skips over any non-number characters, will
output if there are not enough digits, and will also skip over any
digits after the first ten digits.
That means the number should have a minimum length of 10. Then the
if statement should be if (inNumber.size() >= 10)
Need a pass by ref call in the function format(), since you want to change the content of outArray. Additionally, inNumber could be a
const ref, since we do not change this string.
Updated code: (See a sample code online)
#include <iostream>
#include <string>
#include <cstddef> // std::isdigit, std::size_t
void format(std::string& outArray, const std::string& inNumber) /* noexcept */
{
for (std::size_t index = 0; index < 10; ++index)
{
if (index == 0) outArray += '(';
else if (index == 3) outArray += ") ";
else if (index == 6) outArray += '-';
outArray += inNumber[index];
}
}
int main()
{
std::string phone;
std::cout << "Please enter a phone number: ";
std::getline(std::cin, phone);
std::string inNumber;
for (char letter : phone)
if (std::isdigit(static_cast<unsigned char>(letter))) // check the letter == digits
inNumber += letter;
if (inNumber.size() >= 10)
{
std::string outArray;
format(outArray, inNumber);
std::cout << "The properly formatted number is: ";
std::cout << outArray;
}
else {
std::cout << "Input must contain at least 10 digits." << std::endl;
}
return 0;
}
inNumber[num] = phone[index]; //undefined behavior.
You cannot subscript inNumber now, since its capacity is 0, thus it can not store or access any element here.
You may need to use string's constructor whose parameter has a size_t type or string::reserve or string::resize.
And I'm happy to see cppreference get more complete now, learn to use it: http://en.cppreference.com/w/cpp/string/basic_string
BTW, this function won't do anything you want to:
void format(char outArray[], string inNumber)
maybe you'd like to have an signature like this?
void format(char outArray[], string& inNumber)

Parsing comma-delimited numbers in C++

I have a quick question for everyone. I'm trying to write a simple code to extract numbers form user input and save them to an int array, but I'm having a hard time wrapping my mind around how to make it work. The code shown below works well for single-digit numbers, but not so much for numbers with more than 1 digit.
For instance, if user enters: 1,2,3,4,50,60 here is what I get:
Enter numbers (must be comma delimited): 1,2,3,4,50,60
My numbers are: 12345060
My parsed numbers are: 1
My parsed numbers are: 2
My parsed numbers are: 3
My parsed numbers are: 4
My parsed numbers are: 5
My parsed numbers are: 0
Question: how can I modify this simple piece of code to accurately capture numbers with more than 1 digit? Thanks in advance!!
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
using namespace std;
// set up some variables
int numbers[100];
int main() {
// Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
cout << endl << endl << "Enter numbers (must be comma delimited): ";
string nums_in;
getline(cin, nums_in);
nums_in.erase(remove(nums_in.begin(), nums_in.end(), ','), nums_in.end()); // remove the unwanted commas
cout << "My numbers are: " << nums_in << endl;
// convert each char into int
for (int o = 0; o < 6; o++) {
istringstream buf(nums_in.substr(o,1));
buf >> numbers[o];
cout << "My parsed numbers are: " << numbers[o] << endl;
}
cout << endl << endl;
cout << "Done." << endl;
return 0;
}
In your program, you first remove the "unwanted" commas in the input string and then run into the problem that you cannot distinguish the numbers in the input line any more. So it seems as if these commas are not unwanted after all. The solution is to parse the string step by step without removing the commas first, as you need them to split up the input string. Here is an example.
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
int main() {
// Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
std::cout << std::endl << std::endl << "Enter numbers (must be comma delimited): ";
std::string nums_in;
std::getline(std::cin, nums_in);
// Now parse
std::vector<int> data;
std::istringstream buf(nums_in);
while (!buf.eof()) {
int this_number;
buf >> this_number;
if (buf.bad()) {
std::cerr << "Number formatting error!\n";
return 1;
}
data.push_back(this_number);
char comma = 0;
buf >> comma;
if (!buf.eof()) {
if (buf.fail()) {
std::cerr << "Could not read comma.\n";
return 1;
}
if (comma!=',') {
std::cerr << "Found no comma but '" << comma << "' instead !\n";
return 1;
}
}
}
std::cout << "My numbers are:";
for (auto a : data) {
std::cout << " " << a;
}
std::cout << std::endl;
std::cout << "Done." << std::endl;
return 0;
}
Note that I did not use "using namespace std;" as it is considered to be bad style. Also, I used a C++11 feature for printing out the values and used a vector to store the numbers - in your code, typing in a line with 200 numbers would lead to a crash (or other bad behavior). Finally, the parsing error handling is not yet complete. Making it complete and correct is left as an exercise. An alternative to the istringstream-based approach would be to first split the line by the commas and then to read all numbers separately using istringstreams.
By the way, your question is so practical that it would have been better suited for the standard stackexchange site - the connection to computer science is quite weak.
To solve this kind of problems, you have to write a scanner. The scanner breaks input into tokens. Once you have the ability to break the input into tokens, you can check the order of tokens (see parsers).
In your case you have three tokens: number, comma and end. An example of valid input: number comma number end. Another example: end (empty input). An example of invalid input: number number end (there is no comma between numbers).
Below it is a possible solution to your problem. get_token reads a token from input and stores it in token and number globals. get_numbers reads tokens, checks the syntax and stores the numbers in numbers; the count of numbers is stored in count (also global variables).
#include <iostream>
#include <cctype>
enum { max_count = 100 };
int numbers[max_count];
int count;
enum token_type
{
token_unknwon,
token_end,
token_comma,
token_number
};
token_type token;
int number;
token_type get_token()
{
char c;
// get a character, but skip ws except newline
while ( std::cin.get( c ) && c != '\n' && std::isspace( c ) )
;
if ( ! std::cin || c == '\n' )
return token = token_end;
if ( c == ',' )
return token = token_comma;
if ( std::isdigit( c ) )
{
std::cin.unget();
std::cin >> number;
return token = token_number;
}
return token_unknwon;
}
enum error_type
{
error_ok,
error_number_expected,
error_too_many_numbers,
error_comma_expected
};
int get_numbers()
{
//
if ( get_token() == token_end )
return error_ok; // empty input
while ( true )
{
// number expected
if ( token != token_number )
return error_number_expected;
// store the number
if ( count >= max_count )
return error_too_many_numbers;
numbers[count++] = number;
// this might be the last number
if ( get_token() == token_end )
return error_ok;
// not the last number, comma expected
if ( token != token_comma )
return error_comma_expected;
// prepare next token
get_token();
}
}
int main()
{
//...
switch ( get_numbers() )
{
case error_ok: break;
case error_comma_expected: std::cout << "comma expected"; return -1;
case error_number_expected: std::cout << "number expected"; return -2;
case error_too_many_numbers: std::cout << "too many numbers"; return -3;
}
//
std::cout << count << " number(s): ";
for ( int i = 0; i < count; ++i )
std::cout << numbers[i] << ' ';
//...
return 0;
}
This task can be easily done using std::getline to read the entire line in a string and then parse that string using a std::istringstream to extract the individual numbers and skip the commas.
#include <iostream>
#include <sstream>
#include <vector>
using std::cout;
int main() {
// Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
cout << "\nEnter numbers (must be comma delimited): ";
int x;
std::vector<int> v;
std::string str_in;
// read the whole line then use a stringstream buffer to extract the numbers
std::getline(std::cin, str_in);
std::istringstream str_buf{str_in};
while ( str_buf >> x ) {
v.push_back(x);
// If the next char in input is a comma, extract it. std::ws discards whitespace
if ( ( str_buf >> std::ws).peek() == ',' )
str_buf.ignore();
}
cout << "\nMy parsed numbers are:\n";
for ( int i : v ) {
cout << i << '\n';
}
cout << "\nDone.\n";
return 0;
}
Hm... How about parsing the string without removing the commas? Read the string character for character, placing each character in a temp buffer until you hit a comma, then convert the temp buffer to an int and store it in the vector. Empty the temp buffer and repeat.
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
// set up some variables
vector<int> numbers(0);
int main() {
// Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
cout << endl << endl << "Enter numbers (must be comma delimited): ";
string nums_in;
getline(cin, nums_in);
cout << "My numbers are: " << nums_in << endl;
string s_tmp = "";
int i_tmp;
for(vector<int>::size_type i = 0, len = nums_in.size(); i < len; i++){
if( nums_in[i] == ',' ){
if(s_tmp.size() > 0){
i_tmp = std::stoi(s_tmp);
numbers.push_back(i_tmp);
}
s_tmp = "";
}
else if( i == len-1){
s_tmp += nums_in[i];
i_tmp = std::stoi(s_tmp);
numbers.push_back(i_tmp);
cout << "My parsed numbers are:" << i_tmp << endl;
}
else {
s_tmp += nums_in[i];
}
}
cout << endl << endl;
cout << "Done." << endl;
return 0;
}

C++ Identifying the Frequency of words occurring in a sentence

What is the best STL to use for this task? I've been using Map,
and I couldn't get it to work. I'm not sure how I am supposed to check the number of same words that occur in the sentence for example:
I love him, I love her, he love her.
So I want the program to prompt the user to enter an integer, lets say i enter 3, the output will be love as the same word occurs 3 times in the sentence. But what method to use if I want to do a program like this?
Currently my program prompts for the user to enter the word, and then it shall return how many time that word occurs, which for word love, is 3. but now i want it the other way round. Can it be done? Using which STL will be better?
I assume you use a map to store the number of occurrences.
Well,you first have to understand this,since you are using a map,the key is unique while the stored data may not be unique.
Consider a map, x
with contents
x["I"]=3
x["Love"]=3
x["C"]=5
There is unique a mapping from the key to the value,and not the other way round,if you want this one to one mapping ,i would suggest a different data structure.If you want to use map,and still search for an element,using STL search function or your own.Or you can write your search function.
search().
map<string,int>::iterator ser;
cin>>check;
for(ser=x.begin();ser!=x.end();++ser)
{
if(ser->second==check)
{
cout<<"Word"<<ser->first<<endl;
break;
}
}
First build the mapping from word to count and then build the reverse multi-mapping from that. Finally, you can determine which words occur with a given frequency:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <utility>
int main()
{
std::string str("I love him, I love her, he love her");
std::istringstream ss(str);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::map<std::string, int> word_count;
std::for_each(begin, end, [&](const std::string& s)
{
++word_count[s];
});
std::multimap<int, std::string> count_words;
std::for_each(word_count.begin(), word_count.end(),
[&](const std::pair<std::string, int>& p)
{
count_words.insert(std::make_pair(p.second, p.first));
});
auto its = count_words.equal_range(3);
std::for_each(its.first, its.second,
[](const std::pair<int, std::string>& p)
{
std::cout << p.second << std::endl;
});
}
/******************************************************************
Name : Paul Rodgers
Source : HW1.CPP
Compiler : Visual C++ .NET
Action : Program will read in from standard input and determine the
frequency of word lengths found in input. An appropriate
table is also displayed. Maximum word length is 15 characters
words greater then 15 are counted as length 15.
Average word length also displayed.
Note : Words include hyphenated and ones with apostrophes. Words with
apostrophes, i.e. Jim's, will count the apostrophe as part of the
word length. Hyphen is counted if word on same line, else not.
Also an int array is used to hold the number of words with
length associated with matching subscript, with subscript 0
not being used. So subscript 1 corresponds to word length of 1,
subscript 2 to word length of 2 and so on.
------------------------------------------------------------------------*/
#include <iostream>
#include <ctype.h>
#include <iomanip>
using namespace std;
int NextWordLength(void); // function prototypes
void DisplayFrequencyTable(const int Words[]);
const int WORD_LENGTH = 16; // global constant for array
void main()
{
int WordLength; // actual length of word 0 to X
int NumOfWords[WORD_LENGTH] = {0}; // array holds # of lengths of words
WordLength = NextWordLength();
while (WordLength) // continue to loop until no word, i.e. 0
{ // increment length counter
(WordLength <= 14) ? (++NumOfWords[WordLength]) : (++NumOfWords[15]);
WordLength = NextWordLength();
}
DisplayFrequencyTable(NumOfWords);
}
/********************** NextWordLength ********************************
Action : Will determine the length of the next word. Hyphenated words and
words with apostrophes are counted as one word accordingly
Parameters : none
Returns : the length of word, 0 if none, i.e. end of file
-----------------------------------------------------------------------*/
int NextWordLength(void)
{
char Ch;
int EndOfWord = 0, //tells when we have read in one word
LengthOfWord = 0;
Ch = cin.get(); // get first character
while (!cin.eof() && !EndOfWord)
{
while (isspace(Ch) || ispunct(Ch)) // Skips leading white spaces
Ch = cin.get(); // and leading punctation marks
if (isalnum(Ch)) // if character is a letter or number
++LengthOfWord; // then increment word length
Ch = cin.get(); // get next character
if ((Ch == '-') && (cin.peek() == '\n')) //check for hyphenated word over two lines
{
Ch = cin.get(); // don't count hyphen and remove the newline char
Ch = cin.get(); // get next character then on next line
}
if ((Ch == '-') && (isalpha(cin.peek()))) //check for hyphenated word in one line
{
++LengthOfWord; // count the hyphen as part of word
Ch = cin.get(); // get next character
}
if ((Ch == '\'') && (isalpha(cin.peek()))) // check for apostrophe in word
{
++LengthOfWord; // count apostrophe in word length
Ch = cin.get(); // and get next letter
}
if (isspace(Ch) || ispunct(Ch) || cin.eof()) // is it end of word
EndOfWord++;
}
return LengthOfWord;
}
/*********************** DisplayFrequencyTable **************************
Action : Will display the frequency of length of words along with the
average word length
Parameters
IN : Pointer to array holding the frequency of the lengths
Returns : Nothing
Precondition: for loop does not go beyond WORD_LENGTH
------------------------------------------------------------------------*/
void DisplayFrequencyTable(const int Words[])
{
int TotalWords = 0, TotalLength = 0;
cout << "\nWord Length Frequency\n";
cout << "------------ ----------\n";
for (int i = 1; i <= WORD_LENGTH-1; i++)
{
cout << setw(4) << i << setw(18) << Words[i] << endl;
TotalLength += (i*Words[i]);
TotalWords += Words[i];
}
cout << "\nAverage word length is ";
if (TotalLength)
cout << float(TotalLength)/TotalWords << endl;
else
cout << 0 << endl;
}
#include<iostream>
#include<string>
#include<vector>
#include<cstddef>
#include<map>
using std::cout;
using std::cin;
using std::string;
using std::endl;
using std::vector;
using std::map;
int main() {
cout << "Please enter a string: " << endl;
string str;
getline(cin, str, '\n');
size_t str_len = str.size();
cout << endl << endl;
size_t i = 0, j = 0;
bool pop = false;
map<string, int> myMap;
for (size_t k = 0; k < str_len-1; k++) {
if (((k == 0) && isalpha(str[0])) || (!(isalpha(str[k-1])) && isalpha(str[k])))
i = k;
if ( isalpha(str[k]) && !(isalpha(str[k+1])) ) {
j = k;
pop = true;
}
if ( (k == str_len-2) && isalpha(str[k+1]) ) {
j = k+1;
pop = true;
}
if ( (i <= j) && pop ) {
string tmp = str.substr(i, j-i+1);
cout << tmp << '\t';
myMap[tmp]++;
pop = false;
}
}
cout << endl << endl;
map<string, int>::iterator itr, end = myMap.end();
for (itr = myMap.begin(); itr != end; itr++)
cout << itr->first << "\t - - - - - \t" << itr->second << endl;
cout << endl;
return 0;
}

Palindrome program isn't comparing properly

I'm currently learning about vectors and trying to make a palindrome program using them. This is a simple program and so far, I'm trying to make it identify "I am what am I." as a palindrome properly. This is my program so far:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
vector <string> sentVec;
void getSent(string sent);
void readBackwards(string sent);
int main()
{
string sent;
getSent(sent);
readBackwards(sent);
return 0;
}
void getSent(string sent)
{
cout << "Enter your sentence:" << endl;
getline (cin,sent);
string currentWord, currentLetter;
for (int i = 0; i < sent.length(); i++)
{
currentLetter = sent[i];
if (currentLetter == " ") // inserts word
{
currentWord += sent[i];
sentVec.push_back(currentWord);
currentWord = "";
}
else if (currentLetter == ".") // inserts period
{
sentVec.push_back(currentWord);
currentWord = sent[i];
sentVec.push_back(currentWord);
}
else
{
currentWord += sent[i];
}
}
}
void readBackwards(string sent)
{
string sentForwards, sentBackwards;
// create sentence forwards and backwards without the period.
for (int i = 0; i < sentVec.size() - 1; i++)
{
sentForwards += sentVec[i];
}
for (int j = sentVec.size() - 2; j >= 0; j--)
{
sentBackwards += sentVec[j];
if (j == sentVec.size() - 2)
{
sentBackwards += " ";
}
}
cout << "Sentence forwards is: " << sentForwards << endl;
cout << "Sentence backwards is: " << sentBackwards << endl;
if (sentForwards == sentBackwards)
{
cout << "This sentence reads the same backwards as forwards." << endl;
}
else
{
cout << "This sentence does not read the same backwards as forwards." << endl;
}
}
When I run this program, it prints:
Enter your sentence:
I am what am I.
Sentence forwards is: I am what am I
Sentence backwards is: I am what am I
This sentence does not read the same backwards as forwards.
Why does this not trigger the if loop when comparing the two sentences?
Because sentBackwards isn't the same as sentForwards, because sentBackwards has a trailing whitespace at the end, and thus they aren't the same.
I am unsure how your program detects palindromes, but here is a simple iterative method:
#include <string>
bool isPalindrome(std::string in) {
for (int i = 0; i < in.size() / 2; i++) {
if (in[i] != in[in.size() - 1 - i]) {
return false;
}
}
return true;
}
It returns true if the string passed as an argument is a palindrome
You should not only learn about vector, but also the STL algorithm functions such as std::reverse.
As the other answer given pointed out, one vector has a trailing whitespace. You could have avoided all of that by simply taking the original vector, copying it to another vector, and calling std::reverse. There is no need to write a loop:
void readBackwards()
{
// copy the vector
std::vector<std::string> sentBackwards = sentVec;
// reverse it
std::reverse(sentBackwards.begin(), sentBackwards.end());
// see if they're equal
if (sentVec == sentBackwards)
cout << "This sentence reads the same backwards as forwards." << endl;
else
cout << "This sentence does not read the same backwards as forwards." << endl;
}
This works, since std::vector has an overloaded operator == that compares the items in each of the two vectors and returns true if all items are the same.
In addition to this, reading into a vector can be accomplished much more easily than what you attempted.
#include <sstream>
#include <algorithm>
//...
void getSent(string sent)
{
// remove the periods(s)
auto iter = std::remove_if(sent.begin(), sent.end(), [] (char ch) { return ch == '.';});
sent.erase(iter, sent.end());
// copy the data to a vector
std::istringstream iss(sent);
string currentword;
while ( iss >> currentword)
sentVec.push_back(currentword);
}
Note that we use the std::istringstream to serve as the space delimited parser, alleviating the need to write a loop looking for the space. Also, the std::remove_if algorithm is used to remove any period characters from the string before we start to store the individual strings into a vector.
So basically, the only loop in this whole setup is the while to read from the stream into the vector. Everything else is accomplished by using the algorithm functions, and taking advantage of the various member functions of std::vector (like the overloaded ==)