Search code examples
cpointersreversedereference

Reversing a '\0' terminated C string in place?


I have some conceptual questions about reversing a null terminated C string, and clarification questions about the nature of pointers.

The input might be

char arr[] = "opal";

and the code:

void reverse(char *str) {  /* does *str = opal or does *str = o since the pointer str is type char? */

    char* end  = str; /* what is the difference between char* end and char *end? and is *end pointing to opal now? */

    char tmp;

    if (str) {  /* if str isn't null? */
        while (*end) 
            ++end; 
    }
    --end; /* end pointer points to l now */

    while (str < end) {     /* why not *str < *end? is this asking while o < l? */
        tmp = *str; /* tmp = o */

        *str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */
        *end-- = tmp; /* *end points to o */
        }
    }
}

Solution

  • Lots of questions... trying to capture answers to each:

    /* does *str = opal or does *str = o since the pointer str is type char? */

    *str is 'o' since it points at the first character

    /* what is the difference between char* end and char *end? and is *end pointing to opal now? */

    There is no difference between char *end and char* end. It gets trickier when you write

    char* a, b;
    

    since this is equivalent to

    char *a, b;
    

    and not, as you might think

    char *a, *b;
    

    This is why it's cleaner to write char *end;.

    And end is pointing to opal now - *end is 'o'.

    if (str) { /* if str isn't null? */

    Yes - testing that you did not get passed a NULL pointer

    To test that you did not get passed a string of length 0, you would have to test *str (after testing that str is not NULL, otherwise you get a segmentation error for "daring to look at *NULL")

    while (str < end) { /* why not *str < *end? is this asking while o < l? */

    Testing the pointers - one is moving towards the end, the other is moving back. When you meet in the middle you stop; otherwise you do the swap twice, and there will be no net effect...

     *str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */
    

    You first copy the value of *end to *str, then you increment the str pointer. If you put ++str, you increment first, then use it. And that would mean that you put the l in place of the p instead of in place of the o.

    edit one critique on your code (going beyond the questions you asked, and responding to a comment from @chux): when you test for if(str){} you really need an else return; statement, since you actually do end--; and then use *end. Pretty sure that 0xFFFFFFFFFFFFFFFF is almost always an invalid address...

    If you in fact were testing for if(*str!='\0') then you should still just return (an empty string is "irreversible" - or rather, it doesn't need anything to be considered reversed).

    By the way, I much prefer making the condition explicit (like I did just then); not only does it show your intention more clearly, but the compiler might actually complain if you did if(str!='\0') or if(*str != NULL) since the types you are comparing are incompatible. This means you will have code that is more robust, more readable, and more likely to do what you intended.