Domanda

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 */
        }
    }
}
È stato utile?

Soluzione

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.

Altri suggerimenti

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.

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

str is pointer to first element of opal, i.e, it is pointer to first letter o. So, *s means , you are dereferencing the s (the first address) hence it is 'o'.

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

There is no difference. No. It is end that is pointing to opal, i.e, its first element now.

if str isn't null?

Yes.

end pointer points to l now

Yes. It is now pointing to the last letter of the word.

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

*str++ means str will incremented after the value dereferenced str pointing to. ++str simply the pre-incrementation of str.
*str++ = assign the value to the dereferenced variable before incrementing str.

Assuming reverse is called like this:

char str[] = "opal";
reverse(str);

And is assigned to memory, as an example, like this:

Memory Address:   100   101   102   103   104
Memory Value:    ['o'] ['p'] ['a'] ['l'] ['\0']

The following, regarding addresses, are true:

  1. str + 0 == &str[0] == 100
  2. str + 1 == &str[1] == 101
  3. str + 2 == &str[2] == 102
  4. str + 3 == &str[3] == 103
  5. str + 4 == &str[4] == 104

And the following, regarding values, are true:

  1. *(str + 0) == str[0] == 'o'
  2. *(str + 1) == str[1] == 'p'
  3. *(str + 2) == str[2] == 'a'
  4. *(str + 3) == str[3] == 'l'
  5. *(str + 4) == str[4] == '\0'

Regarding NULL, when a pointer is uninitialized, that is, not pointing to valid memory, it should be assigned the value of NULL, which in most cases is the address 0. Consider the following:

char *str = NULL;
reverse(str);

When the following expression is evaluated:

if(str)

It will evaluate to FALSE. Inside reverse, it should (you should fix it) immediately return because using a pointer with an address of NULL will result in undetermined behavior, such as a segmentation fault.

Assigning the address of str to end when its address is NULL and then decrementing it:

--end;

Will result in undetermined behavior.

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

It's both. I know it's confusing, but here is what's going on: in C, a pointer can be interpreted in two ways - either literally, i.e. as a pointer to a single item (char in this case) or as a pointer to the beginning of a sequence of items of the same type. In the later case the end of the sequence is to be defined. There are three ways to know where the sequence ends - by knowing the length explicitly, by knowing the ending pointer, or by placing a "terminator" item at the end of the sequence. In case of C strings, a special character '\0' called "null terminator" is used to terminate the sequence.

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

There is absolutely no difference - they both point to the same place. The placement of asterisk does not matter.

if str isn't null?

Correct

end pointer points to 'l' now

Absolutely!

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

You are comparing locations in memory, not characters they point to. This is asking for the pointers to not "cross" each other, because the two are going toward the center from both ends of the string.

tmp = o

On the first iteration, it is. On the second iteration, it points to 'p'

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

The ++str expression increments the value of the pointer, and evaluates to the value of the pointer after the increment; the *str++ expression increments the value of the pointer, and evaluates to the value of the character that was pointed to by the pointer before the increment.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top