Herramientas de usuario

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
el_lenguaje_de_programacion_c_-_capitulo_4 [2024/10/01 17:20] – [4.3 Variables Externas] peronel_lenguaje_de_programacion_c_-_capitulo_4 [2026/04/21 16:06] (actual) – editor externo 127.0.0.1
Línea 261: Línea 261:
 Las variables externas son también útiles debido a su mayor alcance y tiempo de vida. Las variables automáticas son internas a una función y su existencia se inicia cuando se entra a la función y desaparecen cuando ésta se abandona. Por otro lado, las variables externas son permanentes, de modo que retienen sus valo­res de la invocación de una función a la siguiente. Así, si dos funciones deben compartir algunos datos, aun si ninguna llama a la otra, con frecuencia es más conveniente que los datos compartidos se mantengan en variables externas, en lu­gar de que sean pasados como argumentos de entrada y salida. Las variables externas son también útiles debido a su mayor alcance y tiempo de vida. Las variables automáticas son internas a una función y su existencia se inicia cuando se entra a la función y desaparecen cuando ésta se abandona. Por otro lado, las variables externas son permanentes, de modo que retienen sus valo­res de la invocación de una función a la siguiente. Así, si dos funciones deben compartir algunos datos, aun si ninguna llama a la otra, con frecuencia es más conveniente que los datos compartidos se mantengan en variables externas, en lu­gar de que sean pasados como argumentos de entrada y salida.
  
-Examinemos más a fondo este tema con un ejemplo más amplio. El problema es escribir el programa de una calculadora que provea los operadores ''+'' '','' ''—'' ''/'' ''*'' ''^'' ''/''. Por ser más fácil su implantación, la calculadora utilizará notación polaca in­versa en lugar de infija. (La polaca inversa es utilizada por algunas calculadoras de bolsillo, y en lenguajes como Forth y PostScript.)+Examinemos más a fondo este tema con un ejemplo más amplio. El problema es escribir el programa de una calculadora que provea los operadores ''+'' ''-'' ''*'' ''/''. Por ser más fácil su implantación, la calculadora utilizará notación polaca in­versa en lugar de infija. (La polaca inversa es utilizada por algunas calculadoras de bolsillo, y en lenguajes como Forth y PostScript.)
  
- +En notación polaca inversa, cada operador sigue a sus operandos; por lo tanto, lo que en una expre­sión infija se exoresa como
-En notación polaca inversa, cada operador sigue a sus operandos; una expre­sión infija como+
  
 <code>(1 - 2) * (4 + 5)</code> <code>(1 - 2) * (4 + 5)</code>
  
-se introduce como+en notación polaca inversa se introduce como
  
 <code c>1 2 - 4 5 + *</code> <code c>1 2 - 4 5 + *</code>
  
-Las paréntesis son innecesarias; la notación no es ambigua mientras sepamos cuántos operandos espera cada operador.+Las paréntesis son innecesarias;  toda vez que sepamos cuántos operandos espera cada operador, la notación no resulta ambigua.
  
-La implantación es simple. Cada operando se introduce en una pila o "stack", cuando un operador llega, el número correcto de operandos (dos para operadores binarios) son extraídos, se aplica el operador y el resultado se regresa a la pila. En el ejemplo anterior, se introducen ''1'' y ''2'', después se reemplazan por su diferencia, ''-1''En seguida se introducen ''4'' y ''5'' y luego se reemplazan por su suma, ''9''. El producto de ''-1'' y ''9'', que es ''-9'', los reemplaza en la pila. El valor que se encuentra en el tope de la pila se extrae e imprime cuando se encuentra el fin de la línea de entrada.+La implantación es simple. Cada operando se introduce en una pila o "stack", cuando se arriba a un operador, se extrae el número correcto de operandos (dos en el caso de los operadores binarios), se aplica el operador y el resultado se regresa a la pila. En el ejemplo anterior, se introducen ''1'' y ''2'', luego se reemplazan por su diferencia, ''-1''A continuación se introducen ''4'' y ''5'' y luego se reemplazan por su adición, ''9''. El producto de ''-1'' y ''9'', que es ''-9'', los reemplaza en la pila. El valor que se encuentra en el tope de la pila se extrae e imprime cuando se encuentra el fin de la línea de entrada.
  
-La estructura del programa es así un ciclo que realiza las operaciones adecua­das sobre cada operador y operando que aparece;+De esta forma, La estructura del programa que opere de esta manera será un ciclo que realice las operaciones adecua­das sobre cada operador y operando en la medida que aparecen;
  
 <code c> <code c>
-while (siguiente operador u operando no es fin de archivó)+while (siguiente operador u operando que no es fin de archivó)
     if (número)     if (número)
         introducirlo         introducirlo
Línea 292: Línea 291:
 </code> </code>
  
-Las operaciones de introducir {''push'') y extraer de una pila (''pop''son sencillas, pero cuando se les agrega detección y recuperación de errores, son suficientemenfe largas como para que sea mejor ponerlas en funciones separadas en lugar del codigo a lo largo de todo el programa. Además, debe existir una función separa­da para buscar el siguiente operador u operando.+Las operaciones de introducir en pila {//push//, o "apilar") y extraer de una pila (//pop// o "desapilar"resultan triviales, pero cuando al intentar agregar la detección y recuperación de errores, resultan suficientemente largas como para que sea conveniente colocarlas en funciones separadas en lugar del código repartido a lo largo de todo el programa. Además, debería existir una función separa­da para buscar el siguiente operador u operando.
  
-La principal decisión de diseño que aún no se ha explicado es dónde está la Mía, esto es, cuáles rutinas tienen acceso a ella directamente. Una posibilidad es Mantenerla en ''main'', y pasar la pila y la posición actual a las rutinas que introducen y extraen elementos. Pero ''main'' no necesita saber acerca de las variables que controlan a la pilasólo efectúa las operaciones de introducir y extraer. Así, hemos decidido almacenar la pila y su información asociada en variables externas accesibles a las funciones push y pop, pero no a main.+La principal decisión de diseño que aún no se ha explicado es dónde está la pila, esto es, cuáles rutinas tienen acceso a ella directamente. Una posibilidad es mantenerla en ''main'', y pasar la pila y la posición actual a las rutinas que introducen y extraen elementos. Pero ''main'' no necesita saber acerca de las variables que controlan a la pilasólo efectúa las operaciones de introducir y extraer. Así, hemos decidido almacenar la pila y su información asociada en variables externas accesibles a las funciones ''push'' ''pop'', pero no a main.
  
 Traducir este bosquejo a código es sumamente fácil. Si por ahora pensamos que el programa existe en un archivo fuente, se verá así Traducir este bosquejo a código es sumamente fácil. Si por ahora pensamos que el programa existe en un archivo fuente, se verá así
Línea 315: Línea 314:
 </code> </code>
  
-Más adelante se verá cómo esto se puede dividir entre dos o más archivos fuente. +Más adelante se verá cómo se puede dividir todo esto entre dos o más archivos de código fuente. 
  
-La función ''main'' es un ciclo que contiene un gran ''switch'' sobre el tipo de ope­rador y operando; éste es un uso del ''switch'' más típico que el mostrado en la [[sec­ción 3.4]].+La función ''main'' es un ciclo que contiene un ''switch'' gigante sobre el tipo de ope­rador y operando; éste es un uso del ''switch'' más típico que el mostrado en la [[sec­ción 3.4]].
  
 <code c> <code c>
Línea 330: Línea 329:
 double pop(void); double pop(void);
  
-/* calculadora polaca inversa */+/* Calculadora polaca inversa */
 main() main()
 { {
Línea 357: Línea 356:
             push(pop() / op2);             push(pop() / op2);
         else         else
-            printf("error: zero divisor\n");+            printf("error: divisor cero\n");
             break;             break;
         case '\n':         case '\n':
Línea 363: Línea 362:
             break;             break;
         default:         default:
-            printf("error: unknown command %s\n", s);+            printf("error: comando desconocido %s\n", s);
             break;             break;
         }         }
Línea 371: Línea 370:
 </code> </code>
  
-Puesto que ''+'' y ''*'' son operadores conmutativos, el orden en el que se combinan los operandos extraídos es irrelevante, pero para ''-'' y ''/'' deben distinguirse los ope­randos izquierdo y derecho. En+Puesto que ''+'' y ''*'' son operadores conmutativos, el orden en el que se combinan los operandos extraídos es irrelevante ("el orden de los factores no altera el producto"), pero en el caso de ''-'' y ''/'', se hace necesario distinguir su órden, en este caso específico, cuales son los ope­randos izquierdo y derecho. En
  
 <code c> <code c>
Línea 377: Línea 376:
 </code> </code>
  
-no se define el orden en el que se evalúan las dos llamadas de pop. Para garanti­zar el orden correcto, es necesario extraer el primer valor en una variable tempo­ral, como se hizo en ''main''.+no se ha definido el orden en el que se evalúan las dos llamadas de ''pop''. Para garanti­zar que el orden sea correcto, se hace necesario extraer el primer valor en una variable tempo­ral, como hicimos en ''main''.
  
 <code c> <code c>
Línea 406: Línea 405:
  
  
-Una variable es externa si se encuentra definida fuera de cualquier función. Así, la pila y el índice de la pila que deben ser compartidos por ''push'' y por ''pop'' se definen fuera de estas funciones. Pero ''main'' en sí misma no hace referencia a la pila o a la posición de la pila — la representación puede estar oculta.+Una variable es externa si se encuentra definida fuera de cualquier función. Por tanto, la pila y el índice de la pila que deben ser compartidos por ''push'' y por ''pop'' va definida por fuera de estas funciones. Pero ''main'' en sí misma no hace referencia a la pila o a la posición de la pila — la representación puede estar oculta.
  
-Pasemos ahora a la implantación de ''getop'', la función que toma el siguiente operador u operando. La tarea es fácilIgnorar blancos y tabuladores. Si el si­guiente carácter no es un dígito o punto decimal, regresarloDe otra manera, reu­nir una cadena de dígitos (que pueda incluir un punto decimal), y regresar ''NUMBER''la señal de que ha sido reunido un número.+Pasemos ahora a la implantación de ''getop'', la función que toma el siguiente operador u operando. La tarea es fácil: "Ignorar blancos y tabuladores. Si el si­guiente carácter no es un dígito o punto decimal, regresarloDe otra manera, reu­nir una cadena de dígitos (que pueda incluir un punto decimal), y regresar ''NUMBER'' (la señal de que ha sido reunido un número)".
  
 <code c> <code c>
Línea 425: Línea 424:
     s[1] = '\0';     s[1] = '\0';
     if (!isdigit(c) && c != '.')     if (!isdigit(c) && c != '.')
-        return c;    /* no-número */+        return c;     /* no-número */
     i = 0;     i = 0;
-    if (isdigit(c))    /* recoge parte de entero */+    if (isdigit(c))   /* recoge parte de entero */
         while (isdigit(s[++i] = c = getch()))         while (isdigit(s[++i] = c = getch()))
            ;            ;
-    if (c == '.') /* recoge parte fraccional */+    if (c == '.'    /* recoge parte fraccional */
         while (isdigit(s[++i] = c = getch()))         while (isdigit(s[++i] = c = getch()))
            ;            ;
Línea 440: Línea 439:
 </code> </code>
  
-¿Qué son ''getch'' y ''ungetch''? Por lo común se da el caso de que un programa no puede determinar si ha leído suficiente de la entrada hasta que ha leído de­masiado. Un ejemplo es reunir los caracteres que forman un número: hasta que se vea el primer no-dígito, el número no está completoPero para entonces el progra­ma ya ha leído un carácter de más, para el cual no está preparado.+¿Qué son ''getch'' y ''ungetch''? A menudo se da el caso de que un programa no puede determinar si ha leído lo suficiente de la entrada hasta que ya ha leído de­masiado de ellaReunir los caracteres que forman un número es un ejemplo de elloel número no está completo hasta que se ve el primer caracter no-dígito... pero para cuando ello sucede, el progra­ma ya ha leído un carácter de más, para lo cual no está preparado.
  
-El problema podría ser resuelto si fuera posible “desleer” el carácter no desea­doEntoncescada vez que el programa lea un carácter de más, podría regresarlo a la entrada, así que el resto del código se podrá comportar como si nunca se hubiese leído. Afortunadamente, es fácil simular el regreso de un carácter, escri­biendo un par de funciones cooperativas, ''getch'' entrega el siguiente carácter de la entrada que va a ser considerado; ''ungetch'' reintegra el carácter devuelto a la entrada, de modo que llamadas posteriores a ''getch'' lo regresarán antes de leer algo nuevo de la entrada.+El problema podría ser resuelto si fuera posible “desleer” el carácter indesea­doDe esta maneratoda vez que el programa lea un carácter de más, podría devolverlo a la entrada, provisión con la cual el resto del código se comportará como la lectura de más jamás hubiese sucedido. Afortunadamente, es fácil simular el regreso de un carácter, escri­biendo un par de funciones cooperativas, ''getch'' entrega el siguiente carácter de la entrada que va a ser considerado; ''ungetch'' reintegra el carácter devuelto a la entrada, de modo que llamadas posteriores a ''getch'' lo regresarán antes de leer algo nuevo de la entrada.
  
-Cómo trabajan juntas es sencillo, ''ungetch'' coloca el carácter regresado en un buffer compartido: un arreglo de caracteres. ''getch'' lee del buffer si hay algo allí y si el buffer está vacío llama a ''getchar''. También debe existir una va­riable índice que registre la posición del carácter actual en el buffer temporal. Puesto que el buffer y el índice son compartidos por ''getch'' y ''ungetch'' y deben retener sus valores entre llamadasdeben ser externos a ambas rutinas. Asi, pode­mos escribir ''getch'', ''ungetch'' y sus variables compartidas como:+Cómo trabajan juntas es sencillo, ''ungetch'' coloca el carácter devuelto en un buffer compartido: un arreglo de caracteres. ''getch'' lee del buffer si hay algo allíy si el buffer está vacío llama a ''getchar''. También debe existir una va­riable índice que registra la posición del carácter actual en el buffer temporal. Puesto que el buffer y el índice son compartidos por ''getch'' y ''ungetch'' y deben retener sus valores entre llamadas deben ser externos a ambas rutinas. Asi, pode­mos escribir ''getch'', ''ungetch'' y sus variables compartidas como:
  
 <code c> <code c>
Línea 450: Línea 449:
  
 char buf[BUFSIZE];  /* buffer para ungetch */ char buf[BUFSIZE];  /* buffer para ungetch */
- 
 int bufp = 0;       /* siguiente posición libre en el buffer */ int bufp = 0;       /* siguiente posición libre en el buffer */
  
-int getch(void) /* obtiene un (posiblemente regresado) caracter */+int getch(void)     /* obtiene un (posiblemente regresado) caracter */
 { {
     return (bufp > 0) ? buf[--bufp] : getchar();     return (bufp > 0) ? buf[--bufp] : getchar();
Línea 478: Línea 476:
   * **Ejercicio 4-9**, Nuestros ''getch'' y ''ungetch'' no manejan correctamente un EOF que se regresa. Decida cuáles deben ser sus propiedades si se regresa un EOF, y des­pués realice su diseño. □   * **Ejercicio 4-9**, Nuestros ''getch'' y ''ungetch'' no manejan correctamente un EOF que se regresa. Decida cuáles deben ser sus propiedades si se regresa un EOF, y des­pués realice su diseño. □
   * **Ejercicio 4-10**. Una organización alternativa emplea ''getline'' para leer una línea completa de entrada; esto hace innecesarios a ''getch'' y a ''ungetch''. Corrija la calculadora para que use este planteamiento. □   * **Ejercicio 4-10**. Una organización alternativa emplea ''getline'' para leer una línea completa de entrada; esto hace innecesarios a ''getch'' y a ''ungetch''. Corrija la calculadora para que use este planteamiento. □
-==== 4.4 Reglas y Alcance ==== 
  
 +==== 4.4 Reglas y Alcance ====
  
 ==== 4.5 Archivo de encabezamiento header ==== ==== 4.5 Archivo de encabezamiento header ====

Este sitio web utiliza cookies para guardar datos esenciales de su actividad, como su autenticación. Al entrar acepta el uso de cookies.

Más información