Pregunta

Me gustaría incrementar dos variables en una condición de bucle for en lugar de una.

Entonces algo como:

for (int i = 0; i != 5; ++i and ++j) 
    do_something(i, j);

¿Cuál es la sintaxis para esto?

¿Fue útil?

Solución

Un idioma común es utilizar el operador de coma que evalúa ambos operandos y devuelve el segundo operando Por lo tanto:

for(int i = 0; i != 5; ++i,++j) 
    do_something(i,j);

¿Pero es realmente un operador de coma?

Ahora que lo había escrito, un comentarista sugirió que en realidad era un azúcar sintáctico especial en la declaración for, y no un operador de coma en absoluto. Lo comprobé en GCC de la siguiente manera:

int i=0;
int a=5;
int x=0;

for(i; i<5; x=i++,a++){
    printf("i=%d a=%d x=%d\n",i,a,x);
}

Esperaba que x recogiera el valor original de a, por lo que debería haber mostrado 5,6,7 .. para x. Lo que obtuve fue esto

i=0 a=5 x=0
i=1 a=6 x=0
i=2 a=7 x=1
i=3 a=8 x=2
i=4 a=9 x=3

Sin embargo, si coloqué entre corchetes la expresión para obligar al analizador a ver realmente un operador de coma, obtengo esto

int main(){
    int i=0;
    int a=5;
    int x=0;

    for(i=0; i<5; x=(i++,a++)){
        printf("i=%d a=%d x=%d\n",i,a,x);
    }
}

i=0 a=5 x=0
i=1 a=6 x=5
i=2 a=7 x=6
i=3 a=8 x=7
i=4 a=9 x=8

Inicialmente pensé que esto mostraba que no se estaba comportando como un operador de coma, pero resulta que esto es simplemente un problema de precedencia: el operador de coma tiene el precedencia más baja posible , por lo que la expresión x = i ++, a ++ se analiza efectivamente como (x = i ++), a ++

Gracias por todos los comentarios, fue una experiencia de aprendizaje interesante, ¡y he estado usando C durante muchos años!

Otros consejos

Prueba esto

for(int i = 0; i != 5; ++i, ++j)
    do_something(i,j);

¡Intenta no hacerlo!

De http://www.research.att.com/~bs/JSF-AV-rules.pdf :

  

Norma AV 199

  La expresión de incremento en un bucle for no realizará otra acción que no sea cambiar un solo   parámetro de bucle al siguiente valor para el bucle.

     

Justificación: legibilidad.

for (int i = 0; i != 5; ++i, ++j) 
    do_something(i, j);

Vine aquí para recordarme cómo codificar un segundo índice en la cláusula de incremento de un bucle FOR, que sabía que se podía hacer principalmente al observarlo en una muestra que incorporé a otro proyecto, que está escrito en C ++.

Hoy, estoy trabajando en C #, pero estaba seguro de que obedecería las mismas reglas a este respecto, ya que la declaración FOR es una de las estructuras de control más antiguas en toda la programación. Afortunadamente, recientemente pasé varios días documentando con precisión el comportamiento de un bucle FOR en uno de mis programas C más antiguos, y rápidamente me di cuenta de que esos estudios contenían lecciones que se aplicaban al problema C # de hoy, en particular al comportamiento de la segunda variable de índice. .

Para los incautos, a continuación se presenta un resumen de mis observaciones. Todo lo que vi suceder hoy, al observar cuidadosamente las variables en la ventana Locales, confirmó mi expectativa de que una declaración FOR # C se comporta exactamente como una declaración FOR C o C ++.

  1. La primera vez que se ejecuta un bucle FOR, se omite la cláusula de incremento (la tercera de sus tres). En Visual C y C ++, el incremento se genera como tres instrucciones de máquina en el medio del bloque que implementa el bucle, de modo que el paso inicial ejecuta el código de inicialización una sola vez, luego salta sobre el bloque de incremento para ejecutar la prueba de terminación. Esto implementa la característica de que un bucle FOR se ejecuta cero o más veces, dependiendo del estado de sus variables de índice y límite.
  2. Si se ejecuta el cuerpo del bucle, su última instrucción es un salto a la primera de las tres instrucciones de incremento que se omitieron en la primera iteración. Después de que estos se ejecutan, el control cae naturalmente en el código de prueba de límite que implementa la cláusula intermedia. El resultado de esa prueba determina si el cuerpo del bucle FOR se ejecuta o si el control se transfiere a la siguiente instrucción más allá del salto en la parte inferior de su alcance.
  3. Dado que el control se transfiere desde la parte inferior del bloque de bucle FOR al bloque de incremento, la variable de índice se incrementa antes de que se ejecute la prueba. Este comportamiento no solo explica por qué debe codificar sus cláusulas límite de la manera que aprendió, sino que afecta cualquier incremento secundario que agregue, a través del operador de coma, porque se convierte en parte de la tercera cláusula. Por lo tanto, no se cambia en la primera iteración, pero sí en la última iteración, que nunca ejecuta el cuerpo.

Si cualquiera de sus variables de índice permanece dentro del alcance cuando finaliza el ciclo, su valor será uno más alto que el umbral que detiene el ciclo, en el caso de la variable de índice real. Del mismo modo, si, por ejemplo, la segunda variable se inicializa a cero antes de ingresar el bucle, su valor al final será el recuento de iteraciones, suponiendo que es un incremento (++), no un decremento, y que nada en el cuerpo del bucle cambia su valor.

Estoy de acuerdo con squelart. Incrementar dos variables es propenso a errores, especialmente si solo prueba una de ellas.

Esta es la forma legible de hacer esto:

for(int i = 0; i < 5; ++i) {
    ++j;
    do_something(i, j);
}
Los bucles

For están destinados a casos en los que su bucle se ejecuta en una variable creciente / decreciente. Para cualquier otra variable, cámbiela en el ciclo.

Si necesita que j esté vinculado a i , ¿por qué no dejar la variable original como está y agregar i ?

for(int i = 0; i < 5; ++i) {
    do_something(i,a+i);
}

Si su lógica es más compleja (por ejemplo, necesita monitorear más de una variable), usaría un bucle while .

int main(){
    int i=0;
    int a=0;
    for(i;i<5;i++,a++){
        printf("%d %d\n",a,i);
    } 
}

Usar matemáticas. Si las dos operaciones dependen matemáticamente de la iteración del bucle, ¿por qué no hacer las matemáticas?

int i, j;//That have some meaningful values in them?
for( int counter = 0; counter < count_max; ++counter )
    do_something (counter+i, counter+j);

O, más específicamente refiriéndose al ejemplo del OP:

for(int i = 0; i != 5; ++i)
    do_something(i, j+i);

Especialmente si estás pasando a una función por valor, entonces deberías obtener algo que haga exactamente lo que quieres.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top