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.
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.
It's not always a bad idea, but you need to be careful. Take a look at this article.
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.
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.
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.
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.
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.
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...
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.
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
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;
}
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.
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.
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.
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.