Why doesn't the push_back function accept the value/parameter? - c++

I am trying to store some specific characters of a string in a vector. When I want to push back the characters though, there is a problem with the value and I do not know why. Going over the cpp reference page didn't help me unfortunately. Could someone please help?
Here is the code:
int main()
{
std::string str1 = "xxxGGxx$xxxGxTxGx";
std::vector<std::string> vec;
std::vector<std::string>::iterator it;
for(auto &ch:str1)
{
if(ch == 'G' || ch == '$' || ch == 'T')
{
vec.push_back(ch); //Problem: ch not accepted
}
}
for(it = vec.begin(); it!=vec.end(); it++)
{
std::cout << *it;
}
}

Vector needs to be of type char, not string.

The reason vec.push_back(ch); does not work is because vec is a vector of strings and not a vector of char. push_back() only accepts the type stored inside the vector, in this case string. A vector<int> cannot push_back a string because a string can't be implicitly converted to an int. It has to somehow be converted to an int first then pushed back. Since a char can't be implicitly converted into a string the compiler gets confused and thinks its impossible.
There are two simple alternatives:
Instead of using vector<string> use vector<char> that way push_back() will append characters.
vector<char> vec;
char ch = 'a';
vec.push_back(ch); // both these work
vec.push_back('b'); // both these work
Or, Convert your char into a string and then call push_back onto your string.
string str(1, ch); // Creates a string containing 1 character equal to ch
vec.push_back(str); // Push back our string

Related

Using toupper for first character in the vector string

How to use toupper() to convert the first letter to uppercase of each element inside a vector of strings?
This is what I've tried...
string word;
vector<string> text;
while(cin >> word){
text.push_back(word);
}
for(decltype(text.size()) i = 0; i != text.size()) {
text[0] = toupper(text);
}
You can simply do this,
string word;
vector<string> text;
while(cin >> word){
word[0] = static_cast<char>(toupper(static_cast<int>(word[0])));;
text.push_back(word);
}
Now you don't have to iterate through the word list to change the first letter of every entry to upper.
for(auto& s : text)
if (!s.empty()) s[0] = std::toupper(s[0]);
Or more fancy:
std::transform(std::istream_iterator<std::string>{std::cin}, {},
std::back_inserter(text),
[](auto s) {
if (!s.empty()) s[0] = std::toupper(s[0]);
return s;
});
There are a couple of problems with your code.
Your 2nd loop runs endlessly, you need to add ++i to the end of the loop to actually iterate each string in the vector and terminate the loop when the end of the vector is reached:
for(decltype(text.size()) i = 0; i != text.size(); ++i)
On a side note, you can replace decltype(text.size()) with vector<string>::size_type instead, or decltype(text)::size_type.
A range-based for loop would avoid both issues:
for(string &str : text)
Regarding your actual error, this line does not compile:
text[0] = toupper(text);
Because toupper() takes a single character as input, but you are passing it the vector itself, rather than a single character from a single string in the vector. You would have needed to do this instead:
text[i][0] = toupper(text[i][0]);
However, you actually need to convert characters to unsigned char when passing them to toupper(), eg (I'm separating each step so you can see it more clearly):
string &str = text[i];
char ch = str[0];
unsigned char uc = static_cast<unsigned char>(ch);
uc = toupper(uc);
ch = static_cast<char>(uc);
str[0] = ch;
text[i] = str;
Which, obviously, can also be written as a string expression, if you want:
text[i][0] = static_cast<char>(
toupper(
static_cast<unsigned char>(
text[i][0]
)
)
);
The reason why the cast is needed is explained on this reference page:
Parameters
ch - character to be converted. **If the value of ch is not representable as unsigned char and does not equal EOF, the behavior is undefined.
...
Like all other functions from <cctype>, the behavior of std::toupper is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char

Struggling with the fundamentals. Especially char[], char* and reading from arrays. Perhaps I should use type string

I need a bit of guidance.
I want to sharpen my skill, so I'm practicing with smaller projects.
The current challenge is to create a function that can count syllables in a user inputted word.
My thinking is to declare an array of vowels: a, e, i, o, u.
then iterate through the user inputted word, checking if any letters of the word match with the vowel array, and if yes, check if the next letter doesn't. (I'm assuming a syllable is defined by the presence of a vowel AND consonant.)
This will need nested for loops, one to iterate through the word, and then another to iterate through the vowel array with the current index of 'word'.
I haven't even figured out how I'm going to do the same for word[i+1] yet.
But I'm struggling because I can't get my program to compile due to basic errors. I should probably use a string class, but I don't know.
Here's what I've got (And it won't compile!):
#include <iostream>
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
int numberOfSyllables(char *word)
{
int numberOfVowelsFound = 0;
for ( &element : word )
{
bool vowelMatch = 0;
for ( &vowel : vowels)
{
if (element == vowel)
{
vowelMatch = 1;
break;
}
}
if ((vowelMatch == 1) numberOfVowelsFound++;
}
return numberOfVowelsFound;
}
int main()
{
char *userInput[50];
std::cout << "Enter a word: ";
std::cin >> *userInput;
std::cout << numberOfSyllables(userInput) << " syllables found";
return 0;
}
This is not a code review website, but I will try my best anyway:
Your for loops don't have types:
for (TYPE &element : word )
The type you want to loop over in this case is char.
if you wanted the compiler to figure out the type for you:
for (auto &element : word)
You are looping over word with a "foreach" style loop, but a char * cannot be looped over this way. To be precise, there is no std::begin and std::end functions defined for char *, so the "foreach" style loop doesn't know where you want your string to begin/end. Either use a different style of loop, or use a type that does support "foreach" style loops (such as std::string or C++17's std::string_view).
You added an extra parenthesis ( in the if statement:
// |
// v
if ((vowelMatch == 1) numberOfVowelsFound++;
You declare your userInput variable as an "array of 40 pointers to characters", but you probably want to write "characters" to it, not "pointers to characters". Change it's type to "array of 40 characters".
Similarly, you dereference your userInput variable (probably to avoid a warning), which, because userInput is an "array of 40 (pointers to char)", will return the first, uninitialized, "pointer to char" in that array (*var is the same as var[0] in this case). Just remove the dereference operator * and change the type of the array as suggested above, and std::cin will figure out what to do. Because you (wrongfully) dereferenced userInput already to avoid a warning, std::cin thinks you want to write to the location pointed to by the uninitialized pointer. You have no control over where your program will write too at this point; it might simply crash.
Finally, you once again pass the wrong type into numberOfSyllables(userInput), as mentioned before, userInput is an "array of 40 pointers to char", while your function expects a "pointer of chars". Change the type of userInput to "array of chars", which the compiler can then convert to "pointer of chars".
Final code:
// compile with -std=c++17 for std::string_view, or use another loop style
#include <string_view>
#include <iostream>
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
int numberOfSyllables(char *word)
{
int numberOfVowelsFound = 0;
// `std::string_view` can be used in "foreach" style loops
// we need to use `const char`, since `std::string_view` is a "fake string" and not writable
for (const char &element : std::string_view(word))
// Another loop style (This even works in C):
// for (int i=0; word[i] != '\0'; i++) // While the current element is not NUL
// {
// const char element = word[i]; // Remember the current element
{
bool vowelMatch = 0;
for (const char &vowel : vowels) // Use const here too just for good measure
{
if (element == vowel)
{
vowelMatch = 1;
break;
}
}
if (vowelMatch == 1) numberOfVowelsFound++; // Removed a parenthesis here
}
return numberOfVowelsFound;
}
int main()
{
char userInput[50]; // Changed type of this variable
std::cout << "Enter a word: ";
std::cin >> userInput; // Removed a dereference here
std::cout << numberOfSyllables(userInput) << " syllables found";
return 0;
}

Getting position of char in vector (C++)

I am trying to check if char exists in vector of chars, and if so, to get it`s number. I have done the first part (check if char exists):
char letter(a);
string word;
vector<char>vWord(word.begin(), word.end());
if(find(vWord.begin(), vWord.end(), letter) != vWord.end()){}
But I have no idea how to get the position. Any help is appreciated.
Save the iterator and do some math on it:
vector<char>::iterator itr = find(vWord.begin(), vWord.end(), letter);
if(itr != vWord.end())
{
int index = itr - vWord.begin();
}
However do note that std::string already has a find method.
You're almost there. You already have an iterator pointing to that character (returned by find), so you can use std::distance to find the distance:
char letter(a);
string word;
vector<char>vWord(word.begin(), word.end());
auto it = find(vWord.begin(), vWord.end(), letter);
if (it != vWord.end())
{
size_t index = std::distance(vWord.begin(), it);
}
For random-access iterators (such as those used by std::vector), std::distance(a, b) is a constant-time operation and is implemented by doing b - a.
Side note: you can do std::find and iterator operations on std::string directly; it's a perfectly fine container in its own right.

Converting string to char and int data types

I've populated a string vector with with numbers and characters (*,+,-,/). I want to assign each number and character to two new vector, and int vector and a char vector. Is there a way to convert the everything from string to the desired data type?
You can use string stream in the <sstream> header.
string myString = "123";
stringstream sStream( myString );
int convertedInt;
sStream >> convertedInt.
Include the <sstream> header and you can do something like this:
std::vector<std::string> stringVector = /* get data from somewhere */
std::vector<int> intVector;
std::vector<char> charVector;
for (std::vector<std::string>::const_iterator it = stringVector.begin(); it != stringVector.end(); it++)
{
if (it->length() == 0)
continue; // ignore any empty strings
int intValue;
std::istingstream ss(*it);
if (ss >> someValue) // try to parse string as integer
intVector.push_back(someValue); // int parsed successfully
else
charVector.pushBack((*it)[0]);
}
This assumes anything that cannot be parsed as an integer should be pushed into the char vector instead (so, 234, 100000 and -34 will be put into intVector, and /, + etc will be put into charVector). Only the first character of a non-integer value is pushed, so if you have *hello or *123, only * will be put into the charVector.
If you are using C++11, you can swap the std::vector<std::string>::const_iterator with auto to make it look a bit nicer.

C++ creating a string from char array elements?

I have a char array which is VERY large and I iterate through the array. I look for patterns with logic such as:
if (array[n] == 'x' and array[n+1] == 'y' and array[n+2] == 'z')
{
mystring = array[n+4] + array[n+5];
}
if array[n+4] is '4' and array[n+5] is '5' then mystring = "45"
However, mystring is always "", what am I doing wrong? I don't want to use substring as the array is too large. I just want to cast the chars to strings and then append to mystring.
I suggest so use assign(const char*, len);
no copy constructor is involved
if (array[n] == 'x' and array[n+1] == 'y' and array[n+2] == 'z')
{
mystring.assign(array + n + 4, 2);
}
You're checking for a consecutive "xyz" occurrence , why not simply use std::string ?
std::string s(array);
size_t i =s.find("xyz");
if(i!=std::string::npos && i+5 <= s.size())
{
std::string mystring = std::string(1,array[i + 4]) + array[i + 5];
std::cout<<mystring;
}
You can cast chars to ints and vice versa because they are basic language types. Strings are implemented as a class so you need to invoke the string constructor for both chars then concatenation the two resulting strings into mystring
If you can't use std::string in the first place, as suggested by #P0W (which is a good suggestion), then there is another alternative to do this conversion that does not involve string constructor (I think the solution using string constructor is a great one, but knowing different approaches can give you more flexibility), but relies on std::string::append.
int main ()
{
// create char
char *str1 = new char[6];
strcpy( str1,"hello ");
char *str2 = new char[5];
strcpy(str2, "world" );
// use of append to convert to a string
std::string mystring;
mystring.append(str1);
mystring.append(str2);
std::cout << mystring << std::endl;
}
Check the std::string::append documentation, and you will also see that one of the overloading of this functions is string& append (const char* s, size_t n), which means you can convert just subset of char arrays, as you request it.
Adding characters strings doesn't work like that in C++. The easier way to do this is to create a stringstream and add the characters to the string with the << operator, then recover a string from it using the str() method.
Example:
#include <iostream>
#include <sstream>
using namespace std;
int main(void)
{
char a[] = {'a', 'd', 'c', 'b', 'a' };
stringstream linestream;
linestream << a[0] << a[1];
cout << linestream.str() << endl; // Prints ad
return 0;
}