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;
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].
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;
}
}
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()));
I am trying to write program that takes a string with symbols and numbers and only saves the alphabet, discarding everything else. I tried with a str.erase but I thought it was easier to use loop. Assuming everything is lower case,it works beautifully.copy_str should save the new string without the symbols, to see if it was done I displayed it. When it is inside the if-it shows correct string, but when I display it outside the for loop-nothing. :/
here is my code:
int main()
{
string str="am73$$ore r0ma!!!";
int size_str=str.size();
string copy_str;
for(int i=0;str[i]!='\0';i++)
{
if((str[i]>=97) && (str[i]<123))
{
copy_str[i]=str[i];
cout<<copy_str[i];
}
}
cout<<copy_str;
You should use isalpha, see here.
copy_str is uninitialized and you initialize only the positions where your if statement inside the loop is fulfilled. Add single chars using +=.
std::string src = "am73$$ore r0ma!!!";
std::string dst; // empty string
for ( size_t i = 0; i < src.size(); i++ )
{
if ( isalpha(src[i]) ){ dst += src[i]; }
}
std::cout << dst << std::endl;
The program is undefined since you're assigning to non-existent elements of an empty string.
Assigning to an element that doesn't exist does not make the string longer, it's invalid.
Since the program is undefined, anything can happen.
You can use push_back to expand the result:
if(str[i] >= 'a' && str[i] <= 'z')
{
copy_str.push_back(str[i]);
}
or +=:
if(str[i] >= 'a' && str[i] <= 'z')
{
copy_str += str[i];
}
I'm tring to solve a small problem. I have two strings. s1 and s2. I want my function to return the first index of s1 that has a character not present in the string s2. This is my code.
int cad_nenhum_dos (char s1[], char s2[]){
int i,j;
for (i=0;s1[i]!='\0';i++)
{
for (j=0;s2[j]!='\0';j++)
if (s1[i]!=s2[j]) return i;
}
return -1;
}
If I run s1="hello" s2="hellm", the result should be index 4, because s1[4]='o' and "o" is not present in s2... But I allways get 0 when I run this. The -1 works fine if the strings are the same.
What am I doing wrong?
Regards
In your inner loop you need to break out when you find a character the same -- as it stands you're returning when there are any different characters in the second string, even if an earlier one was the same. You want something like
for (j=0;s2[j]!='\0';j++)
if (s1[i]==s2[j]) break;
if (s2[j]==0)
return i;
I.e. you want to return the ith character of the first string when you've made you way through the whole of the second string without having found that character.
For programming exercises at the introductory level it's a good idea to carefully execute the code manually (step through yourself and see what's happening).
As TooTone suggested, you need to break out of the loop when you find a match:
for (int i = 0; s1[i] != '\0'; i++)
{
bool charFound = false;
for (int j = 0; s2[j] != '\0'; j++)
{
if (s1[i] == s2[j])
{
charFound = true;
break;
}
}
if ( ! charFound)
return i;
}
Because the inner for-loop is comparing first letter of the first string against all the letters in the second string.
int cad_nenhum_dos (char s1[], char s2[])
{
int i,j;
for(i=0; s1[i]; i++)
{
if(s1[i] != s2[j])
return(i);
}
return(-1);
}