0

Regarding pointers (in structs for this case), I understand that if 'a' were a struct and 'b' declared within the struct, then we can access the data through:

a->b

And now, I've recently found out C has a lot of shortcuts regarding pointers, one of which would be the arrow operator as above.

I've seen 'a->b' being written as '[a] + b', such that:

a->b <=> [a] + b //meaning that they are interchangeable

However, I am having trouble making sense of this what '[a] + b' actually means and would really appreciate someone laying the details out for me (or perhaps I misread and the above is nonsense !). Many thanks in advance!

7
  • "I've seen 'a->b' being written as '[a] + b'..." Where'd you see that? That can't possibly be valid C syntax. The array subscript [] operator requires two arguments because the expression p[i] is equivalent to *(p+i). I can't see how [a] alone is valid C. Commented Mar 16, 2011 at 7:04
  • where did you see [a] + b ? can you provide some example? Commented Mar 16, 2011 at 7:05
  • My teacher's study guide for our midterm tomorrow! >< If this is all silliness, perhaps he made a typo? I wasn't sure if there existed a 'square-brackets operator,' because it caught me off guard. Commented Mar 16, 2011 at 7:09
  • @honeywind: The [] operator certainly does exist, but the example you provided is not how they are used. Like I said, the [] operator is for accessing elements of an array, not members of a structure. That's what the -> operator is for (so that a->b is equivalent to (*a).b). You should certainly ask your teacher about this unusual "operator". Commented Mar 16, 2011 at 7:09
  • @In silico: Phew, thought I missed something really basic; must be a typo. Sorry for the silly question! I'm still a bit new to C and I appreciate you helping me out and the additional 'shortcut' information. ^^ I'll definitely ask him! Thank you. Commented Mar 16, 2011 at 7:13

2 Answers 2

3

In the C language, [a] + b means nothing. It is a syntax error. Your book probably uses that notation to explain something, but out of context it means nothing. However, it is similar-looking enough to several other pointer shortcuts as to cause confusion. So to dispel that confusion, here are all the pointer shortcuts I can think of:

  • a->b is a synonym for (*a).b, that is, accessing a member of a pointer to a struct type.
  • a[b] is a synonym for *(a + b), that is, accessing an array element by performing pointer arithmetic to a specified offset.
    • Note that, due to the above, a[b] is synonymous with b[a], because a[b] <=> *(a + b) <=> *(b + a) <=> b[a]. Evil tricksters will do things like 0[x] or 5["string"] to confuse you. Fear not, for now you know the answer.
  • *&a is a synonym for a, that is, dereferencing an address. It creates a pointer, then dereferences it immediately, yielding the original object.
    • Note that &a[b] translates to &*(a + b) which translates to a + b. Both &a[b] and a + b create pointers to an array element in the same way. Which way is the "best" way depends on personal preference, place of employment, and phase of the moon.
    • Note that &*a is not the same as *&a. The latter creates a pointer, then dereferences it, yielding the original object. The former assumes a is a pointer, dereferences it, then takes the address of the result, yielding the original pointer. &*a is mandated by the standard not to dereference the pointer and can be safely used on a NULL pointer.
  • *(type *)&a is an evil hack that you may see from time to time. It takes the address of a, casts the pointer to a pointer to a type, and dereferences it. This is usually unspecified behavior*, but in practice will cause the bits of object a to be reinterpreted as a type object. This allows you to get at e.g. the bitwise representation of floats or other objects. There are perhaps better ways to accomplish that goal, but if you ever stumble across this line of code, you'll at least know what the authors intended by it.

I'll add more if I think of them.

*I say unspecified because, if you did int i = -1; printf("%u\n", *(unsigned int)&i);, the C standard doesn't mandate whether this would print the value UINT_MAX (for two's complement), UINT_MAX - 1 (for one's complement) or (unsigned int)INT_MAX + 2 (for sign-and-magnitude).

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

7 Comments

Wow this is beautiful. I will definitely be coming back to this post! (Why is C so evil? :P)
C (like all languages) is only as evil as you are.
@Chris Lutz Regarding possible undefined behaviour of pointer casts, I believe you are wrong. I cannot find anything in the standard labelling such casts as undefined or unspecified behaviour, they seem to be perfectly valid. The only related undefined behaviour is casts that results in incorrect alignment. This is all addressed in the standard below 6.3.2.3.
ISO 9899:1999 6.3.2.3.7 - Conversion between two pointer types produces a result that is incorrectly aligned (A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned57) for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.
@Lundin - Technically, that is sufficient, as the standard makes no specifications about the sizes or alignments of types (aside from the integer and floating-point hierarchies), so both short s; *(int *)&s; or int i; *(long *)&i; are at risk of alignment issues. You could preface all such casts with checking that the sizeofs (or alignof using #define alignof(t) offsetof(struct {char c;t x;}, x)) are equal, but that gets annoying quickly. However, I thought the UB was in the dereference. Perhaps I was wrong.
|
0

As already pointed out, [a]+b isn't valid C. Maybe he meant

a->b <=> a[0].b

3 Comments

Or based off of Chris' post, 0[a].b (is that valid?) Wait till my Java friends hear this. :P
It's not valid because 0 is not a pointer. ((void*)0) is a pointer but indexing it is invalid because void has no size. The closest you may get would be (provided that sizeof(char)==1 and sizeof(int)>=sizeof(a)): ((char*)0)[(int)a].b (I'm not really sure about the cast syntax, but you get the idea).
You're incorrect. The standard requires that, in the expression a[b], one of a and b is a pointer, and the other an integer. It doesn't say which one must be which.

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.