I thought one could declare several variables in a for
loop:
for (int i = 0, char* ptr = bam; i < 10; i++) { ... }
But I just
Try this:
int i;
char* ptr;
for (i = 0, ptr = bam; i < 10; i++) { ... }
It's true that you can't simultaneously declare and initialize declarators of different types. But this isn't specific to for loops. You'll get an error if you do:
int i = 0, char *ptr = bam;
too. The first clause of a for loop can be (C99 §6.8.5.3) "a declaration" or a "void expression". Note that you can do:
int i = 0, *j = NULL;
for(int i = 0, *j = NULL;;){}
because i
and *j
are both of type int
. The exact syntax for a declaration is given in §6.7
According to http://linuxsoftware.co.nz/cppgrammar.html#for-init-statement you can get only simple declaration or an expression (which is not permitted to contain declaration) in the for-init statement. That means the answer is no (if I analyzed the BNF correctly :) )
You can also do:
for (int i = 0; i < 10; i++) {
static char* ptr = bam;
}
I think the languages they teach you kids these days are meant to handcuff you and rot your brain so you just be quiet and put the lego blocks together in the very limited form in which they are meant to snap together so you build mediocre stuff. The beauty of C is that you can follow the rules, and in a clever way, to get what you want. Here is how you write this loop with extra initialzers. Here is a working example that shows you how to bridge an extended loop onto a first. You use the first to pirate its variables and they remain in scope. You use a dummy variable to make the outer loop run once. A smart compiler will note the fact and nuke the loop with the loop unroller. So for you it is just benefit. The second array then uses some variables from the first declaration and the second declaration and runs to completion. It is a trivial example just meant you to be able to understand how to do it without the heavy handed move of throwing in some scoping. Because this technique can be used with macros when written like this in order to create beautiful next-generation like structure enumeration, like "for value in array do", of which I have many.
#include "stdio.h"
int
main(int argc, char **argv)
{
const int max=7;
const char *array[7] = {
"hello","you","kids","who","don't","know","malloc\n"
};
for(int i=0,count=max,$=1;$;$=0)
for(const char **p=array;count<max;i++)
{
printf("%s ",p[i]);
}
}
There is nothing missing here. This technique of for loop joining with a one shot for loop has been used to embed in a call to get an enumerator for this hash object, and start the enumeration, to get the values extracted for the key and value, and also by convenience create them as void pointers for the user, he just has to name them. Then they are filled, and the enumeration will continue until all keys and values are done. If the user breaks in the iteration the whole cascade of oneshot forloops will fall apart as we'd want because they're probably not even there since they were constructed with simple const ops that the compiler can see will unroll the loop. So basically it lets you extend the syntax to do things like this with no penalty.
But you need to know a bit of C and at least have your head out of the robot box that the schools are putting them in these days with these toy languages.
You can (but generally shouldn't) use a local struct type.
for ( struct { int i; char* ptr; } loopy = { 0, bam };
loopy.i < 10 && * loopy.ptr != 0;
++ loopy.i, ++ loopy.ptr )
{ ... }
Since C++11, you can initialize the individual parts more elegantly, as long as they don't depend on a local variable:
for ( struct { int i = 0; std::string status; } loop;
loop.status != "done"; ++ loop.i )
{ ... }
This is just almost readable enough to really use.
C++17 addresses the problem with structured bindings:
for ( auto [ i, status ] = std::tuple{ 0, ""s }; status != "done"; ++ i )