¿Dónde puedes y no puedes declarar nuevas variables en C?

Escuché (probablemente de un docente) que uno debería declarar todas las variables sobre el progtwig / función, y que declarar nuevas entre las declaraciones podría causar problemas.

Pero luego estaba leyendo K & R y me encontré con esta frase: “Las declaraciones de variables (incluidas las inicializaciones) pueden seguir al paréntesis izquierdo que introduce cualquier enunciado compuesto, no solo el que comienza una función”. Él sigue con un ejemplo:

if (n > 0){ int i; for (i=0;i<n;i++) ... } 

Jugué un poco con el concepto, y funciona incluso con arreglos. Por ejemplo:

 int main(){ int x = 0 ; while (x5){ int y[x]; y[0] = 10; printf("%d %d\n",y[0],y[4]); } x++; } } 

Entonces, cuando exactamente no estoy autorizado a declarar las variables? Por ejemplo, ¿qué pasa si mi statement de variable no es correcta después de la llave de apertura? Como aquí:

 int main(){ int x = 10; x++; printf("%d\n",x); int z = 6; printf("%d\n",z); } 

¿Podría esto causar problemas dependiendo del progtwig / máquina?

También a menudo escucho que poner variables en la parte superior de la función es la mejor manera de hacer las cosas, pero estoy totalmente en desacuerdo. Prefiero limitar las variables al scope más pequeño posible para que tengan menos posibilidades de ser mal utilizadas, así que tengo menos cosas que llenan mi espacio mental en cada línea del progtwig.

Si bien todas las versiones de C permiten el scope del bloque léxico, donde puede declarar las variables depende de la versión del estándar C al que se dirige:

C99 en adelante o C ++

Los comstackdores modernos de C, como gcc y clang, son compatibles con los estándares C99 y C11 , que le permiten declarar una variable en cualquier lugar donde pueda ir una statement. El scope de la variable comienza desde el punto de la statement hasta el final del bloque (siguiente corchete de cierre).

 if( x < 10 ){ printf("%d", 17); // z is not in scope in this line int z = 42; printf("%d", z); // z is in scope in this line } 

También puede declarar variables dentro de los inicializadores de bucle. La variable solo existirá solo dentro del bucle.

 for(int i=0; i<10; i++){ printf("%d", i); } 

ANSI C (C90)

Si se dirige al estándar anterior ANSI C , entonces está limitado a declarar variables inmediatamente después de un paréntesis inicial 1 .

Sin embargo, esto no significa que tenga que declarar todas sus variables en la parte superior de sus funciones. En C puede colocar un bloque delimitado por corchetes en cualquier lugar donde pueda ir una instrucción (no solo después de cosas como if o for ) y puede usar esto para introducir nuevos ámbitos de variables. La siguiente es la versión ANSI C de los ejemplos anteriores de C99:

 if( x < 10 ){ printf("%d", 17); // z is not in scope in this line { int z = 42; printf("%d", z); // z is in scope in this line } } {int i; for(i=0; i<10; i++){ printf("%d", i); }} 

1 Tenga en cuenta que si está utilizando gcc, necesita pasar el indicador - --pedantic para hacer que se aplique realmente el estándar C90 y quejarse de que las variables se declararon en el lugar equivocado. Si solo usa -std=c90 hace que gcc acepte un superconjunto de C90 que también permite las declaraciones de variables C99 más flexibles.

missingno cubre lo que ANSI C permite, pero no aborda por qué sus profesores le dijeron que declare sus variables en la parte superior de sus funciones. Declarar variables en lugares impares puede hacer que su código sea más difícil de leer, y eso puede causar errores.

Tome el siguiente código como un ejemplo.

 #include  int main() { int i, j; i = 20; j = 30; printf("(1) i: %d, j: %d\n", i, j); { int i; i = 88; j = 99; printf("(2) i: %d, j: %d\n", i, j); } printf("(3) i: %d, j: %d\n", i, j); return 0; } 

Como puede ver, lo he declarado dos veces. Bueno, para ser más precisos, he declarado dos variables, ambas con el nombre i . Podría pensar que esto causaría un error, pero no es así, porque las dos variables i están en diferentes ámbitos. Puedes ver esto más claramente cuando miras la salida de esta función.

 (1) i: 20, j: 30 (2) i: 88, j: 99 (3) i: 20, j: 99 

Primero, asignamos 20 y 30 a i y j respectivamente. Luego, dentro de las llaves, asignamos 88 y 99. Entonces, ¿por qué entonces el j mantiene su valor, pero i vuelvo a ser 20 otra vez? Es debido a las dos variables i diferentes.

Entre el conjunto interno de llaves, la variable i con el valor 20 está oculta e inaccesible, pero como no hemos declarado una nueva j , todavía estamos usando la j del scope externo. Cuando dejamos el conjunto interno de llaves, el i tiene el valor 88 desaparece, y nuevamente tenemos acceso a la i con el valor 20.

Algunas veces este comportamiento es bueno, otras veces, tal vez no, pero debe quedar claro que si usas esta característica de C indiscriminadamente, puedes realmente hacer que tu código sea confuso y difícil de entender.

Si su comstackdor lo permite, está bien declarar en cualquier lugar que desee. De hecho, el código es más legible (en mi humilde opinión) cuando declara la variable donde usa en lugar de en la parte superior de una función porque facilita la detección de errores, por ejemplo, olvidando inicializar la variable u ocultando accidentalmente la variable.

Una publicación muestra el siguiente código:

 //C99 printf("%d", 17); int z=42; printf("%d", z); //ANSI C printf("%d", 17); { int z=42; printf("%d", z); } 

y creo que la implicación es que estos son equivalentes. Ellos no son. Si int z se coloca en la parte inferior de este fragmento de código, provoca un error de redefinición contra la primera definición de z pero no contra el segundo.

Sin embargo, múltiples líneas de:

 //C99 for(int i=0; i<10; i++){} 

funciona. Mostrando la sutileza de esta regla C99.

Personalmente, rechazo apasionadamente esta función C99.

El argumento de que reduce el scope de una variable es falso, como se muestra en estos ejemplos. Según la nueva regla, no puede declarar una variable de manera segura hasta que haya escaneado todo el bloque, mientras que antes solo necesitaba comprender lo que estaba sucediendo al principio de cada bloque.

Según el lenguaje de progtwigción The C de K & R –

En C, todas las variables deben declararse antes de ser utilizadas, generalmente al comienzo de la función antes de cualquier instrucción ejecutable.

Aquí puedes ver la palabra por lo general, no es obligatorio.