c# - would - ¿Qué es posible en un bucle for?
custom attributes c# (8)
- Java y C # comparten esta misma sintaxis
- La sintaxis probablemente proviene de C / C ++, que es la "raíz" de Java & C #
- Sí, también puede tener cero inicializadores y condiciones finales para su bucle for.
- Si es o no es una mala práctica realmente depende de cómo se usa. Puede crear código bastante críptico usando esta técnica, sin embargo, no significa que cuando se usa correctamente es perfectamente aceptable.
- ¡Lo dudo!
Así que hoy fui a una entrevista y una de las preguntas fue la siguiente (contexto de C #).
//Print the output for the following code:
for (int i = 10, j = 0; j <= 10; j++, i--)
{
if (i > j)
Console.WriteLine(j.ToString());
}
Nunca había visto tal construcción antes y, al haber preguntado a mis colegas, 4 de 5 en mi lugar de trabajo tampoco sabían (quizás más una reflexión sobre nosotros, pero estoy divagando) . Usando un poco de lógica básica, pude responder la pregunta correctamente, pero este conocimiento ha alterado radicalmente mi comprensión de cómo se pueden estructurar los bucles.
Así que supongo que mi pregunta se reduce a esto.
- ¿Todos los lenguajes basados en sintaxis C implementan esta funcionalidad? IE: C, C ++, Java, Javascript, etc.
- ¿De dónde proviene esta sintaxis?
- ¿Existen otras estructuras "no conocidas" que pueda tomar un bucle for?
- ¿Se considera una mala práctica escribir código como el anterior, dada la dificultad de leer?
- ¿Hay buenos ejemplos del mundo real donde se requiera tal estructura?
Java soporta esto para la estructura. En otros lenguajes como C, puede tener cualquier expresión en lugar de una cláusula de condición. Esta cláusula no tiene que estar relacionada y podría usar diferentes variables.
for({declaration-clause}; {condition-clause}; {expression-clause})
La sintaxis es solo una extensión de la declaración y las notaciones de expresión en C.
int i = 10, j = 0; // a declaration j++, i--; // an expression.
Demasiados para mencionar.
- Puede ser una mala práctica si no puede determinar qué significa el código. En tu caso, pudiste resolverlo incluso si no lo hubieras escrito de esa manera.
- Nunca se requiere un bucle for. Siempre se puede reemplazar con un bucle while, no.
De acuerdo con mi experiencia y mi investigación, este tipo de "construcción de condición" se ve con mucha frecuencia en el procesamiento de imágenes, digamos (en realidad, digamos) que necesita comparar píxeles entre dos imágenes en (por ejemplo, nuevamente) direcciones opuestas. O incluso atravesar vecinos en direcciones opp, también. Otro ejemplo, bajo este tipo de ''construcción de condición'', cuando necesita convertir un bmp de 32 bits a 24 bits o viceversa. (solo que el incremento sería un poco difuso como i = i + 4, j = j + 3).
En C y Java for
bucles, puede especificar un número ilimitado (o cero) de inicializadores separados por comas (del mismo tipo de datos) y acciones de fin de bucle.
La sección de inicialización es en realidad solo una sentencia java; Las definiciones de variables java se pueden agrupar si son del mismo tipo, es decir:
int i = 0;
int j = 0;
es equivalente a:
int i = 0, j = 0;
Puede hacer lo que quiera en la sección de fin de bucle: cualquier número de declaraciones separadas por comas.
Desde Java 5, también existe la sintaxis de foreach
, por ejemplo:
List<String> list;
for (String element : list) {
// do something with the variable element
}
La sintaxis funciona con tipos Iterable
, que incluyen matrices y colecciones.
En el contexto de C # (que solo se considerará mi respuesta), no hay un operador de coma como en C ++ y C, por lo que, técnicamente, hacer referencia al operador de coma no es correcto para C #.
Pero el C # for
declaración todavía estaba diseñado para permitir construcciones que la gente ya conocía de C ++.
Las reglas precisas se encuentran en la sección La declaración for
en la Especificación de lenguaje C # . Vemos que el tercer y último "componente" en una declaración for (;;)
se define como una lista -expresión-declaración , y una lista-expresión-declaración se define, de manera recursiva, como una lista de expresiones de declaración separadas por el personaje ,
(coma).
Así que eso explica la parte j++, i--
.
También vemos que la primera parte de for (;;)
puede ser una local-variable-declaration o una lista de expresiones de declaración . El primero puede contener una coma también. La declaración int i = 10, j = 0;
también se permite como una declaración independiente (es decir, no está dentro), y debe interpretarse como una declaración de variable local .
En respuesta a 5, un uso común es algo como esto (en C):
for (size_t pos = 0, end = strlen(something); pos < end; ++pos) {
if isspace((unsigned)(something[pos])) {
puts("contains whitespace");
break;
}
}
en lugar de:
for (size_t pos = 0; pos < strlen(something); ++pos) { ... }
strlen
podría ser cualquier operación que sea costosa en relación con el bucle, de modo que tenga sentido levantarlo. Para strlen
en particular, tal vez el optimizador pueda hacerlo automáticamente, pero en general, si el compilador no sabe lo que hace la llamada, y lo pone en la condición de bucle, tiene que evaluarlo cada vez que lo haga porque no lo sabe. si va a cambiar
Por supuesto, en lugar de eso podrías escribir esto:
const size_t end = strlen(something);
for (size_t pos = 0; pos < end; ++pos) { ... }
Por lo tanto, ciertamente no hay una necesidad estricta de que la variable adicional se defina en la declaración for, y de todas formas se puede decir que hay una pequeña ventaja en hacer const (o final) final, que se pierde al definir pos
y end
juntos. Algunas personas prefieren las "variables de bucle" (en este caso, incluyendo una "constante de bucle") a todas definidas en la declaración for, ya que "pertenecen" a ella.
Además, antes de que alguien lo señale, en mi ejemplo de C no necesitas indexar nada:
for (const char *ptr = something; *ptr; ++ptr) {
if isspace((unsigned)*ptr) { ... }
}
pero podemos fingir que tenemos una tarea en la que vamos a iterar utilizando un punto final calculado ...
La salida es: 0 9 8 7 6
- Los lenguajes basados casi en sintaxis C implementan esta funcionalidad.
- ¿De dónde proviene esta sintaxis de c.
- Una parte, dos partes, tres partes, todo puede desaparecer. No tiene ninguna parte, el bucle puede funcionar correctamente.
- Es una mala práctica.
- No lo sé.
for (statement1; statement2; statement3)
{
/* body */
}
(1) Primero se ejecuta la statement1
.
(2) Se ejecuta la siguiente statement2
.
(3) Si la evaluación de la statement2
es verdadera, entonces se ejecuta el cuerpo.
(4) Entonces se ejecuta la statement3
.
(5) Repita desde el paso (2)
| +<-----------------+
| | ^
V V |
for ( (s1); -------->(s2 true? | false?); (s3) )
{ | | ^
| | |
| | |
V | |
(body)-----|--------->+
} |
|
V
(come out)
La estructura que ha mostrado es la misma estructura normal que la anterior. La statement n
podría ser cualquier declaración. En su ejemplo, ha separado por operadores de coma en la statement1
y la statement3
. Puede separar cualquier número de declaraciones por operadores de coma.
Generalmente, los bucles se usan con la statement1
con inicialización, ya que se ejecuta solo una vez. La statement2
se usa para la verificación de la condición de terminación del bucle, porque el valor de evaluación de esta sentencia se usa para decidir si se ingresa el cuerpo de ruptura. Y la statement3
se utiliza para actualizar la variable de terminación de bucle, ya que se ejecuta después del cuerpo. Pero en general podrían ser utilizados de cualquier manera.
La primera statement1
es i=10, j=0;
Esto inicializa las variables. El siguiente en la statement2
es j <= 10
si esto es cierto, entonces se ejecuta el cuerpo. Después de que se ejecuta el cuerpo, se ejecuta la statement3
que es i--,j++
. El bucle iterará 11
veces de 0
a 10
. Pero se imprimirá 5
veces, ya que en un punto i
y j
se volverán iguales y if (i > j)
evaluará falso.
EDITAR Aquí hay un ejemplo en el que se puede usar, no es muy práctico sino un uso de muestra, para buscar una cadena de palíndromo.
int i, j, n, flag;
char str[128];
printf ("/nEnter string: ");
scanf ("%s", &str);
n = strlen (str);
for (flag=1, i=n-1, j=0; j<n/2; j++, i--)
{
if (str[i] != str[j])
{
flag = 0;
break;
}
}
if (flag)
printf ("/n/"%s/" is a palindrome");
else
printf ("/n/"%s/" is not a palindrome");
Siempre debemos tratar de escribir un código que sea fácil de leer y que no cree confusión. Esto ayuda al escritor del código así como a otros que leen el código.