I want to read a string with integers and whitespaces into an array. For example I have a string looks like 1 2 3 4 5, and I want to convert it into an integer array arr[5]={1, 2, 3, 4, 5}. How should I do that?
I tried to delete the whitespaces, but that just assign the whole 12345 into every array element. If I don't everything element will all assigned 1.
for (int i = 0; i < str.length(); i++){
if (str[i] == ' ')
str.erase(i, 1);
}
for (int j = 0; j < size; j++){ // size is given
arr[j] = atoi(str.c_str());
}
A couple of notes:
Use a std::vector. You will most likely never know the size of an input at compile time. If you do, use a std::array.
If you have C++11 available to you, maybe think about stoi or stol, as they will throw upon failed conversion
You could accomplish your task with a std::stringstream which will allow you to treat a std::string as a std::istream like std::cin. I recommend this way
alternatively, you could go the hard route and attempt to tokenize your std::string based on ' ' as a delimiter, which is what it appears you are trying to do.
Finally, why reinvent the wheel if you go the tokenization route? Use Boost's split function.
Stringstream approach
std::vector<int> ReadInputFromStream(const std::string& _input, int _num_vals)
{
std::vector<int> toReturn;
toReturn.reserve(_num_vals);
std::istringstream fin(_input);
for(int i=0, nextInt=0; i < _num_vals && fin >> nextInt; ++i)
{
toReturn.emplace_back(nextInt);
}
// assert (toReturn.size() == _num_vals, "Error, stream did not contain enough input")
return toReturn;
}
Tokenization approach
std::vector<int> ReadInputFromTokenizedString(const std::string& _input, int _num_vals)
{
std::vector<int> toReturn;
toReturn.reserve(_num_vals);
char tok = ' '; // whitespace delimiter
size_t beg = 0;
size_t end = 0;
for(beg = _input.find_first_not_of(tok, end); toReturn.size() < static_cast<size_t>(_num_vals) &&
beg != std::string::npos; beg = _input.find_first_not_of(tok, end))
{
end = beg+1;
while(_input[end] == tok && end < _input.size())
++end;
toReturn.push_back(std::stoi(_input.substr(beg, end-beg)));
}
// assert (toReturn.size() == _num_vals, "Error, string did not contain enough input")
return toReturn;
}
Live Demo
Your code arr[j] = atoi(str.c_str()); is fault. The str is a string, not a char. When you used atoi(const char *), you should give the &char param. So the correct code is arr[j] = atoi(&str[j]). By the way, if you want to change the string to int, you could use the function arr[j] = std::stoul(str). I hope this can help you.
You have modified/parsing the string in one loop, but copying to integer array in another loop. without setting any marks, where all the embedded integers in strings start/end. So we have to do both the actions in single loop.
This code is not perfect, but to give you some idea; followed the same process you followed, but used vectors.
string str = "12 13 14";
vector<int> integers;
int start=0,i = 0;
for (; i < str.length(); i++){
if (str[i] == ' ')
{
integers.push_back(atoi(str.substr(start,i).c_str()));
start = i;
}
}
integers.push_back(atoi(str.substr(start,i).c_str()));
Related
I am trying to compare two string arrays, but am not allowed to use classes or libraries to assist.
The issue I have with this is that if one string is more than one character, then it compares the whole string to again, even though it already checked the first one.
char *find_first_not_in_the_set(char *str, const char *set)
{
for(int i = 0; *(str + i) != '\0'; i++)
{
for(int j = 0; *(set + j) != '\0'; j++)
{
if(str[i] != set[j])
{
return &(str[i]);
}
}
}
return NULL;
}
If "Hello World!" is the first string and the second string is "He". The program should return l, but it returns H because it still checks the first character.
I'd rather use this:
bool matrix[256] = {0};
int length = strlen(set);
// remember all characters we have in the 'set'
for( int i=0; i<length; i++) matrix[set[i] & 0xFF] = 1;
length = strlen(str);
// now check the characters from 'str'
for( int i=0; i<length; i++) {
if( ! matrix[str[i] & 0xFF] ) {
printf( "Found: %c", str[i] );
break;
}
}
For every character in str, your code checks if it is present on each and every position in set.Thus, when i=0 'H' is compared with set[0] i.e. 'H' for j=0.But when j=1,'H' is compared with 'e' and this causes the function to return str[0] because i is still 0.
Your problem will be solved if you use just one loop and check str[i]!=set[i].
It is Chief Hopper Greedy algorithm question .Here it is
https://www.hackerrank.com/challenges/chief-hopper/problem
I want to ask why splitting of string is done even though we are not giving any string as input and after that they used stoi function to convert that in int ??
string arr_temp_temp;
getline(cin, arr_temp_temp);
vector<string> arr_temp = split_string(arr_temp_temp);
vector<int> arr(n);
for (int i = 0; i < n; i++) {
int arr_item = stoi(arr_temp[i]);
arr[i] = arr_item;
}
vector<string> split_string(string input_string) {
string::iterator new_end = unique(input_string.begin(), input_string.end(), [] (const char &x, const char &y) {
return x == y and x == ' ';
});
input_string.erase(new_end, input_string.end());
while (input_string[input_string.length() - 1] == ' ') {
input_string.pop_back();
}
vector<string> splits;
char delimiter = ' ';
size_t i = 0;
size_t pos = input_string.find(delimiter);
while (pos != string::npos) {
splits.push_back(input_string.substr(i, pos - i));
i = pos + 1;
pos = input_string.find(delimiter, i);
}
splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i + 1));
return splits;
I don't know where did u find this approach but from my point of view author trying to save time on IO operations. I think that this approach is wrong. I don't know how fast is reading string with getline compared to reading each int value one by one in the loop:
for(int i = 0; i<n; i++) cin>> x;
But I'm quite sure that converting string to integer is more time-consuming. So it's normal in competive programming to use scanf/printf for the fast IO or
ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
if you wanna use cout/cin.
To sum up I think that code author tried to save time on IO operations.
UPD: Sorry I was in rush and didn't take into account the platform. It should be this platform feature to read input only line by line so they give a template for you to focus only on the problem.
The code is simplified from a more complex program but the issue I'm facing still occurs in this more simplified situation.
So I'm trying to erase a character from a string by using a pointer:
string str = "Hellxo World";
char *eraseHere;
for(int i = 0; i < str.length(); i++) {
if (str[i] == 'x') {
eraseHere = &str[i];
str.erase(*eraseHere);
}
}
I expected str to become Hello World, but instead it gives an out_of_range exception and stops the program.
Isn't eraseHere a pointer to the character "x"? I used eraseHere in a printf to try test what's wrong:
printf("%c\n",*eraseHere);
But it could print that character perfectly fine.
Thanks in advance.
The string class doesn't support erasing with a pointer, so you can't do that.
You can erase with an iterator which is nearly the same thing
for (auto i = str.begin(); i != str.end(); ) {
if (*i == 'x')
i = str.erase(i);
else
++i;
}
Also, even if it worked, your code has the common newbie mistake that you are ignoring that your string gets shorter when you erase a character. So it's not right to do i++ after erasing a character because you'll skip over the character after the 'x' you've just removed.
you can simply store the index of the 'x', then delete it after you finish the loop... or you can use the iterator in the answer above
string str = "Hellxo World";
char *eraseHere;
int indx=-1;
for(int i = 0; i < str.length(); i++)
{
if (str[i] == 'x')
{
eraseHere = &str[i];
indx=i;
}
}
indx!=-1 ? (str.erase(indx,1)):str;
cout<<str<<endl;
Ok, so I'm working on a homework project in C++ and am running into an issue, and can't seem to find a way around it. The function is supposed to break an input string at user-defined delimiters and store the substrings in a vector to be accessed later. I think I got the basic parser figured out, but it doesn't want to split the last part of the input.
int main() {
string input = "comma-delim-delim&delim-delim";
vector<string> result;
vector<char> delims;
delims.push_back('-');
delims.push_back('&');
int begin = 0;
for (int i = begin; i < input.length(); i++ ){
for(int j = 0; j < delims.size(); j++){
if(input.at(i) == delims.at(j)){
//Compares chars in delim vector to current char in string, and
//creates a substring from the beginning to the current position
//minus 1, to account for the current char being a delimiter.
string subString = input.substr(begin, (i - begin));
result.push_back(subString);
begin = i + 1;
}
The above code works fine for splitting the input code up until the last dash. Anything after that, because it doesn't run into another delimiter, it won't save as a substring and push into the result vector. So in an attempt to rectify the matter, I put together the following:
else if(input.at(i) == input.at(input.length())){
string subString = input.substr(begin, (input.length() - begin));
result.push_back(subString);
}
However, I keep getting out of bounds errors with the above portion. It seems to be having an issue with the boundaries for splitting the substring, and I can't figure out how to get around it. Any help?
In your code you have to remember that .size() is going to be 1 more than your last index because it starts at 0. so an array of size 1 is indexed at [0]. so if you do input.at(input.length()) will always overflow by 1 place. input.at(input.length()-1) is the last element. here is an example that is working for me. After your loops just grab the last piece of the string.
if(begin != input.length()){
string subString = input.substr(begin,(input.length()-begin));
result.push_back(subString);
}
Working from the code in the question I've substituted iterators so that we can check for the end() of the input:
int main() {
string input = "comma-delim-delim&delim-delim";
vector<string> result;
vector<char> delims;
delims.push_back('-');
delims.push_back('&');
auto begin = input.begin(); // use iterator
for(auto ii = input.begin(); ii <= input.end(); ii++){
for(auto j : delims) {
if(ii == input.end() || *ii == j){
string subString(begin,ii); // can construct string from iterators, of if ii is at end
result.push_back(subString);
if(ii != input.end())
begin = ii + 1;
else
goto done;
}
}
}
done:
return 0;
}
This program uses std::find_first_of to parse the multiple delimiters:
int main() {
string input = "comma-delim-delim&delim-delim";
vector<string> result;
vector<char> delims;
delims.push_back('-');
delims.push_back('&');
auto begin = input.begin(); // use iterator
for(;;) {
auto next = find_first_of(begin, input.end(), delims.begin(), delims.end());
string subString(begin, next); // can construct string from iterators
result.push_back(subString);
if(next == input.end())
break;
begin = next + 1;
}
}
lets say that we have:
string list[]= {"12.34.56.78","55.34.5","23.44.5"}
I want the user to enter part of the string which is also a string:
for example string 55 and it will loop through the string a and look for the whole string and print "55.34.5"
What I was doing is:
str is a string input and list is a whole list of the strings
for (int i=0; i<n; i++){
for (int j=0; j<(list[i].length()); j++){
for (int k=0; k<(str.length()); k++){
if (list[i][j] == str[k])
cout<<list[i]<<endl;
else
break;
however, there is a problem with this, and it doesn't work properly.
Update:
so I have updated my code to:
for (int i=0; i<n; i++)
if (strncmp(list[i].c_str(), str.c_str(), str.length()) == 0)){
cout<<list[i]<<endl;
}
however, this doesn't output any of the strings.
For any function fanatics (see it work):
std::string findInList(const std::vector<std::string> &searchFrom, const std::string &lookFor) {
for (const std::string &s : searchFrom) {
if (s.find(lookFor) != std::string::npos)
return s;
}
return "";
}
I used a vector instead of an array because vectors are better and don't require extra work to get the array size from. If C++11 isn't being used, a normal for loop works perfectly fine.
This also assumes you want the first match to be returned. A probably better option is to return a vector of strings, empty if none are found, which makes it explicit that none were found, or as many as are found otherwise. Instead of returning the found string, just add it to the vector and continue on, returning the vector when you're done.
If you want to model the standard algorithms, you can also have it take a beginning iterator and an ending iterator instead of the actual container. This will allow you to call it on any type of container, including arrays, with any range in that container to look through.
Taking both points into consideration, you can evolve it into this (see it work):
template <typename Iterator>
std::vector<std::string> findInList(Iterator start, const Iterator end, const std::string &lookFor) {
std::vector<std::string> ret;
for (; start != end; ++start)
if (start->find(lookFor) != std::string::npos)
ret.emplace_back(*start);
return ret;
}
Again, if not using C++11, emplace_back can be swapped out for push_back.
That just compares the first character in list[i] with the first char in your string. If the corresponding first chars match, it prints the entire ith string and then advances k, the offset into your str, without changing the offset into the string against which you're comparing. I think you can dispense with the inner two loops, and use a fixed length string comparison, i.e.,
for (int i=0; i < n; i++) {
if (strncmp(list[i].c_str(), str.c_str(), str.length()) == 0) {
// match
}
}
Here's an answer that combines both of the previous answers. It uses the find member function of the std::string class
for (int i=0; i < n; i++) {
if (list[i].find(str) != std::string::npos) {
std::cout << list[i] << std::endl;
}
}