2

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

5 Answers 5

5

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Somewhat more verbose, but I'd use remove_copy_if and an IsNotSpace functional object which used one of the isspace functions from the standard. (Generally, when one wants to "remove spaces", white space, and not just the space character, is meant.)
in your example 'ip' would not be null terminated, remove_copy_if doesn't append the '\0'
@DavidRodríguez-dribeas Using isspace from <cctype> doesn't work, because it only has defined behavior if the int it is passed is in the range [0...UCHAR_MAX] or is EOF. (In practice, a lot of implementations do make it work with negative characters.) If you're doing any amount of text processing, however, one of the first things you should do is write simple functional object wrappers for all of the ctype functions. You'll use them a lot. (Mine take a locale object, defaulting to the global one, and use the functions in <locale>.)
0

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.

3 Comments

<cctype> has an isspace function which cannot be called with a char (since the value of a char might be negative), and <locale> has a number of ways of testing for space, all of which require a std::locale object or the std::ctype facet.
while that info is all in the links I provided, you're right to point this out explicitly. But both his example and variable names suggest he just wants to remove trailing spaces from IP addresses, for which boost::trim is in my opinion the best solution. So I didn't want to emphasize the isspace too much.
I understand. For "simple" cases like this, boost::trim or some similar already-written function is probably the best solution. For starters, it will probably use isspace, and use it correctly:-)
0

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.

5 Comments

This code is undefined behavior, after removal of the iterator, you cannot use it any longer (in particular, you cannot increment it in the next pass of the loop). Additionally, even if it was not UB, it would still be incorrect, as it would fail to remove two consecutive spaces (i.e. the first one will be removed, the second one would take it's position and then the iterator would be incremented to one position after the new location of the second space).
It is simpler to do as: for (iterator it = tmp.begin(); it != tmp.end(); ) { if ( *it==' ' ) it = tmp.erase(it); else ++it; } avoiding the need for the nested loop (both of which update the same control variable). And then again, it is better yet to use std::remove_copy in the first place: string tmp; remove_copy( src.begin(), src.end(), std::back_inserter(tmp), ' ' ); and avoid potential bugs in the code...
@kbok After the edit (I think), the code has undefined behavior if the string ends with spaces, since it will dereference the end iterator, and possibly increment it as well (if it doesn't crash or go into an endless loop first).
@JamesKanze I edited the code. Now this solution seems too complex to be actually useful, but I'll leave it since the discussion was interesting.
@kbok It's still not correct, because if the text ends with a space, the inner loop will leave iter at the end, and the outer loop will increment it. (In general, STL iterators don't work well with in-place modifications. It's usually much better to generate into a new object, then assign the results to the original.)
-1

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/)

Comments

-1

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.

2 Comments

@duedl0r , But in his example he talked about pIPAddress[13]=0; which means he is talking about null termination actually not spaces.
he wants to remove spaces.. so he sets the first space to null. It's not about the ending null from a string.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.