views:

812

answers:

14

An example of this would be:

char str[] = "Hello";
int strLength = strlen(str);

for (   char * pc = str;
        pc < str + strLength;
        pc++)
{
    *pc += 2;
}

Edit: Accounted for write-protected memory issue.

A: 

Its not a bad idea in and of itself, but it is unusual. If you expect other people to be working on your code, I'd use the int i version just to reduce confusion.

Either way you've got to worry about the same problems.

Kevin Montrose
dmckee
Kevin Montrose
xcramps
It certainly is a great book, but just because you _can_ do something doesn't mean you should. Using `*ptr` in a conditional clause (looking for a null terminator, generally) is a great example of something that works just fine but will confuse every third programmer (generously assuming 66% of working programmers understand pointers **AND** strings) and thus should be avoided in codebases where there are more than a few principle developers.
Kevin Montrose
Using pointers in loops and conditionals is pretty idiomatic C; based on my experience, I'd be surprised if it confused *that* many programmers.
John Bode
I would love to work with the programmers you do, to have formed that opinion. Perhaps I'm being a _little_ too paranoid, but I've been burned by handing "obvious" code off to other developers before.
Kevin Montrose
66% of working programmers is a well qualified statement. A GOOD programmer WILL understand pointer. Any student who actually GROKed data structures class should. But alas not all do, and they still go on to graduate. That's why I hate the notion of CS departments dumbing down classes to use Python or some other language that doesn't require you to understand pointers for data structures. CS is suppose to be about understanding program efficiency, Software Engineering is more about programmer efficiency.
NoMoreZealots
JavaSchools, Pete. What can you do?
Hooked
A: 

It is faster than using higher level objects but as others warn be careful with it. You might have to do it due to the constraints that you are programming to but it is unconventional.

The scope of the variable being in the loop may not be portable as well.

ojblass
Um, the question compared pointer access with indexed access. IYO, does the latter qualify as "higher level"? If so, do you really claim pointer access is faster than index access? If not, what do you mean then?
sbi
+7  A: 

My one issue is that you'd have a lot of fun if you leave out the * in *pc in the for loop. Whoops? More generally, it is slightly harder to tell the difference between reassigning the pointer and modifying the value.

However, (though I don't have it handy), Stroustroup himself endorses(see edit) pointer iteration in the C++ Programming Language book. Basically, you can have a pretty terse implementation of string comparison between two char arrays using pointer arithmetic.

In short, I would recommend using such pointers in a "read only" fashion. If you need to write to the array, I would use the more traditional i.

This is, of course, all my personal preference.

Edit: Stroustroup doesn't endorse pointer iteration OVER integer -- he simply uses it at one point in the book, so my reasoning is that he doesn't think its anethema to good practice.

Agor
STL iterators are simply pointers with a more annoying syntax. Personally I like for(i=0 ....
Martin Beckett
They are not simply pointers. That's a very naive way to think about them. Yes, in simple cases they are glorified pointers, but in other cases they certainly are not. Not to mention you can be more consistent with iterators, and use `std::algorithms` with iterators.
GMan
Why don't you like to use pointers if you're performing read/write operations on an array?The problem I have with using them for C-arrays is you often don't have access to the 'end' pointer, you want to be writing code like:for (T *it = arr; it != arrEnd; ++it) doSomething(it);but the condition ends up being something like:it != (arr + len)which is a bit ugly, or*it != '\0'which seems OK to me for strings.
David Claridge
The real root of this preference is simply that its "easy" to skip over the *, or imagine a * that isn't there, and so it takes more effort to read the code correctly. Basically, it is to help maintain the separation between pointer and array. If I'm thinking that "pc is an array", then I'd expect to see element access done through pc[x], rather than *(pc + x). Obviously, a big shiny aspect of C++ and C is that arrays and pointers are in many ways equivalent, and that certainly has advantages. Here, I think, it is just confusing. Using the pointer for read-only (conceptually) mitigates that.
Agor
+2  A: 

It can be confusing to people not used to working with pointers. But there is simply no point in writing

for (int i=0; a[i]!=NULL; ++i){
    a[i] = ...;
}

instead of

for (aptr p=a; p!=NULL; ++i){
    *p = ...;
}

Use the counter when they are equivalent and a pointer when it makes sense.

dmckee
I'm going to claim that that proves my point. Yeah, that's it. Its not that I'm a dolt or anything.
dmckee
+1  A: 

For C++: It's not a bad idea at all. In C++ you can use pointers similar to the iterators of the standard library. You can even use the standard library algorithms, such as std::copy, with pointers. It's also feasible to implement std::vector using pointers as iterators. Therefore I prefer iterating using pointers instead of indexes.

Malte Clasen
+8  A: 

It's ALWAYS a bad idea to use a construct that you don't fully understand. This extends to the people who will have to read your code after you... (I think this is a corollary to the "Don't be a clever programmer" rule)

In this case, if you DO understand, and are fully comfortable with the construct, then there's nothing inherently wrong with it... But usually, if you have to ask if it's a bad idea, then you're not fully comfortable with it...

Brian Postow
Not bad advice at all. But I'd add that if you are working in c, know about pointer is not optional. That is a little less pressing in c++, but still...
dmckee
Indeed, being clever is bad, but being a good programmer? You shouldn't dumb down code because some one else who needs to learn can't read it.
GMan
Fair enough. But isn't the point of the question to become a programmer who does fully understand this construct?
Brooks Moses
I think thats quite an overstatement :P
Stanislav Palatnik
"It's ALWAYS a bad idea to use a construct that you don't fully understand. "If your aim is to to never learn.
smcameron
Fair enough... in a past life I was a theorist, so I tend to try to understand things fully in the abstract before I actually use them. I understand that most people don't work this way...
Brian Postow
@Brian: Few people learn things in the abstract and then are comfortable doing them. Most of us will have to make things badly in order to learn to make them well.
David Thornley
+3  A: 

It is pretty much the idea behind STL iterators, so no, it's not a bad idea.

A canonical loop working on iterators looks something like this:

for (iter cur = begin(); cur != end(); ++cur)

where iter might be a pointer type, or might be some other iterator. It is basically how all the standard library algorithms are implemented.

However, a better question might be what you're trying to achieve with it. The C++ standard library does it because it enables a similar syntax for iterating over any kind of sequence, not just arrays or other containers which define operator[].

It better expresses your intent, in some cases. Sometimes, you don't care about the loop counter i, so why should it be there?

But in other cases, a plain old for loop, where you have access to the counter variable, makes more sense. Do what best expresses your intent.

jalf
+1 clearly since STL, a pointer is a form of iterator, and an iterator is a Good Thing.
Daniel Earwicker
A: 

Have a look at the C bible, a.k.a. K&R C (sanitised Amazon link) as they have a discussion about the advantages of both techniques.

Either way, "there be dragons ahead, arr!" so tread very carefully as the road of good pointer arithmetic intentions is paved with the abundant corpses of buffer overflow exploit victims! (-:

In fact, for an excellent discussion and a "wander out on to the thin ice of advanced pointer manipulation" (his term), have a look at Andy Koenig's excellent book "C Traps and Pitfalls" (sanitised Amazon link)

Edit: One thing I forgot to mention, is that I tend to prefer the usual "for (int i = 0; ..) style purely because it is such an ingrained idiom that anyone can see what you're doing with a quick glance. Using pointer arithmetic requires a bit more of a deeper look.

HTH

Rob Wells
+4  A: 

No, it's not a bad idea, except that you messed it up.

For one, you're writing into a string literal. That's undefined behavior. (It crashes on Windows.) Had you written const char* str = "Hello!" the compiler would have barked at you. Unfortunately there's a (in C++ deprecated, but still allowed) conversion from a string literal to a non-const char* which allows your code to compile. However, what you want is an array which you can write into (and which is pre-initialized). For that use char str[] = "Hello!".

The other, minor, mistake is, that you loop through the string twice: strlen runs along the characters until it finds a '\0', and then you do the same again. It would be better if you checked for that '\0' yourself and avoid the call to strlen altogether.

Here's a fixed version of your loop:

char str[] = "Hello!";

for (char * pc = str; *pc != '\0'; pc++)
{
    *pc += 2;
}
sbi
A: 

Sometimes incrementing pointer in a loop looks pretty natural. Take a look at the following code that initialize DirectX texture from GDI+ bitmap:

boost::uint8_t* pDest = static_cast<boost::uint8_t*>(d3dlr.pBits);
const boost::uint8_t* pSrc = static_cast<const boost::uint8_t*>(bitmap_data.Scan0);
for ( UINT i = 0; i < bmp_height; ++i, pSrc += bitmap_data.Stride, pDest += d3dlr.Pitch ) 
    memcpy(pDest, pSrc, bmp_width * BPP);

Here were used two pointers. Each pointer has its own incrementation. I believe that using additional int in this loop will result in deterioration of code readability.

Kirill V. Lyadvinsky
A: 

Generaly I stick to this claim by Bartosz Milewski in his great freely avaliable C++ book C++ In Action.

Don’t use pointers unless there is no other way. I leave this kind of optimisations to compilers. It is so simple and common usage that is verry unlikely that compilers can not figure out how to optimise this kind of code.

One last thing from his book:

If your compiler is unable to optimize the human readable, maintainable version of the algorithm, and you have to double as a human compiler-- buy a new compiler! Nobody can afford human compilers any more. So, have mercy on yourself and your fellow programmers who will have to look at your code.

ralu
"Don't use pointers unless there is no other way." You mean within the context of this question right? Many things CAN be done with out pointers, but that doesn't always mean it's any clearer.
NoMoreZealots
I dont get it what write protected memory issue mean. Should not first line be -> const char str[] = "Hello"; ? His implementation using pointer arithmetic is slow becuse it iterates twice over the string. First time in strlen() and second time in for loop. About Milewski's qoute I think that correct quote shoud be "Don't use pointer arithmetics unless there is no other way." Of course passing by reference and pointers on functions are ussualy nice and clean solution, I just never use pointer arithmetic, becuse you can always write []
ralu
A: 

I agree with ralu (and Milewski). Many years ago compilers were dumb and would literal-mindedly recalculate the array offset each time (I'm told), so that it was more efficient to use and bump a ptr, yourself. However, they got smarter a few years later (as Milewski says) and could convert the [i] pattern to ptr bumping themselves. In addition, they could use the [i] pattern to unroll the loop a bit, but at that time were not smart enough to see through a programmer's bump-your-own-ptr trick. Now I don't know whether compilers are smart enough nowadays to unroll a loop with hand-rolled simple pointer bumping, possibly so; but I took from that example that the compiler could do cleverer things than had occurred to me, and that the best I could do was make my intent clear and get out of its way. Plus, I think it's easier for another programmer to understand indexes, and that trumps a lot things.

JDonner
A: 

I do not find it problematic to use a pointer as the loop variable. However, I have a few problems with your example:

char str[] = "Hello";
int strLength = strlen(str);

for (   char * pc = str;
        pc < str + strLength;
        pc++)
{
    *pc += 2;
}

strlen iterates over the whole string to figure out the length of the string. Even for a simple example such as this, there is no need for that kind of waste.

This example can be more clearly and succinctly written as:

char str[] = "Hello";

for (char *pc = str; *pc; ++pc) {
    *pc += 2;
}

This version is more efficient and easier to understand. It also illustrates there is nothing wrong in principle with using a pointer as the loop variable.

Sinan Ünür