Removing starting characters from string using std::string::erase - c++

I am trying to truncate beginning zeros from a string, so I used sequence erase function
string& erase (size_t pos = 0, size_t len = npos);
This is my implementaion:
string str="000010557";
for(char c:str){
cout<<c<<" "<<str<<" "<<"\n";// for debug purpose
if(c=='0')
str.erase(0,1);
else
break;
}
cout<<str;
the output string that I got is 0010557 instead of10557 and debug statements prints:
0 000010557
0 00010557
1 0010557
I read the documentation of erase and this post thinking might there be some iterator invalidation but implementing the code snippet recommended in the accepted answer also gave the same output, please help me understand where is the problem.
I am new to using stl library functions, so please forgive any negligence of mine,Thanks.

Your for loop is incrementing the position from which c is extracted, even if you erase a leading zero. Thus, after two runs of the loop, you have erased the first and third of the leading zeros, then the c value will be the first 1.
Here's an attempt at following what happens in your code:
Start of first loop:
"000010557"
^
c is '0', so erase is called, making the string:
"00010557"
At the end of this first loop, the position is incremented, so...
Start of second loop:
"00010557"
^ (Note that we've skipped a zero!)
c is '0', so erase is called, making the string:
"0010557"
End of loop, position increment, and we skip another zero, so...
Start of third loop:
"0010557"
^
c is not '0', so we break out of the loop.
Instead, you should use a while loop, testing only the first character:
int main()
{
string str = "000010557";
char c;
while ((c = str.at(0)) == '0') {
cout << c << " " << str << " " << "\n";// for debug purpose
str.erase(0, 1);
}
cout << str;
}
Output:
0 000010557
0 00010557
0 0010557
0 010557
10557
Of course, you only need the c variable for your 'debugging' line so, without that, you can just have:
int main()
{
string str = "000010557";
while (str.at(0) == '0') str.erase(0, 1);
cout << str;
}

Even if you get this code to work, it's not a good solution. Removing a single character from the front of a string means moving all of the subsequent characters down one position, and the code does that for every leading zero. Instead, count the leading zeros and remove them all at once:
std::string::size_type non_zero_pos = 0;
while (non_zero_pos < str.size() && str[non_zero_pos] == '0')
++non_zero_pos;
str.erase(0, non_zero_pos);
That way, the (expensive) erase operation is only done once.
Or use iterators:
auto non_zero_it = std::find_first_not_of(std::begin(str), std::end(str), "0");
str.erase(std::begin(str), non_zero_it);
Edit: fixed search for non-0 iterator.

Related

Placing a negative index in C++

In Python and C#, we need to place a negative index to get last value.
In C++, I don't know how to do it. I tried the same way to do it but it didn't work out.
Example
string str = "get last space "
cout << str[-1];
In this example, I should get null value because there's a tailing space in the string. How can I do this?
cout << str[str.length() - 1];
str.length()will return the number of chars in this string, and to get the char at the end of str, you should use the index of the end char, which is 1 less than str length, since 0 is the first index
you can use back() method in string class :
string str = "get last space ";
cout << str.back();
its return char& to last character in string
Since you are using std::string, you can use the method std.back();.
cout << str.back();
This will get the last character of the string as you wish.
Since no one mentioned str.back() is UB if str is empty, I'd like to elaborate on it.
std::cout << str.back(); // Trigger UB if str.emtpy() == true
The better form is as following:
if(str.empty() == false){
std::cout << str.back();
}
Since str.back() is equivalent to str[str.length()-1], they both have UB when str is empty.
You can also use the str.end() iterator
string str = "get last space ";
cout << *(str.end()-1);

Problem with a function similar to strcat()

I tried to write a function similar to strcat() in c++.
Here is the code of this function:
char *mystrcat(char *str1, char *str2){
int i = 0;
char *buffer = str1;
while(*str1){
str1++; i++;
}
i++;
while(*str2){
str1[i] = *str2;
str2++; i++;
}
str1[++i] = '\0';
str1 = buffer;
return str1;
}
The input values for this function are given by this code:
char string1[100], string2[100];
cout << "Enter string 1 ";
cin >> string1;
cout << "Enter string 2 ";
cin >> string2;
mystrcat(string1, string2);
cout << string1 << endl;
When I ran the code and tried to input two strings, it has given me this output:
Enter string 1 qwerty
Enter string 2 asdf
qwerty
Why the first string is displayed only?
For a start, since you're incrementing both str1 and i in the first loop, you're going to move twice as fast through that array as you think. Thats because you're increasing both:
the base of the array; and
the offset from that base.
You're actually lucky to have chosen an even number of characters, otherwise you'd probably keep going beyond the end of str1 (by missing the \0), resulting in all sorts of fun and hilarity :-)
You should increment one or the other, such as with:
char *mystrcat(char *str1, char *str2) {
int i = 0;
while(str1[i] != '\0')
i++;
while(*str2 != '\0')
str1[i++] = *str2++;
str1[i] = '\0';
return str1;
}
The reason why you only get the first string after the concatenation, is the i++ after the first loop (which I've removed from the above code).
When you exit that loop, i is the index of the str1 terminator character so, an i++ at that point will jump over it. That means that you'll append str2 after that terminator:
qwerty<nul>asdf<nul>
Hence the string will only be qwerty because C strings always stop at the first terminator.
I often find it's useful to be able to start with a memory map and variable register (on paper), then run the code in your head, changing variables along the way. It helps to understand how your program will work. You can start with something like:
1 2
Index: 012345678901234567890
str1: qwerty_
str2: asdf_
i: 0
Then, each line of code in your head will result in i changing, or the string memory blocks changing (the _ at the end indicates the string terminator).
Don't increment the string pointers. Do just
while (str1[i]) {
++i;
}
And start with iterating str2 with another variable, from 0.
What you are doing currently is basically: str1[12] = str[6]
When you want: str1[6] = str2[0]

Calculate occurance of each character in a string without using count in C++

Here is my code:
#include <iostream>
#include <string>
using namespace std;
void calc(string s){
for(int i = 0;i < s.size();++i){
int count = 1;
for(int j = i + 1;j <s.size();++j){
if(s[i] == s[j]){
count += 1;
}
}
cout << s[i] <<"(" << count << ")" << " ";
}
}
int main(){
string str;
while(cin >> str){
calc(str);
}
}
Everything works fine, except that I want to iterate through unique characters in string and I don't know how to implement this.
Can you help me with it?
There are many ways you can do this. Here are a few suggestions:
Modify the code you have written so that before you count up how many times a character appears after the current character, you first scan over the characters before you in the string to see if any of them match. If so, skip the current character.
Every time you find a character that matches the current character, replace it with a copy of the first character in the string. Then, whenever you visit a character in the string that isn't in the first position, check if it matches the first character in the string. If so, you've already scanned it. If not, count up its occurrences.
Maintain an auxiliary data structure (an array, a hash table, etc.) mapping characters to their frequencies. Fill in the table by doing one pass over the original string, then iterate over the table, which has unique keys, to print everything out.
Sort the string. Counting how many times each character occurs then boils down to finding the length of each consecutive run of characters in the string.
Option (1) is good if you can't modify the original string and if you're not allowed to use other data structures. Option (2) has excellent time and space requirements if you're allowed to modify the original string. Option (3) is likely the easiest to code up, but uses a bit more space than other approaches. Option (4) is also very easy to code up and, if you use something like heapsort, has good memory usage but is still asymptotically slower than option (2).
Why don't you maintain an auxillary array of 26 length, initialize it to 0 and then increment the corresponding index's value by 1 everytime you encounter a character?
Pseudocode:
auxArray[26] = [0] // 26 length array initialized to zero
for character in string: // loop through every character in the string
auxArray[character - 'a']++; //increment the corresponding index value by 1
print auxArray //print the entire array. [0] will give you count of 'a', and [25] will give you count of 'z'
This is assuming that you have a character String from 'a' to 'z' (All lower case).
In the case where we have an uppercase-lowercase mixture of characters as well, you might similar stuff but instead use an array of 128. In this case, you won't have to subtract 'a' as it was being done to accommodate the indexes with the chars.
auxArray[128] = [0]
for character in string:
auxArray[character]++;
for index in auxArray:
print(((char)index) + " Count is " + auxArray[index])
Another way to do this is with std::map:
std::map<char,int> count;
for (int i = 0; i < s.size(); ++i)
count[s[i]]++;
for (auto iter = s.begin(); iter != s.end(); ++iter)
std::cout << iter->first << ā€œ: ā€œ << iter->second << ā€˜\nā€™;
Not tested, sorry.

Having trouble with simple palindrome program

I'm trying to code a simple c++ program that lets the user know if the word they input is palindrome or not. Example: 'mom' is palindrome.
Here's what I have:
#include <iostream>
#include <string>
using namespace std;
// Forward Declaration
string reversed_string(string);
int main(){
string str;
string reversed;
cout << "Enter string to check:\n";
getline(cin, str);
reversed = reversed_string(str);
if(str == reversed){
cout << str << " is palindrome\n\n";
}
else{
cout << "Not palindrome";
}
}
string reversed_string(string str){
string reversed;
for(int i = int(str.length()); i >= 0; i--){
reversed += str[i];
}
return reversed;
}
When I try to input a palindrome word, it always goes to the else statement in my main function. What am I doing wrong?
The last character of a string is at index len - 1, not len. As per the standard (C++11):
Returns *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object leads to undefined behavior.
What that standardese actually means is that, if pos is not less than the string length, the function returns a reference to a null character. Hence the first character you're putting into your reversed string is the null.
However, you don't really need to reverse the string to find if it's a palindrome, it might be easier to simply use the following (pseudo-code) algorithm:
def isPalindrome(string):
set left to zero
set right to one less than string length
while left is less than right:
if string[left] is not equal to string[right]:
return false
add one to left
subtract one from right
return true
Given you have to process every character to form the reversed string anyway, you may as well use that processing power to just check the characters in the original string. That way, you can exit early if it's not a palindrome.
This will, of course, consider an empty string to be a palindrome, which is arguably correct. If you don't think that's correct, simply put a check in up front:
def isPalindrome(string):
if string length is zero:
return false
set left to zero
... and so on

While loop not seeing or finding terminating null character

I am trying to iterate through a char array using a while loop using '\0' as the terminating condition, but my problem is that its not finding the '\0' until index position 481, the array is declared as 200 long and I cant see what I am doing wrong!! I cannot use strings or any form of string functions for this before anyone asks. Can anyone help??
#include <iostream>
using namespace std;
int main()
{
char fullString[200]={'\0'}; // Declare char string of 200, containing null characters
int alphaCount = 0;
int charCount = 0;
int wordCount = 0;
cin.getline(fullString,200); //
cout << "\n\n" << fullString;
cout << "\n\n\n";
int i=0;
int i2 = 0;
while(fullString[i]!='\0'){ //iterate through array until NULL character is found
cout << "\n\nIndex pos : " << fullString[i]; //Output char at 'i' position
while(fullString[i2]!= ' '){ //while 'i' is not equal to SPACE, iterate4 through array
if(isalpha(fullString[i2])){
alphaCount++; // count if alpha character at 'i'
}
charCount++; // count all chars at 'i'
i2++;
}
if(charCount == alphaCount){ // if charCount and alphaCount are equal, word is valid
wordCount++;
}
charCount = 0; // zero charCount and alphaCount
alphaCount = 0;
i=i2;// Assign the position of 'i2' to 'i'
while(fullString[i] == 32){ //if spaces are present, iterate past them
i++;
cout << "\n\ntest1";
}
i2 = i; // assign value of 'i' to 'i2' which is the next position of a character in the array
if(fullString[i] == '\0')
{
cout << "\n\nNull Character " << endl;
cout << "found at pos: " << i << endl;
}
}
cout << "\n\ni" << i;
cout << "\n\nWord" << wordCount;
return 0;
}
As others have pointed out, your problem is with the inner loop. You test for a space character but not for NULL, so it's iterating past the end of the last word because there is no space character after the last word.
This is easily fixed by changing your while condition from this:
while(fullString[i2]!= ' ')
... to this:
while(fullString[i2] && fullString[i2]!= ' ')
This will change your inner while loop to first test for non-NULL, and then test for non-space.
I'm not correcting the rest of your code because I presume this is a class project (it looks like one) so I'm limiting my answer to the scope of your question.
You do not check in the inner loop
while(fullString[i2]!= ' '){ //while 'i' is not equal to SPACE, iterate4 through array
if(isalpha(fullString[i2])){
alphaCount++; // count if alpha character at 'i'
}
charCount++; // count all chars at 'i'
i2++;
}
...
i=i2;// Assign the position of 'i2' to 'i'
whether the next character is equal to '\0'
It's because the inner loops don't check for the termination, they just continue looping even past the end of the string.
By the way, if you want to count the number of words, spaces and non-space characters, there are easier ways in C++. See e.g. std::count and std::count_if for the spaces and characters. For example:
std::string input = "Some string\twith multiple\nspaces in it.";
int num_spaces = std::count_if(std::begin(input), std::end(input),
[](const char& ch){ return std::isspace(ch); });
For counting words, you can use std::istringstream, std::vector, std::copy, std::istream_iterator and std::back_inserter:
std::istringstream iss(input);
std::vector<std::string> words;
std::copy(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter(words));
After the code above, the size of the words vector is the number of words.
If you use e.g. std::copy_if then you can use the above code for the other cases as well (but std::count_if is better for single character classes).