0

I'm having some issues trying to remove all whitespace from a string (for example: "a b c x") using a method that takes a double pointer argument. I have solved it using single pointers and using strings in c++, but I wanted to get this working as well for curiosity's sake :)

This is what I've tried:

void remove_whitespace(char** s)
{
    char **rd; // "read" pointer
    char **wr; // "write" pointer

    rd = wr = s; // initially, both read and write pointers point to beginning of string

    while ( *rd != 0 ) // while not at end of string
    {
    while ( isspace( **rd ) ) // while rd points to a whitespace character
        rd++;                  // advance rd
    *wr++ = *rd++;           // copy *rd to *wr, advance both pointers
    }
    *wr = 0;                   // terminate the result

    printf("\nsquished: %s\n", s);
}

11
  • 6
    Why char** over char*? Commented Jan 13, 2023 at 16:58
  • 1
    Why are you using char ** for a single string? You don't reassign s so there's no need. Commented Jan 13, 2023 at 16:58
  • 1
    should be printf("\nsquished: %s\n", *s);, "%s" expects a char* Commented Jan 13, 2023 at 17:00
  • 1
    If you need to have char** s you can have char *rd, *wr; rd = wr = *s;. Commented Jan 13, 2023 at 17:03
  • 1
    Jonas Örnfelt, post how remove_whitespace() is called. Post a minimal reproducible example. Commented Jan 13, 2023 at 17:06

2 Answers 2

1

All errors in this function stem from confusing the level of indirection. Using char** over char* increases the level of indirection which affects every usage of these variables.

Simply converting the function to use char* makes it much clearer:

void remove_whitespace(char* s)
{
    char *rd; // "read" pointer
    char *wr; // "write" pointer

    rd = wr = s; // initially, both read and write pointers point to beginning of string

    while ( *rd != 0 ) // while not at end of string
    {
        if (isspace( *rd ) ) // while rd points to a whitespace character
        {
            rd++;                  // advance rd
            continue;
        }
        *wr++ = *rd++;           // copy *rd to *wr, advance both pointers
    }
    *wr = 0;                   // terminate the result

    printf("\nsquished: %s\n", s);
}
Sign up to request clarification or add additional context in comments.

6 Comments

In the first version, *wr++; and *rd++; should be (*wr)++; and (*rd)++;.
'Here is a correct version while keeping char**' – have you tested? This looks pretty suspicious to me: *rd++; increments the pointee of rd, but due to rd = wr = s; this is the same pointee than the one of wr, so you increment *wr right with it, and actually *s, too!
You guys are correct. Fixed.
There is still one uncorrected *rd++;. Also, @Aconcagua's point about *s being modified still holds.
Probably best just to get rid of the first version. It's neither correct nor useful!
|
0
  1. It is good if function returns something.
  2. Your local worker pointers do not have to be pointers to pointers
char **remove_whitespace(char **s)
{
    char *rd; // "read" pointer
    char *wr; // "write" pointer

    rd = wr = *s; 

    while ( *rd) // while not at end of string
    {
    while ( isspace( (unsigned char)*rd ) ) // while rd points to a whitespace character
        rd++;                  // advance rd
    *wr++ = *rd++;           // copy *rd to *wr, advance both pointers
    }
    *wr = 0;                   // terminate the result

    printf("\nsquished: %s\n", *s);
    return s;
}

Usage:

int main(void)
{
    char z[] = "asdas das as \r dfds \n dsa \t";
    char *p = z;

    remove_whitespace(&p);
}

https://godbolt.org/z/Ex337TE6n

5 Comments

@JonasÖrnfelt because you do not pass pointer to pointer. READ THE WARNINGS IN YOUR CODE!!!! If you pass &z it will not give pointer to pointer only pointer to array and it is not thee same
'Your local worker pointers do not have to be pointers to pointers' – actually even: 'must not' – at least if initialised as in the question...
It is good if function returns something. Depends... In many cases convenient, but opens the question: Is the string returned a copy (i.e. does it have to be freed) or is the modification in place? Sure, documentation needs to reveal that anyway, but a void return type would automatically imply the latter (self-documenting code)...
Ah, okay. I was calling it with: char* test = "a b c "; remove_whitespace(&test);
You can't modify the string literal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.