-2

Can someone please let me know where the problem is and how to correct it.

The function is required to remove all whitespace from a string which includes ' ', '\t' and '\n' The output of the function should be a copy of the input string but with all of whitespace removed. The function prototype should stay the same and void.

void removeWS(char *strNoSpace, const char *strWithSpace)
{
    int i, j;

    stringNoSpace = malloc(strlen(strWithSpace) + 1);

    for(i = 0, j = 0; stringWithSpace[i] != '\0'; i++, j++){

        if (isspace((char) strWithSpace[i]) != 0){

            strNoSpace[j++] = strWithSpace[i];

        }

    }

}
  • Can you give the example inputs and the unexpected output? Dramatically reduces time spent checking code. – ShadowRanger Oct 08 '15 at 14:24
  • Placing a null char `'\0'` in a string will effectively cut it short. – M Oehm Oct 08 '15 at 14:24
  • Use a debugger. SO is no debugging service, but helps with **specific** problems. – too honest for this site Oct 08 '15 at 14:26
  • 3
    [Why did you asked same question again ?](http://stackoverflow.com/questions/33015305/removing-whitespace-from-a-character-array-in-c) – ameyCU Oct 08 '15 at 14:27
  • @MOehm: If they weren't advancing `j` in the `for` loop increment step that wouldn't be a problem (because they'd replace the `NUL` on the next loop). `j` is just getting incremented more than it should (in both space and non-space cases). – ShadowRanger Oct 08 '15 at 14:29
  • Try not to allocate more memory than you actually need. stringNoSpace = malloc(strlen(strWithSpace) + 1) could allocate more memory from OS than you need. Adding a null at the end of string does not free memory to system. First could redundant symbols and then use malloc. – Kamen Stoykov Oct 08 '15 at 14:32
  • @ShadowRanger: The increment in the for loop update is superflous. `j` should only be incremented on appending to the destination string, since `j` is the destination string length. – M Oehm Oct 08 '15 at 14:34
  • Possible duplicate of [How do I trim leading/trailing whitespace in a standard way?](http://stackoverflow.com/questions/122616/how-do-i-trim-leading-trailing-whitespace-in-a-standard-way) <-- not 100% duplicate, but at least look into the many examples there, and use them as a basis – Elias Van Ootegem Oct 08 '15 at 14:35

4 Answers4

2

Stripped down to the actual issue:

void removeWS(char *strNoSpace, const char *strWithSpace)
{
    strNoSpace = malloc(strlen(strWithSpace) + 1);
    // ...
}

// ....
char* paramStrNoSpace = NULL;
char* paramStrWithSpace = "...";
removeWS(paramStrNoSpace, paramStrWithSpace);

Now strNoSpace is a copy of paramStrNoSpace It points to the same memory, which in this case is NULL. Then inside your function you change strNoSpace to something, malloc() returns. Now strNoSpace is something different to NULL, while paramStrNoSpace is still NULL, because strNoSpace was a copy of that pointer.

A simple soulution could be to pass a pointer to a pointer instead:

void removeWS(char **strNoSpace, const char *strWithSpace)
{
    *strNoSpace = malloc(strlen(strWithSpace) + 1);
    // ...
}

// ....
char* paramStrNoSpace = NULL;
char* paramStrWithSpace = "...";
removeWS(&paramStrNoSpace, paramStrWithSpace);

Now strNoSpace points to the exact position, where the pointer paramStrNoSpace is stored. Whenever you modify *strNoSpace, you actually modify paramStrNoSpace now.

The downside of that approach is, that you will loose track of your memory allocations sooner or later, when functions just allocate and return new memory. The rule of thumb is: whoever allocates memory, is also responsible to free it. Therefore I think a better interface would expect the caller to allocate enough memory for this function:

void removeWS(char *strNoSpace, ind strNoSpaceMaxSize, const char *strWithSpace)
{
    // ...
}

// ....
char* paramStrWithSpace = "...";
char* paramStrNoSpace = malloc(strlen(paramStrWithSpace) + 1);
removeWS(paramStrNoSpace, strlen(paramStrWithSpace), paramStrWithSpace);

Now removeWS() does never change strWithSpace. Therefore we can pass it as a simple pointer again, but we have to tell removeWS() the size of the allocated memory block. It has to check while running and stop in case, there is not enough memory.

cdonat
  • 2,748
  • 16
  • 24
1

I see three obvious issues:

  1. You refer to string in the for condition, not strWithSpace
  2. You're only placing NUL ('\0') terminators when you see a space (which is actually pointless, since you'll overwrite on the next non-space character), but not when you finish the loop, so if the input doesn't end with whitespace, the string isn't NUL-terminated.
  3. You're advancing (or not) j correctly within the loop, but also advancing it in the for loop increment step, so you'll leave NULs scattered around (prematurely terminating the string) and skip non-space characters before then.
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 1
    You should be able to do this yourself from the description. Set `strNoSpace[j] = '\0';` after the loop, remove `, j++` from `for` loop's final clause, and change `string` to `strWithSpace` in `for` loop conditional. StackOverflow isn't a "write the exact code for me" sort of service, even if sometimes people do spell everything out in excessive detail. – ShadowRanger Oct 08 '15 at 14:41
1

This can be done inplace as characters are being removed. The pointers to and from advance through the string. When a space is found only from is advanced.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

void removeWS( char *strWithSpace)
{
    //declare two pointers and set them to first character of strWithSpace
    char *to = strWithSpace;
    char *from = strWithSpace;

    while ( *from) {//when from points to terminating '\0' while will exit
        if ( isspace ( *from)) {
            from++;//found space character, advance from
            continue;//back to top of while
        }
        *to = *from;//copy from character to to
        to++;//advance to
        from++;//advance from
    }
    *to = '\0';//set terminating '\0'
}

int main( int argc, char *argv[])
{
    char text[40] = {"text with spaces between the words"};

    printf("before   %s\n", text);
    removeWS( text);
    printf("after    %s\n", text);

    return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16
0

try this

void removeWS(char *strNoSpace, const char *strWithSpace)
{
    int i, j;

    strNoSpace = malloc(strlen(strWithSpace) + 1);
    if ( strNoSpace == NULL ) {
            // error handle 
    }

    for(i = 0, j = 0; strWithSpace[i] != '\0'; i++ ) {    
        if ( isspace( strWithSpace[ i ] ) == 0 ) {
                strNoSpace[j++] = strWithSpace[i];    
        }    
    }
    strNoSpace[ j ] = '\0';
}
Itay Sela
  • 942
  • 9
  • 26