In my code, I have char array and here it is: char pIPAddress[20];
And I'm setting this array from a string with this code:strcpy(pIPAddress,pString.c_str());
After this loading; for example pIPAddress value is "192.168.1.123 ". But i don't want spaces. I need to delete spaces. For this i did this pIPAddress[13]=0;.
But If IP length chances,It won't work. How can i can calculate space efficient way? or other ways?
Thnx
The simplest approach that you can do is to use the std::remove_copy algorithm:
std::string ip = read_ip_address();
char ipchr[20];
*std::remove_copy( ip.begin(), ip.end(), ipchr, ' ' ) = 0; // [1]
The next question would be why would you want to do this, because it might be better not to copy it into an array but rather remove the spaces from the string and then use c_str() to retrieve a pointer...
EDIT As per James suggestion, if you want to remove all space and not just the ' ' character, you can use std::remove_copy_if with a functor. I have tested passing std::isspace from the <locale> header directly and it seems to work, but I am not sure that this will not be problematic with non-ascii characters (which might be negative):
#include <locale>
#include <algorithm>
int main() {
std::string s = get_ip_address();
char ip[20];
*std::remove_copy_if( s.begin(), s.end(), ip, (int (*)(int))std::isspace ) = 0; // [1]
}
The horrible cast in the last argument is required to select a particular overload of isspace.
[1] The *... = 0; needs to be added to ensure NUL termination of the string. The remove_copy and remove_copy_if algorithms return an end iterator in the output sequence (i.e. one beyond the last element edited), and the *...=0 dereferences that iterator to write the NUL. Alternatively the array can be initialized before calling the algorithm char ip[20] = {}; but that will write \0 to all 20 characters in the array, rather than only to the end of the string.
If spaces are only at the end (or beginning) of your string, you'd best use boost::trim
#include <boost/algorithm/string/trim.hpp>
std::string pString = ...
boost::trim(pString);
strcpy(pIPAddress,pString.c_str());
If you want to handcode, <cctype> has the function isspace, which also has a locale specific version.
I see you have a std::string. You can use the erase() method :
std::string tmp = pString;
for(std::string::iterator iter = tmp.begin(); iter != tmp.end(); ++iter)
while(iter != tmp.end() && *iter == ' ') iter = tmp.erase(iter);
Then you can copy the contents of tmp into your char array.
Note that char arrays are totally deprecated in C++ and you shouldn't use them unless you absolutely have to. In either way, you should do all your string manipulations using std::string.
To make the solution work at all cases, i suggest you iterate through your string, and when finding a space you deal with it.
A more high-level solution may be for you to use the string methods that allow you to do that automatically. (see: http://www.cplusplus.com/reference/string/string/)
I think if you are using
strcpy(pIPAddress,pString.c_str())
then nothing is required to be done, as c_str() returns the a char* to a null terminated string. So after doing the above operation your char array 'pIPAddress' is itself null terminated. So nothing needs to be done to adjust the length as you said.
Related
Let's say I am traversing a string of length n. I want it to end at a specific character that fulfils some conditions. I know that C style strings can be terminated at the i'th position by simply assigning the character '\0' at position i in the character array.
Is there any way to achieve the same result in an std::string (C++ style string)? I can think of substr, erase, etc. but all of them are linear in their complexity, which I cannot afford to use.
TL;DR, is there any "end" character for an std::string? Can I make the end iterator point to the current character somehow?
You can use resize:
std::string s = /* ... */;
if (auto n = s.find(c); n != s.npos) {
s.resize(n);
}
The logical answer here is basic_string::resize. What the standard says about this function is:
Effects: Alters the length of the string designated by *this as follows:
If n <= size(), the function replaces the string designated by *this with a string of length n whose elements are a copy of the initial elements of the original string designated by *this.
If n > size(), the function replaces the string designated by *this with a string of length n whose first size() elements are a copy of the original string designated by *this, and whose remaining elements are all initialized to c.
Now, that looks very much like linear time. However, the standard does not specifically state that things will happen this way. They only state that it will be "as if" things happen this way. Therefore, an implementation is completely free to implement the shrinking version of resize by shifting one pointer and writing a NUL character. Nothing in the standard would forbid such an implementation.
So the real question is... are standard library implementations written by complete morons? It's certainly possible that they are. But it's probably wise not to assume so.
Personally, I'd just use resize on the assumption that the library implementers know what they're doing. After all, if they can't write an optimization as simple as that, then who knows what other things they're doing wrong? If you can't trust your standard library implementation not to do stupid things, then you shouldn't be using it in performance-critical code.
is there any "end" character for an std::string?
No. It is possible to define a std::string that is not null terminated. You won't be able to do a few things for such strings, such as treat the return value of std::string:data() as a null terminated C string 1, but a std::string can be constructed that way.
Can I make the end iterator point to the current character somehow?
To get a std::string::iterator point to a certain character, you'll have to traverse the string.
E.g.
std::string str = "This is a string";
auto iter = str.begin();
auto end = iter;
while ( end != str.end() && *end != 'r' )
++end;
After that, the range defined by iter and end contains the string "This is a st".
If that is not acceptable, you'll have to adapt your code to check the value of the character for every step.
std::string str = "This is a string";
auto iter = str.begin();
// Break when 'r' is encountered or end of string is reached.
while ( iter != str.end() && *iter != 'r' )
{
// Use *iter
...
}
1 Thanks are due to #Cubbi for pointing out an error in what I stated. std::string::data() can return a char const* that is not null terminated if using a version of C++ earlier than C++11. If using C++11 or later, std::string::data() is required to return a null terminated char const*.
std::string does not have an "end character" like c style strings. You can have many null terminators inside a single std::string. If you want to the string to end after a certain character then you need to erase the rest of the characters in the string after that last character.
In your case that would give you something like
string_variable.erase(pos_of_last_character + 1)
TL;DR, is there any "end" character for an std::string? Can I make the end iterator point to the current character somehow?
Not really. std::string uses the std::string::size() function to keep track of the number of characters stored and maintained independently of any sentinel characters like '\0'.
Though these are considered when a std::string is initialized from a const char*.
Is a std::string without a null-character in the end valid and can it be acquired like this?:
std::string str = "Hello World";
str.resize(str.size() - 1);
For those who are curious:
I have a 3rd party function taking a string and iterating over the chars (using iterators). Unfortunately the function is buggy (as its a dev-version) and cannot deal with null-characters. I dont have another signature to chose from, I cant modify the function (as I said, 3rd party and we dont want to fork) and at the same time I dont want to reinvent the wheel. As far as I can tell, the function should work as desired without the null-character so I want atleast to give it a try.
The iteration takes place like this:
bool nextChar(CharIntType& c)
{
if (_it == _end) return false;
c = *_it;
++_it;
return true;
}
where _it is initialized to std::string::begin() and _end to std::string::end()
Until C++11, std::string was not required to include a trailing nul until you called c_str().
http://en.cppreference.com/w/cpp/string/basic_string/data
std::string::data()
Returns pointer to the underlying array serving as character storage. The pointer is such that the range [data(); data() + size()) is valid and the values in it correspond to the values stored in the string.
The returned array is not required to be null-terminated.
If empty() returns true, the pointer is a non-null pointer that should not be dereferenced. (until c++11)
The returned array is null-terminated, that is, data() and c_str() perform the same function.
If empty() returns true, the pointer points to a single null character. (since c++11)
From this we can confirm that std::string::size does not include any nul terminator, and that std::string::begin() and std::string::end() describe the ranges you are actually looking for.
We can also determine this by the simple fact that std::string::back() doesn't return a nul character.
#include <iostream>
#include <string>
int main() {
std::string s("hello, world");
std::cout << "s.front = " << s.front() << " s.back = " << s.back() << '\n';
return 0;
}
http://ideone.com/nUX0AB
While it is possible to have non null terminated strings I would not recommend it, strings are null terminated for a good reason, i would actually recommend in this instance that you either go ahead and write the function properly or get in touch with the third party and have them fix it.
To answer your questions yes a std::string is valid if it is not null terminated, to achieve this you can use the overload of string copy with a maximum length loaded, once again i do not recommend this.
See this page for more information:
http://c2.com/cgi/wiki?NonNullTerminatedString
This is a very late answer but I just post it so that anyone who comes later can use it for their reference. If you write a null terminated string into the string.data() array, it will terminate the string and would not let you to continue concatenate the string if you need to. The way to solve it is already answer in the question.
str.resize(str.size() - 1);
This would solve the problem, I have tested out in my code.
I have a character range with pointers (pBegin and pEnd). I think of it as a string, but it is not \0 terminated. How can I print it to std::cout effectively?
Without creating a copy, like with std::string
Without a loop that prints each character
Do we have good solution? If not, what is the smoothest workaround?
You can use ostream::write, which takes pointer and length arguments:
std::cout.write(pBegin, pEnd - pBegin);
Since C++17 you can use std::string_view, which was created for sharing part of std::string without copying
std::cout << std::string_view(pBegin, pEnd - pBegin);
pEnd must point to one pass the last character to print, like how iterators in C++ work, instead of the last character to print
What is string_view?
In C++11 what is the most performant way to return a reference/pointer to a position in a std::string?
In older C++ standards boost::string_ref is an alternative. Newer boost versions also have boost::string_view with the same semantics as std::string_view. See Differences between boost::string_ref and boost::string_view
If you use Qt then there's also QStringView and QStringRef although unfortunately they're used for viewing QString which stores data in UTF-16 instead of UTF-8 or a byte-oriented encoding
However if you need to process the string by some functions that require null-terminated string without any external libraries then there's a simple solution
char tmpEnd = *pEnd; // backup the after-end character
*pEnd = '\0';
std::cout << pBegin; // use it as normal C-style string, like dosomething(pBegin);
*pEnd = tmpEnd; // restore the char
In this case make sure that pEnd still points to an element inside the original array and not one past the end of it
I am very confused about when to use string (char) and when to use string pointers (char pointers) in C++. Here are two questions I'm having.
which one of the following two is correct?
string subString;
subString = anotherString.sub(9);
string *subString;
subString = &anotherString.sub(9);
which one of the following two is correct?
char doubleQuote = aString[9];
if (doubleQuote == "\"") {...}
char *doubleQuote = &aString[9];
if (doubleQuote == "\"") {...}
None of them are correct.
The member function sub does not exist for string, unless you are using another string class that is not std::string.
The second one of the first question subString = &anotherString.sub(9); is not safe, as you're storing the address of a temporary. It is also wrong as anotherString is a pointer to a string object. To call the sub member function, you need to write anotherString->sub(9). And again, member function sub does not exist.
The first one of the second question is more correct than the second one; all you need to do is replace "\"" with '\"'.
The second one of the second question is wrong, as:
doubleQuote does not refer to the 10th character, but the string from the 10th character onwards
doubleQuote == "\"" may be type-wise correct, but it doesn't compare equality of the two strings; it checks if they are pointing to the same thing. If you want to check the equality of the two strings, use strcmp.
In C++, you can (and should) always use std::string (while remembering that string literals actually are zero-terminated character arrays). Use char* only when you need to interface with C code.
C-style strings need error-prone manual memory management, need to explicitly copy strings (copying pointers doesn't copy the string), and you need to pay attention to details like allocating enough memory to have the terminating '\0' fit in, while std::string takes care of all this automagically.
For the first question, the first sample, assuming sub will return a substring of the provided string.
For the second, none:
char doubleQuote = aString[9];
if( doubleQuote == '\"') { ... }
Erm, are you using string from STL?
(i.e. you have something like
#include <string>
#using namespace std;
in the beginning of your source file ;) )
then it would be like
string mystring("whatever:\"\""");
char anElem = mystring[9];
if (anElem=="\"") { do_something();}
or you can write
mystring.at(9)
instead of square brackets.
May be these examples can help.
If I want to construct a std::string with a line like:
std::string my_string("a\0b");
Where i want to have three characters in the resulting string (a, null, b), I only get one. What is the proper syntax?
Since C++14
we have been able to create literal std::string
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-\0-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
Before C++14
The problem is the std::string constructor that takes a const char* assumes the input is a C-string. C-strings are \0 terminated and thus parsing stops when it reaches the \0 character.
To compensate for this, you need to use the constructor that builds the string from a char array (not a C-String). This takes two parameters - a pointer to the array and a length:
std::string x("pq\0rs"); // Two characters because input assumed to be C-String
std::string x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.
Note: C++ std::string is NOT \0-terminated (as suggested in other posts). However, you can extract a pointer to an internal buffer that contains a C-String with the method c_str().
Also check out Doug T's answer below about using a vector<char>.
Also check out RiaD for a C++14 solution.
If you are doing manipulation like you would with a c-style string (array of chars) consider using
std::vector<char>
You have more freedom to treat it like an array in the same manner you would treat a c-string. You can use copy() to copy into a string:
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
and you can use it in many of the same places you can use c-strings
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
Naturally, however, you suffer from the same problems as c-strings. You may forget your null terminal or write past the allocated space.
I have no idea why you'd want to do such a thing, but try this:
std::string my_string("a\0b", 3);
What new capabilities do user-defined literals add to C++? presents an elegant answer: Define
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
then you can create your string this way:
std::string my_string("a\0b"_s);
or even so:
auto my_string = "a\0b"_s;
There's an "old style" way:
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
then you can define
std::string my_string(S("a\0b"));
The following will work...
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
You'll have to be careful with this. If you replace 'b' with any numeric character, you will silently create the wrong string using most methods. See: Rules for C++ string literals escape character.
For example, I dropped this innocent looking snippet in the middle of a program
// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '\0' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
Here is what this program output for me:
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
That was my first print statement twice, several non-printing characters, followed by a newline, followed by something in internal memory, which I just overwrote (and then printed, showing that it has been overwritten). Worst of all, even compiling this with thorough and verbose gcc warnings gave me no indication of something being wrong, and running the program through valgrind didn't complain about any improper memory access patterns. In other words, it's completely undetectable by modern tools.
You can get this same problem with the much simpler std::string("0", 100);, but the example above is a little trickier, and thus harder to see what's wrong.
Fortunately, C++11 gives us a good solution to the problem using initializer list syntax. This saves you from having to specify the number of characters (which, as I showed above, you can do incorrectly), and avoids combining escaped numbers. std::string str({'a', '\0', 'b'}) is safe for any string content, unlike versions that take an array of char and a size.
In C++14 you now may use literals
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
Better to use std::vector<char> if this question isn't just for educational purposes.
anonym's answer is excellent, but there's a non-macro solution in C++98 as well:
template <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
With this function, RawString(/* literal */) will produce the same string as S(/* literal */):
std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
Additionally, there's an issue with the macro: the expression is not actually a std::string as written, and therefore can't be used e.g. for simple assignment-initialization:
std::string s = S("a\0b"); // ERROR!
...so it might be preferable to use:
#define std::string(s, sizeof s - 1)
Obviously you should only use one or the other solution in your project and call it whatever you think is appropriate.
I know it is a long time this question has been asked. But for anyone who is having a similar problem might be interested in the following code.
CComBSTR(20,"mystring1\0mystring2\0")
Almost all implementations of std::strings are null-terminated, so you probably shouldn't do this. Note that "a\0b" is actually four characters long because of the automatic null terminator (a, null, b, null). If you really want to do this and break std::string's contract, you can do:
std::string s("aab");
s.at(1) = '\0';
but if you do, all your friends will laugh at you, you will never find true happiness.