Why do I need to cast the argument of algorithm remove()? - c++

I am trying to delete the consecutive duplicate characters from a string such as "helloworld" and delete all occurrences of the duplicate character. In this case, it is 'l', so the new string should be "heoword". I have written the code like this:
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
int main() {
string s = "helloworld";
for (int i = 0; i < s.length() - 1; i++) {
if (s[i] == s[i+1]) {
s.erase(remove(s.begin(), s.end(), s[i]), s.end()); // PROBLEM
cout << s << endl; // printing `heowrld`, instead of `heoword`
}
}
return 0;
}
The code above doesn't work unless I cast s[i] like (char)s[i]. I looked up the operator [] for the string and it is returning the reference to the character at position. The remove method also accepts const T& val as parameter for character to be replaced. Since both of them are of the same type, why can't I just put in s[i] as argument to the remove method?
p.s. This is not homework problem. By casting the s[i] in remove, I can get correct output but I would like to know why I need to cast s[i].

The problem here is your moving the value to remove out from under yourself. Lets look at
#include <iostream>
int main()
{
int a = 5, b = 10;
int & ref = a;
std::cout << "a: " << a << " b: " << b << " ref: " << ref << "\n";
std::swap(a, b);
std::cout << "a: " << a << " b: " << b << " ref: " << ref << "\n";
}
If you run it you will get
a: 5 b: 10 ref: 5
a: 10 b: 5 ref: 10
and as you can see ref doesn't move to now follow b but stays with a (as it should) and prints a's new value.
We are seeing the same thing with
s.erase(remove(s.begin(), s.end(), s[i]), s.end());
Since s[i] is a reference to an element in the string its value gets changed as remove swaps the elements around. So it removes both l's and then it also removes the last o since o is moved into the same position that l used to occupy but it only does so after it passed the first o in the string.
The reason casting "fixes" this is because now you are no longer referring to an element of the string. You create a temporary variable and you use that variables value to remove the l's.

Related

Pointer and char in struct

How to read the second letter in char with a pointer? I can read the whole message "carp" and first letter 'c' but I have no idea how to read second letter... Here is my example code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
struct list {
char name[20];
int length;
};
list first ={
"carp",
6,
};
list *p = &first;
cout << p->name << endl; // "carp"
cout << *p->name << endl; // "c"
p = p + 1;
cout << *p->name << endl; // Not working...How to read a?
return 0;
}
Incrementing p with p++ or p = p+1 moves you to the next instance of struct list, which is not what you want (and it's not even there).
Instead, you want to move to the second letter of name, which can be done in several ways:
Use index on the name - cout << p->name[1] << endl;
Make a pointer to p->name and increment it, i.e. char *np = p->name; np++; cout << *np
Use pointer arithmetic instead of indexing, i.e. cout << *(p->name+1) << endl;
You can use index on name to access any character:
p->name[1] // gives 'a'
p->name[2] // gives 'r'
Note that arrays begin with an index of 0. So p->name[0] would give 'c'.
p + 1 actually increments p, which is a pointer to list. This essentially moves to the next instance of list, which is not even initialized in your code.
Use the array subscript operator with an index of 1:
p->name[1];
If you want to output the second character using pointers without the subscript operator then you can just write
cout << *( p->name + 1 ) << endl;
It is the same as
cout << p->name[1] << endl;
Or you can introduce an intermediate pointer. For example
for ( const char *q = p->name; *q != '\0'; ++q )
{
cout << *q;
}
cout << endl;

cout and String concatenation

I was just reviewing my C++. I tried to do this:
#include <iostream>
using std::cout;
using std::endl;
void printStuff(int x);
int main() {
printStuff(10);
return 0;
}
void printStuff(int x) {
cout << "My favorite number is " + x << endl;
}
The problem happens in the printStuff function. When I run it, the first 10 characters from "My favorite number is ", is omitted from the output. The output is "e number is ". The number does not even show up.
The way to fix this is to do
void printStuff(int x) {
cout << "My favorite number is " << x << endl;
}
I am wondering what the computer/compiler is doing behind the scenes.
The + overloaded operator in this case is not concatenating any string since x is an integer. The output is moved by rvalue times in this case. So the first 10 characters are not printed. Check this reference.
if you will write
cout << "My favorite number is " + std::to_string(x) << endl;
it will work
It's simple pointer arithmetic. The string literal is an array or chars and will be presented as a pointer. You add 10 to the pointer telling you want to output starting from the 11th character.
There is no + operator that would convert a number into a string and concatenate it to a char array.
adding or incrementing a string doesn't increment the value it contains but it's address:
it's not problem of msvc 2015 or cout but instead it's moving in memory back/forward:
to prove to you that cout is innocent:
#include <iostream>
using std::cout;
using std::endl;
int main()
{
char* str = "My favorite number is ";
int a = 10;
for(int i(0); i < strlen(str); i++)
std::cout << str + i << std::endl;
char* ptrTxt = "Hello";
while(strlen(ptrTxt++))
std::cout << ptrTxt << std::endl;
// proving that cout is innocent:
char* str2 = str + 10; // copying from element 10 to the end of str to stre. like strncpy()
std::cout << str2 << std::endl; // cout prints what is exactly in str2
return 0;
}

Why std::make_move_iterator works on vector<string> but not on vector<int>

I was expecting that std::make_move_iterator will always move contents, but it seems not.
It looks like it is moving elements in vector<string> but not in vector<int>.
See the below code snippet:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
void moveIntVector()
{
std::cout << __func__ << std::endl;
std::vector<int> v1;
for (unsigned i = 0; i < 10; ++i) {
v1.push_back(i);
}
std::vector<int> v2(
std::make_move_iterator(v1.begin() + 5),
std::make_move_iterator(v1.end()));
std::cout << "v1 is: ";
for (auto i : v1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "v2 is: ";
for (auto i : v2) {
std::cout << i << " ";
}
std::cout << std::endl;
}
void moveStringVector()
{
std::cout << __func__ << std::endl;
std::vector<std::string> v1;
for (unsigned i = 0; i < 10; ++i) {
v1.push_back(std::to_string(i));
}
std::vector<std::string> v2(
std::make_move_iterator(v1.begin() + 5),
std::make_move_iterator(v1.end()));
std::cout << "v1 is: ";
for (auto i : v1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "v2 is: ";
for (auto i : v2) {
std::cout << i << " ";
}
std::cout << std::endl;
}
int main()
{
moveIntVector();
moveStringVector();
return 0;
}
The result is:
moveIntVector
v1 is: 0 1 2 3 4 5 6 7 8 9 # I expect this should be `0 1 2 3 4` as well!
v2 is: 5 6 7 8 9
moveStringVector
v1 is: 0 1 2 3 4
v2 is: 5 6 7 8 9
I'm on Ubuntu 14.04, gcc 4.8.2 and the code is compiled with -std=c++11
Could you explain why std::make_move_iterator have different behaviour on vector<int> and vector<string>? (Or is it a bug?)
The behaviour is expected. A move from both vectors leaves the original v1 with 5 moved-from elements in their second half.
The difference is that when the strings are moved, what is left behind is empty strings. This is because it is a very efficient way to move strings, and leave the moved-from string in a self-consistent state (Technically, they could be left to hold the value "Hello, World, nice move!", but that would incur extra cost). The bottom line is that you don't see those moved-from strings in your output.
In the case of the int vectors, there is no way to move an int that is more efficient than copying it, so they are just copied over.
If you check the sizes of the vectors, you will see the v1 have size 10 in both cases.
Here's a simplified example to illustrate that the moved from strings are left empty:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> v1{"a", "b", "c", "d", "e"};
std::vector<std::string> v2(std::make_move_iterator(v1.begin()),
std::make_move_iterator(v1.end()));
std::cout << "v1 size " << v1.size() << '\n';
std::cout << "v1: ";
for (const auto& s : v1) std::cout << s << " - ";
std::cout << '\n';
std::cout << "v2 size " << v2.size() << '\n';
std::cout << "v2: ";
for (const auto& s : v2) std::cout << s << " - ";
std::cout << '\n';
}
Output:
v1 size 5
v1: - - - - -
v2 size 5
v2: a - b - c - d - e -
When we talk about a move we are not talking about moving the object itself (it remains intact). What gets moved are its internal data. This may or may not affect the value of the object whose internal data gets moved.
That is why your int array doesn't loose its original ints. As to your string example, it still has the original std::strings just like the int example but their internal values have changed to empty strings.
It is important to remember that internally a std::string (essentially) holds a pointer to a character array. So when you copy a std::string you copy every element of the character array. A move, however, avoids doing all that copying by copying the internal pointer instead.
But if the move operation stopped there that would leave both std::strings pointing at the same character array and changing the character data pointed to by either std::string would also change the other's. So when you move a string it is not enough to merely copy the internal pointer, you have to make the internal pointer of the std::string you moved from point to a new blank character array so that it can no longer affect the string its data was moved to.
When moving an int there is no further action required after the copy of its data. There are no pointers involved so after the copy both ints contain independent data.
move constructor is like of an object works like taking a regular reference and a instruction to move things. the default move constructor tries to call the move constructor of all member variables. a user defined one... pretty much it's up to the programmer to tell it what to do.
you could program your objects to be in a undefined state after being subject to a move constructor, you can keep them unchanged(the destructor will still be called so you need to take care of that), you can keep them valid. strings will have a defined state after being subject to a move constructor.
as for your example...
int is trivially copyable and it's move constructor won't do anything but copying.
string is not trivially copyable. it has some dynamic stuff in it that the move constructor moves. and the previous one is left with a length of zero, you ARE printing them, along with the trailing "space" which you added. it's just they are the last 5 elements, at the end of what your printing and you aren't noticing it because it's equivalent to 5 trailing white spaces.

Why setting null in the middle of std string doesn't have any effect

Consider
#include <string>
#include <iostream>
int main()
{
/*
hello
5
hel
3
*/
char a[] = "hello";
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
a[3] = 0;
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
/*
hello
5
hel o
5
*/
std::string b = "hello";
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
b[3] = 0;
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
getchar();
}
I expect std::string will behave identical to char array a. That's it, insert null character in the middle of the string, will "terminate" the string. However, it is not the case. Is my expectation wrong?
A std::string is not like a usual C string, and can contain embedded NUL characters without problems. However, if you do this you will notice the string is prematurely terminated if you use the .c_str() function to return a const char *.
No - std::strings are not NUL-terminated like C "strings"; the std::string records its length independently.
#Lou is right: don't do that. Instead, do this:
b.erase (3, b.length());
Yes, your expectation is wrong. std::string is meant to be different from C strings (e.g. not necessarily stored in consecutive memory / an array).
To duplicate the first section's behavior, try std::cout << b.c_str() instead of std::cout << b.
I expect std::string will behave identical to char array a.
Why? Nothing in the documentation, anywhere, having to do with std::string says it does this.
My suggestion, stop treating like C++ as C plus some stuff.

Comparing Character Literal to Std::String in C++

I would like to compare a character literal with the first element of string, to check for comments in a file. Why use a char? I want to make this into a function, which accepts a character var for the comment. I don't want to allow a string because I want to limit it to a single character in length.
With that in mind I assumed the easy way to go would be to address the character and pass it to the std::string's compare function. However this is giving me unintended results.
My code is as follows:
#include <string>
#include <iostream>
int main ( int argc, char *argv[] )
{
std::string my_string = "bob";
char my_char1 = 'a';
char my_char2 = 'b';
std::cout << "STRING : " << my_string.substr(0,1) << std::endl
<< "CHAR : " << my_char1 << std::endl;
if (my_string.substr(0,1).compare(&my_char1)==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
std::cout << "STRING : " << my_string.substr(0,1) << std::endl
<< "CHAR : " << my_char2 << std::endl;
if (my_string.substr(0,1).compare(&my_char2)==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
std::cout << "STRING : " << my_string << std::endl
<< "STRING 2 : " << "bob" << std::endl;
if (my_string.compare("bob")==0)
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
}
Gives me...
STRING : b
CHAR : a
NOPE...
STRING : b
CHAR : b
NOPE...
STRING : bob
STRING 2 : bob
WOW!
Why does the function think the sub-string and character aren't the same. What's the shortest way to properly compare chars and std::string vars?
(a short rant to avoid reclassification of my question.... feel free to skip)
When I say shortest I mean that out of a desire for coding eloquence. Please note, this is NOT a homework question. I am a chemical engineering Ph.D candidate and am coding as part of independent research. One of my last questions was reclassified as "homework" by user msw (who also made a snide remark) when I asked about efficiency, which I considered on the border of abuse. My code may or may not be reused by others, but I'm trying to make it easy to read and maintainable. I also have a bizarre desire to make my code as efficient as possible where possible. Hence the questions on efficiency and eloquence.
Doing this:
if (my_string.substr(0,1).compare(&my_char2)==0)
Won't work because you're "tricking" the string into thinking it's getting a pointer to a null-terminated C-string. This will have weird effects up to and including crashing your program. Instead, just use normal equality to compare the first character of the string with my_char:
if (my_string[0] == my_char)
// do stuff
Why not just use the indexing operator on your string? It will return a char type.
if (my_string[0] == my_char1)
You can use the operator[] of string to compare it to a single char
// string::operator[]
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str ("Test string");
int i; char c = 't';
for (i=0; i < str.length(); i++)
{
if (c == str[i]) {
std::cout << "Equal at position i = " << i << std::endl;
}
}
return 0;
}
The behaviour of the first two calls to compare is entirely dependent on what random memory contents follows the address of each char. You are calling basic_string::compare(const char*) and the param here is assumed to be a C-String (null-terminated), not a single char. The compare() call will compare your desired char, followed by everything in memory after that char up to the next 0x00 byte, with the std::string in hand.
Otoh the << operator does have a proper overload for char input so your output does not reflect what you are actually comparing here.
Convert the decls of and b to be const char[] a = "a"; and you will get what you want to happen.
Pretty standard, strings in c++ are null-terminated; characters are not. So by using the standard compare method you're really checking if "b\0" == 'b'.
I used this and got the desired output:
if (my_string.substr(0,1).compare( 0, 1, &my_char2, 1)==0 )
std::cout << "WOW!" << std::endl;
else
std::cout << "NOPE..." << std::endl;
What this is saying is start at position 0 of the substring, use a length of 1, and compare it to my character reference with a length of 1. Reference