Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 */
        }
    }
}
like image 517
Opal Avatar asked Jan 14 '14 01:01

Opal


2 Answers

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.

like image 140
Floris Avatar answered Sep 19 '22 01:09

Floris


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

*str dereferences the pointer, which is of type char*, so the type you get is char. That char will be the value pointed to by str, which will be 'o'.

what is the difference between char* end and char *end?

Nothing.

and is *end pointing to opal now?

Yes, well, close. end is pointing to exactly the same adddress as str, which is the start of your string of characters. *end is a character type, not a pointer. Its value will be 'o'.

if str isn't null?

Correct, doing a boolean test on a pointer is a standard test. It evaluates to a 'true' value if the pointer is not null and 'false' otherwise. Note that this is not the same as a zero value. The C standard allows any value to represent a null address.

why not *str < *end? is this asking while o < l?

No, it is comparing the actual memory address. It says to loop while str points to an earlier part of the string than end. You'll notice that during the loop, str increases, and end decreases. So eventually they will pass eachother or meet at the same character (ie the middle of the string).

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

str++ is applied first, which increments str and returns its previous value, then the * unary operator derferences to give the character at that old position. Yes, the first time around, the 'l' from end will be assigned to the beginning of the string (where str used to point before it was incremented). The tmp is used to carry the old character and assign it to end. This is a standard 'swap' operation.

like image 32
paddy Avatar answered Sep 19 '22 01:09

paddy