1

So far as I know, when we create an array or string, their names are pointers to their first elements. And the pointer, in this case, cannot be changed.

However, this piece of code works:

#include <stdio.h>

void swapString(char **str1_ptr, char **str2_ptr)
{
    char *temp = *str1_ptr;
    *str1_ptr = *str2_ptr;
    *str2_ptr = temp;
}

int main()
{
    char strings[][30] = {"Test1","Test2","Test3"};
    int i;
    
    swapString((char **)&strings[0],(char **)&strings[1]);
    
    for(i=0;i<3;i++){
        printf("%s\n",strings[i]);
    }
    
    return 0;
}

Why does this work well? Is it a good practice to swap strings (or arrays in general) in this way? When it is not a good idea to use this approach?

4
  • Why do you think the pointer cannot be changed? What prevents it? Commented Oct 13, 2021 at 4:58
  • @Cheatah Actually, the addresses pointed by the name os strings and arrays cannot be changed, so far as I know. Can we change it? Commented Oct 13, 2021 at 5:02
  • Yes, if they are not declared const. The biggest risk is that your function assumes it can just change the pointers, while in reality the pointers are put in some read-only section. That's up to the developer to keep track of, and properly apply const specifiers. Commented Oct 13, 2021 at 5:16
  • 1
    @Cheatah there are no pointers involved but an array. Commented Oct 13, 2021 at 6:59

1 Answer 1

5

Why does this work well?

It does not work well. It seems to work well because you lie to your compiler and use insufficient test data.

void swapString(char **str1_ptr, char **str2_ptr)
{
    char *temp = *str1_ptr;
    *str1_ptr = *str2_ptr;
    *str2_ptr = temp;
}

You claim to provide a pointer to a pointer. As a consequence this functions swaps as much bytes between two places as a pointer takes. That is 4 or 8 bytes on most systems.

But then you pass addresses of arrays, not pointers to pointers:

    char strings[][30] = {"Test1","Test2","Test3"};
    
    swapString((char **)&strings[0],(char **)&strings[1]);

This is causing undefined behaviour. You are using casts because your compiler told you that this is crab if you remove them:

test.c:15:28: warning: passing argument 2 of ‘swapString’ from incompatible pointer type [-Wincompatible-pointer-types]
   15 |     swapString(&strings[0],&strings[1]);
      |                            ^~~~~~~~~~~
      |                            |
      |                            char (*)[30]
test.c:3:41: note: expected ‘char **’ but argument is of type ‘char (*)[30]’

As a result the function thinks it swaps a pointer but instead it swaps the first 8 bytes of your array.

To verify this you could use longer strings:

#include <stdio.h>

void swapString(char **str1_ptr, char **str2_ptr)
{
    char *temp = *str1_ptr;
    *str1_ptr = *str2_ptr;
    *str2_ptr = temp;
}

int main()
{
    char strings[][30] = {"Test111111","Test222222","Test333333"};
    int i;

    swapString((char **)&strings[0],(char **)&strings[1]);

    for(i=0;i<3;i++){
        printf("%s\n",strings[i]);
    }

    return 0;
}

And then you get the result you deserve. ;)

Test$ ./test
Test222211
Test111122
Test333333

In case of 32bit addresses you need to make the first 4 bytes of your strings distinguishable.

As you can see, there are no swapped pointers at all. Just the start of your arrays is messed up.

If you want to swap strings by just swapping pointers, you need to change your array definition:

    char *strings[] = {"Test111111","Test222222","Test333333"};
    swapString(&strings[0],&strings[1]);

As a side effect you can also drop the casts from your function call as the types now match what is expected.

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

1 Comment

Nice explanation! Thank you!

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.