tags:

views:

386

answers:

5

What is the easiest and most efficient way to remove spaces from a string in C?

Thanks.

+9  A: 

Easiest and most efficient don't usually go together...

Here's a possible solution (untested):

void RemoveSpaces(char* source)
{
  char* i = source;
  char* j = source;
  while(*j != 0)
  {
    *i = *j++;
    if(*i != ' ')
      i++;
  }
  *i = 0;
}
Aaron
What happens if the input source was initialized from a string literal?
Suppressingfire
@Suppressingfire: assuming you mean `RemoveSpaces("blah");`, and not `char a[] = "blah"; RemoveSpaces(a);`, then undefined behaviour. But that's not the fault of this code. It is not recommended to pass a read-only string to a function which is documented to modify the string passed to it (by, for example, removing spaces) ;-)
Steve Jessop
+2  A: 
#include <ctype>

char * remove_spaces(char * source, char * target)
{
     while(*source++ && *target)
     {
        if (!isspace(*source)) 
             *target++ = *source;
     }
     return target;
}

Notes;

  • This doesn't handle Unicode.
quark
Won't this skip the first character?
Aaron
@Aaron: Yup. Fixed.
quark
You should cast the value passed to `isspace` to `unsigned char`, since that function is defined to accept a value either in the range of `unsigned char`, or EOF.
caf
A: 

I assume the C string is in a fixed memory, so if you replace spaces you have to shift all characters.

The easiest seems to be to create new string and iterate over the original one and copy only non space characters.

stefanB
+1  A: 

In C, you can replace some strings in-place, for example a string returned by strdup():

char *str = strdup(" a b c ");

char *write = str, *read = str;
do {
   if (*read != ' ')
       *write++ = *read;
} while (*read++);

printf("%s\n", str);

Other strings are read-only, for example those declared in-code. You'd have to copy those to a newly allocated area of memory and fill the copy by skipping the spaces:

char *oldstr = " a b c ";

char *newstr = (char*) malloc(strlen(oldstr)+1);
char *np = newstr, *op = oldstr;
do {
   if (*op != ' ')
       *np++ = *op;
} while (*op++);

printf("%s\n", newstr);

You can see why people invented other languages ;)

Andomar
Your second example forgets to properly terminate the destination string.
caf
..and your first example doesn't do the right thing at all (eg if the string starts off with two non-space characters).
caf
@caf: The while loop will run for the \0 terminator, because it's `while (*(op++))` and not `while (*(++op))`
Andomar
@caf: You're right about the first example, edited now
Andomar
That's true, which means the it's still buggy, because it skips the first character regardless of whether it's a space or not.
caf
@caf: Righty, fixed
Andomar
You can common up the loop here: `void copyExceptSpace(char*, const char*);`, `void removeSpace(char *s) { copyExceptSpace(s,s); }`, `char *dupExceptSpace(const char *s) { char *n = malloc(strlen(s)+1); if (n) copyExceptSpace(n,s); return n; }`. Or something like that.
Steve Jessop
A: 

Braces are unnecessary:

do while(isspace(*s)) s++; while(*d++ = *s++);

The above should be perfectly safe.

But, if you can risk some undefined behavior, and never have empty strings, you can get rid of the body:

while(*(d+=!isspace(*s++)) = *s);

Heck, if by space you mean just space character, so much "bloat" can be removed:

while(*(d+=*s++!=' ')=*s);

Don't use that in production :)

porneL
Interesting, the first two function on my machine. But I guess all of these are undefined, since using s++ and *s in one statement results in undefined behavior?
Andomar
make sure that you aren't beyond the end of the string when dereferencing it.
Casey
@Andomar: First one is completely safe and sound. Last two are sketchy indeed (tested in GCC4.2).
porneL