views:

4362

answers:

11

What is the best approach in stripping leading and trailing spaces in C?

+5  A: 

This question looks as if it might be a homework question, so I'll answer obliquely: look up the man pages for isspace(3) and strlen(3) and use pointer arithmetic. Also depending on the problem at hand you may need malloc(3) to hold space for the result.

Don't forget that the representation of a C string includes a trailing 0 byte, often written '\0', which is not counted as part of the length of the string.

Norman Ramsey
A: 
int i = strlen(s) - 1;
while (isspace(s[i]))
    s[i--] = '\0';
while (isspace(*s))
    s++;

That should take care of the problem as long as you don't care about mangling up the string like crazy and if you don't care about memory leaks!

mcjabberz
what heppens if s contains only spaces? ;-)
Serge
This will under run if s is zero lenth or contains only spaces.
Binary Worrier
A: 

You should be able to do it in-place; stripping whitespace can never cause the string to grow. You might be able to do it without first checking the length of the string, but doing so might be needlessly "clever". You should look into the memmove() function, in addition to the ones @Norman Ramsey mentioned.

unwind
+12  A: 

Here is how linux kernel does the trimming, called strstrip():

char *strstrip(char *s)
{
    size_t size;
    char *end;

    size = strlen(s);

    if (!size)
     return s;

    end = s + size - 1;
    while (end >= s && isspace(*end))
     end--;
    *(end + 1) = '\0';

    while (*s && isspace(*s))
     s++;

    return s;
}

Its basically a better formatted and error-checked version what the previous poster said.

Tuminoid
This implementation is easy to misuse. A naive user is likely to try to free the returned pointer (or overwrite their original pointer). Since we're not working in the kernel, I think it would be nicer to copy the trimmed string to the beginning of the buffer :)
fpsgamer
This looks quite bad. You're not only altering the original string but creating another pointer at a different location; I'd say this is a bad example at this level; I also agree that a buffer should be passed, or the result stored somewhere else.
widgisoft
...If you don't keep the original pointer; surely you've just caused a memory leak as the initial "space" can never be recovered.
widgisoft
This discussion shows that what makes a good answer depends on the context in which the code will be used. If preserving the original string is important, this is not the solution; otherwise, this works. It also works unless tracking the initial pointer is important or a memory copy is an issue,
Jonathan Leffler
To address the concerns listed in the comments, you could just return strdup(s) and require the caller free the result. (i know non-standard but it's like 4 lines to hand roll if you don't have it).
Evan Teran
@widgisoft: you aren't losing the original pointer, it isn't passed by "reference" or anything. you could easily do this safely. char *const s = strpdup(" hello world"); char *const s2 = strstrip(s); /* use s2 */ free(s);
Evan Teran
+2  A: 

You can do this entirely in place.

 void stripLeadingAndTrailingSpaces(char* string){

     assert(string);

     /* First remove leading spaces */

     const char* firstNonSpace = string;

     while(*firstNonSpace != '\0' && isspace(*firstNonSpace))
     {
          ++firstNonSpace;
     }

     size_t len = strlen(firstNonSpace)+1;         

     memmove(string, firstNonSpace, len);

     /* Now remove trailing spaces */

     char* endOfString = string + len;

     while(string < endOfString  && isspace(*endOfString))
     {
          --endOfString ;
     }

     *endOfString = '\0';

}
fpsgamer
There are two problems with this: (1) strcpy has undefined behaviour if the source and destination buffers overlap (use memmove or a while loop to copy the string), and (2) consider what happens if the string contains embedded whitespace characters, not just leading and trailing spaces.
ChrisN
I don't really like the use of assert here. In my mind, assert means 'this _really_ shouldn't happen, but just in case', whereas a null pointer passed to this function is quite possible. Perhaps it is merely taste.
Bernard
My interpretation is this: A string which consists of one or more printable characters is of course a string. An empty string (containing only the null terminator) is also a string. However, a string which is just a null pointer is not a string at all; this is a precondition violation.
fpsgamer
I would like to see this calculate the size that actually NEEDS to be memmoved rather than memmoving the whole string and then trimming the trailing spaces.
SoapBox
@eben: One could argue that NULL pointers are so common that you have the wrong precondition. I would put the test for NULL inside the function otherwise you are forcing all users of your function to test for NULL. Do users to always do this: if (x) {stripLeadingAndTrailingSpaces(x);}
Martin York
isspace('\0') is not TRUE. Check your algorithm actually strips the back space.
Martin York
If the string is all blank, this code does 'strlen()' from the first character after the trailing '\0'. The result is unlikely to be satisfactory!
Jonathan Leffler
It would also be more efficient if you worked out where the last non-space character is before you did the memmove() - there is not much point in copying the trailing spaces if you are then going to hide them after a NUL '\0'.
Jonathan Leffler
Any solution eliciting this much commentary is not a strong solution.
Norman Ramsey
I've never seen an accepted answer with negative votes before.
Graeme Perrow
i also think that this is wrong: char* endOfString = string + len; you will point exactly at the terminating, new null character. which is of course not a space, and your loop immediately terminates.
Johannes Schaub - litb
anyway, i agree with the guy with assert, would use it myself too. that NULL pointers are common is not a good argument IMHO. that makes them not valid arguments or valid strings.
Johannes Schaub - litb
i think this statement char* endOfString = string + len is really wrong because you indexed the string out of bound, consider "abc",then according to your algorithm,len is 4,then string+4 is absolutely exception.
Tracy
+4  A: 

Here's a version using isspace:

char * trim(char *c) {
    char * e = c + strlen(c) - 1;
    while(*c && isspace(*c)) c++;
    while(e > c && isspace(*e)) *e-- = '\0';
    return c;
}
Johannes Schaub - litb
+3  A: 
char *strstrip(char *s)
{
    char *end;

    while ( (*s) && isspace( *s))
        s++;

    if(!( *s) )
        return s;
    end = s;

    while( ! *end)
        end++;
    end--;

    while (end ! = s && isspace( *end))
        end--;
    *(end + 1) = '\0';

    return s;
}

It is basically a more optimized code (in terms of speed & codesize ).

If we need to retain memory space then,

void strstrip(char *s)
{
    char *start;
    char *end;

    start = s; 
    while ( (*start) && isspace( *start))
        start++;

    if(!( *start) ) 
    {
        *s='\0';
        return ;
    }
    end = start;

    while( ! *end)
        end++;
    end--;

    while (end ! = start && isspace( *end))
        end--;
    *(end + 1) = '\0';

    memmove(s, start, end-start+1);

    return;
}
lakshmanaraj
A: 

If you're on Linux/Windows and have the library glib linked into your program, you can use the the routine g_strstrip().

Ben Combee
+2  A: 

Here is a more concise and safer version of lakshmanaraj's first function:

#include <ctype.h>
char *mytrim(char *s)
{
    if(s) { /* Don't forget to check for NULL! */
        while(*s && isspace(*s))
            ++s;
        if(*s) {
            register char *p = s;
            while(*p)
                ++p;
            do {
                --p;
            } while((p != s) && isspace(*p));
            *(p + 1) = '\0';
        }
    }
    return(s);
}
Anthony Cuozzo
checking s is not null should be done before the function call. Assume s is a garbage pointer and then how do you gaurantee that this program? Hence bset practice is that S should be checked before the function call and not inside the function call.
lakshmanaraj
@lakshmanaraj: I said safer...not safe. What if our user is on a non-standard system and wants to call the function like this: mytrim(strdup(x));?
Anthony Cuozzo
A: 

while(s && isspace(s))
is redundant
(edit- I do not know why the asterisks in the above line are not visible)

while (isspace(*s))
does the same thing

assume you have a string s=" ". where s[1]=0 isspace(0) also true and hence a pointer will get incremented and then it will go for checkingisspace(s[2]) which is wrong. Hence to limit s[1]!=0 in otherwords s[1] = *s
lakshmanaraj
A: 

has anyone knows how to write for any function whcich to delete all spaces from string.

Sorry for my bad english. :-((

You can post as another question, instead of asking here!
lakshmanaraj