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);
Related
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.
Suppose we have a string
std::string str; // some value is assigned
What is the difference between str.empty() and str[0] == '\0'?
C++11 and beyond
string_variable[0] is required to return the null character if the string is empty. That way there is no undefined behavior and the comparison still works if the string is truly empty. However you could have a string that starts with a null character ("\0Hi there") which returns true even though it is not empty. If you really want to know if it's empty, use empty().
Pre-C++11
The difference is that if the string is empty then string_variable[0] has undefined behavior; There is no index 0 unless the string is const-qualified. If the string is const qualified then it will return a null character.
string_variable.empty() on the other hand returns true if the string is empty, and false if it is not; the behavior won't be undefined.
Summary
empty() is meant to check whether the string/container is empty or not. It works on all containers that provide it and using empty clearly states your intent - which means a lot to people reading your code (including you).
Since C++11 it is guaranteed that str[str.size()] == '\0'. This means that if a string is empty, then str[0] == '\0'. But a C++ string has an explicit length field, meaning it can contain embedded null characters.
E.g. for std::string str("\0ab", 3), str[0] == '\0' but str.empty() is false.
Besides, str.empty() is more readable than str[0] == '\0'.
Other answers here are 100% correct. I just want to add three more notes:
empty is generic (every STL container implements this function) while operator [] with size_t only works with string objects and array-like containers. when dealing with generic STL code, empty is preferred.
also, empty is pretty much self explanatory while =='\0' is not very much.
when it's 2AM and you debug your code, would you prefer see if(str.empty()) or if(str[0] == '\0')?
if only functionality matters, we would all write in vanilla assembly.
there is also a performance penalty involved. empty is usually implemented by comparing the size member of the string to zero, which is very cheap, easy to inline etc. comparing against the first character might be more heavy. first of all, since all strings implement short string optimization, the program first has to ask if the string is in "short mode" or "long mode". branching - worse performance. if the string is long, dereferencing it may be costly if the string was "ignored" for some time and the dereference itself may cause a cache-fault which is costly.
empty() is not implemented as looking for the existence of a null character at position 0, its simply
bool empty() const
{
return size() == 0 ;
}
Which could be different
Also, beware of the functions you'll use if you use C++ 11 or later version:
#include <iostream>
#include <cstring>
int main() {
std::string str("\0ab", 3);
std::cout << "The size of str is " << str.size() << " bytes.\n";
std::cout << "The size of str is " << str.length() << " long.\n";
std::cout << "The size of str is " << std::strlen(str.c_str()) << " long.\n";
return 0;
}
will return
The size of str is 3 bytes.
The size of str is 3 long.
The size of str is 0 long.
You want to know the difference between str.empty() and str[0] == '\0'. Lets follow the example:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str, str2; //both string is empty
str2 = "values"; //assigning a value to 'str2' string
str2[0] = '\0'; //assigning '\0' to str2[0], to make sure i have '\0' at 0 index
if(str.empty()) cout << "str is empty" << endl;
else cout << "str contains: " << str << endl;
if(str2.empty()) cout << "str2 is empty" << endl;
else cout << "str2 contains: " << str2 << endl;
return 0;
}
Output:
str is empty
str2 contains: alues
str.empty() will let you know the string is empty or not and str[0] == '\0' will let you know your strings 0 index contains '\0' or not. Your string variables 0 index contains '\0' doesn't mean that your string is empty. Yes, only once it can be possible when your string length is 1 and your string variables 0 index contains '\0'. That time you can say that, its an empty string.
C++ string has the concept of whether it is empty or not. If the string is empty then str[0] is undefined. Only if C++ string has size >1, str[0] is defined.
str[i] == '\0' is a concept of the C-string style. In the implementation of C-string, the last character of the string is '\0' to mark the end of a C-string.
For C-string you usually have to 'remember' the length of your string with a separate variable. In C++ String you can assign any position with '\0'.
Just a code segment to play with:
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
char str[5] = "abc";
cout << str << " length: " << strlen(str) << endl;
cout << "char at 4th position: " << str[3] << "|" << endl;
cout << "char at 5th position: " << str[4] << "|" << endl;
str[4]='X'; // this is OK, since Cstring is just an array of char!
cout << "char at 5th position after assignment: " << str[4] << "|" << endl;
string cppstr("abc");
cppstr.resize(3);
cout << "cppstr: " << cppstr << " length: " << cppstr.length() << endl;
cout << "char at 4th position:" << cppstr[3] << endl;
cout << "char at 401th positon:" << cppstr[400] << endl;
// you should be getting segmentation fault in the
// above two lines! But this may not happen every time.
cppstr[0] = '\0';
str[0] = '\0';
cout << "After zero the first char. Cstring: " << str << " length: " << strlen(str) << " | C++String: " << cppstr << " length: " << cppstr.length() << endl;
return 0;
}
On my machine the output:
abc length: 3
char at 4th position: |
char at 5th position: |
char at 5th position after assignment: X|
cppstr: abc length: 3
char at 4th position:
char at 401th positon:?
After zero the first char. Cstring: length: 0 | C++String: bc length: 3
I'm trying to find the index of a substring in another string, using find(), but getting a junk value and not std::npos if the substring is not there.
This is the Code:
string output1 = "abcd";
cout << output.find("gf") << endl;
And this is the output:
18446744073709551615
can this behaviour be prevented? is there another way to find the substring?
(actually i only need to find if the substring is contained)
Thank you
What it return is size_t of npos of your string because it can't find your char or text. you can do this instead:
std::size_t found = str.find("findme");
if (found != std::string::npos)
std:cout << found << std::endl;
else
std::cout << "String not found" << std::endl // If not found
If the string was abcdef how do I get bcdef. I tried
cout << str.substr(1,'\0')<< endl;
but that didn't work.
What about a char array?
#include <iostream>
using namespace std;
int main() {
std::string str = "abcdef";
cout << str.substr (1);
return 0;
}
Try it live: http://ideone.com/AueOXR
if you take a look at the documentation for string::substr:
string substr (size_t pos = 0, size_t len = npos) const;
Generate substring
Returns a newly constructed string object with its value initialized to a copy of a substring of this object.
The substring is the portion of the object that starts at character position pos and spans len characters (or until the end of the string, whichever comes first).
http://www.cplusplus.com/reference/string/string/substr/
That means: if you don't specify a second parameter a default one that goes all the way to the end of the string is assumed.
Try
cout << str.substr(1)<< endl;
Of course, the documentation of string tells you everything you need to know ...
Make it simpler:)
std::cout << str.substr( 1 ) << std::endl;
The other way and I think more effective is to use member function c_str if the string does not contain embedded zeroes
std::cout << str.c_str() + 1 << std::endl;
substr(position, length) will return the string started at the position index and ending at length characters after position.
You need to change the \0 to either the end of the string index or to nothing because it will default to returning the rest of the string if you don't have a second parameter.
str.substr(1) will return bcdef
str.substr(1, 5) will also return bcdef
As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string