views:

990

answers:

8

I'm preparing some slides for an introductory C class, and I'm trying to present good examples (and motivation) for using pointer arithmetic over array subscripting.

A lot of the examples I see in books are fairly equivalent. For example, many books show how to reverse the case of all values in a string, but with the exception of replacing an a[i] with a *p the code is identical.

I am looking for a good (and short) example with single-dimensional arrays where pointer arithmetic can produce significantly more elegant code. Any ideas?

+6  A: 

Getting a pointer again instead of a value:

One usually uses pointer arithmetic when they want to get a pointer again. To get a pointer while using an array index: you are 1) calculating the pointer offset, then 2) getting the value at that memory location, then 3) you have to use & to get the address again. That's more typing and less clean syntax.

Example 1: Let's say you need a pointer to the 512th byte in a buffer

char buffer[1024]
char *p = buffer + 512;

Is cleaner than:

char buffer[1024];
char *p = &buffer[512];

Example 2: More efficient strcat

char buffer[1024];
strcpy(buffer, "hello ");
strcpy(buffer + 6, "world!");

This is cleaner than:

char buffer[1024];
strcpy(buffer, "hello ");
strcpy(&buffer[6], "world!");


Using pointer arithmetic ++ as an iterator:

Incrementing pointers with ++, and decrementing with -- is useful when iterating over each element in an array of elements. It is cleaner than using a separate variable used to keep track of the offset.


Pointer subtraction:

You can use pointer subtraction with pointer arithmetic. This can be useful in some cases to get the element before the one you are pointing to. It can be done with array subscripts too, but it looks really bad and confusing. Especially to a python programmer where a negative subscript is given to index something from the end of the list.

Brian R. Bondy
But you still have the total number of variables.
Uri
You know, an even **cleaner** thing to do for the second example would be `sprintf(buffer, "%s%s", "hello ", "world!")`.
Cirno de Bergerac
@sgm, and expensive
Longpoke
+2  A: 
char *my_strcpy(const char *s, char *t) {
  char *u = t;
  while (*t++ = *s++);
  return u;
}

Why would you want to spoil such a beauty with an index? (See K&R, and how they build on up to this style.)There is a reason I used the above signature the way it is. Stop editing without asking for a clarification first. For those who think they know, look up the present signature -- you missed a few restrict qualifications.

Structure alignment testing and the offsetof macro implementation.

dirkgently
I thought about using that one, but I still feel that it worry that it won't convince the students, it still maps to a very similar code with indices.
Uri
But that's an extra variable you need not use.
dirkgently
I'm not who's editing it and why.
Uri
@Uri: I know who's editing it. Let's just get on with your question.
dirkgently
Uri, no-one said you are teh evil bro :p anyway what does offsetof and "structure alignment testing" have to do with whether using *(p + i) or p[i] ?
Johannes Schaub - litb
@litb: They are good examples of pointer arithmetic in general. I should've mentioned that. Hoped that may be of some help.
dirkgently
+1  A: 

iterating through a 2-dimensional array where the position of a datum does not really matter
if you dont use pointers, you would have to keep track of two subscripts
with pointers, you could point to the top of your array, and with a single loop, zip through the whole thing

adi92
A: 

If you were using an old compiler, or some kind of specialist embedded systems compiler, there might be slight performance differences, but most modern compilers would probably optimize these (tiny) differences out.

The following article might be something you could draw on - depends on the level of your students:

http://geeks.netindonesia.net/blogs/risman/archive/2007/06/25/Pointer-Arithmetic-and-Array-Indexing.aspx

dommer
A: 

Often the choice is just one of style - one looks or feels more natural than the other for a particular case.

There is also the argument that using indexes can cause the compiler to have to repeatedly recalculate offsets inside a loop - I'm not sure how often this is the case (other than in non-optimized builds), but I imagine it happens, but it's probably rarely a problem.

One area that I think is important in the long run (which might not apply to an introductory C class - but learn 'em early, I say) is that using pointer arithmetic applies to the idioms used in the C++ STL. If you get them to understand pointer arithmetic and use it, then when they move on to the STL, they'll have a leg up on how to properly use iterators.

Michael Burr
A: 

You're asking about C specifically, but C++ builds upon this as well:

Most pointer arithmetic naturally generalizes to the Forward Iterator concept. Walking through memory with *p++ can be used for any sequenced container (linked list, skip list, vector, binary tree, B tree, etc), thanks to operator overloading.

Tom
A: 

Something fun I hope you never have to deal with: pointers can alias, whereas arrays cannot. Aliasing can cause all sorts of non-ideal code generation, the most common of which is using a pointer as an out parameter to another function. Basically, the compiler cannot assume that the pointer used by the function doesn't alias itself or anything else in that stack frame, so it has to reload the value from the pointer every time it's used. Or rather, to be safe it does.

MSN
A: 

Pointer arithmetic may look fancy and "hackerish", but I have never encountered a case it was FASTER than the standard indexing. Just the opposite, I often encountered cases when it slowed the code down by a large factor.

For example, typical sequential looping through an array with a pointer may be less efficient than looping with a classic index on a modern processors, that support SSE extensions. Pointer arithmetic in a loop sufficiently blocks compilers from performing loop vectorization, which can yield typical 2x-4x performance boost. Additionally, using pointers instead of simple integer variables may result in needless memory store operations due to pointer aliasing.

So, generally pointer arithmetic instead of standard indexed access should NEVER be recommended.