M. C. Bertha López Azamar Modulo 4 pag. 1 PROGRAMACION ESTRUCTURADA 1.1 Esquema General de un programa en Lenguaje C El lenguaje C, tiene una sintaxis que permite al programador estructurar sus programas de una manera fácil, siempre y cuando se respeten las reglas y se tenga un buen estilo de programación. Todo programa tiene una estructura general, dependiendo muchas veces del tipo de programación que se este tratando, va a ser la forma de incluir los elementos que un programa permite. En el caso de la programación en el lenguaje C, todo programa consta de uno o más módulos llamados funciones. Una de las funciones se llama main(), y todo programa escrito en C comenzará con ésta función, desde la cual se puede acceder a las demás funciones. Recordemos que un programa puede considerarse como una secuencia de acciones (instrucciones) que manipulan un conjunto de objetos (datos). Contendrá, por lo tanto, dos bloques para la descripción de los aspectos citados: Bloque de declaraciones: En él que se especifican todos los objetos que utiliza el programa (variables, constantes, tablas, registros, archivos, etc.) El lenguaje C es sensible a mayusculas y minusculas. Bloque de instrucciones: Constituido por el conjunto de operaciones que se han de realizar para la obtención de los resultados deseados. 1.1.1 Descomposición de un problema #include <stdio.h> #define PI 3.1416 #define CUADRADO(x) ((x)*(x)) /* Programa: Area de un círculo Autor: A.G. programador Descripción: Este programa calculará el área de un círculo. El programador sólo debe introducir el radio. El valor devuelto está en unidades cuadradas Variables: valor_de entrada = Valor introducido por el usuario. radio = Radio del círculo. area = área del círculo. Constantes: PI = 3.1416 Prototipos de funciones: */ void explica_el programa(void); float obtener_valor(void); float area_del_circulo(float radio); void mostrar_la_respuesta(void);
29
Embed
PROGRAMACION ESTRUCTURADA - unpa.edu.mxblopez/ProgramacionEstructurada/Estructura... · M. C. Bertha López Azamar Modulo 4 pag. 1 PROGRAMACION ESTRUCTURADA 1.1 Esquema General de
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
M. C. Bertha López Azamar Modulo 4 pag. 1
PROGRAMACION ESTRUCTURADA
1.1 Esquema General de un programa en Lenguaje C
El lenguaje C, tiene una sintaxis que permite al programador estructurar sus programas de
una manera fácil, siempre y cuando se respeten las reglas y se tenga un buen estilo de programación.
Todo programa tiene una estructura general, dependiendo muchas veces del tipo de
programación que se este tratando, va a ser la forma de incluir los elementos que un programa
permite. En el caso de la programación en el lenguaje C, todo programa consta de uno o más
módulos llamados funciones. Una de las funciones se llama main(), y todo programa escrito en C
comenzará con ésta función, desde la cual se puede acceder a las demás funciones.
Recordemos que un programa puede considerarse como una secuencia de acciones
(instrucciones) que manipulan un conjunto de objetos (datos). Contendrá, por lo tanto, dos bloques
para la descripción de los aspectos citados:
Bloque de declaraciones: En él que se especifican todos los objetos que utiliza el
programa (variables, constantes, tablas, registros, archivos, etc.) El lenguaje C es
sensible a mayusculas y minusculas.
Bloque de instrucciones: Constituido por el conjunto de operaciones que se han de
realizar para la obtención de los resultados deseados.
1.1.1 Descomposición de un problema
#include <stdio.h>
#define PI 3.1416
#define CUADRADO(x) ((x)*(x))
/* Programa: Area de un círculo
Autor: A.G. programador
Descripción: Este programa calculará el área de un círculo. El programador sólo
debe introducir el radio. El valor devuelto está en unidades cuadradas
Variables:
valor_de entrada = Valor introducido por el usuario.
radio = Radio del círculo.
area = área del círculo.
Constantes: PI = 3.1416
Prototipos de funciones:
*/
void explica_el programa(void);
float obtener_valor(void);
float area_del_circulo(float radio);
void mostrar_la_respuesta(void);
M. C. Bertha López Azamar Modulo 4 pag. 2
float area; //area del circulo
void main()
{
float radio;
explica_el_programa(); /*explica el programa*/
radio = obtener_valor(); //pide el radio al usuario
area = area_del circulo(radio); //calcula el área del circulo
mostrar la respuesta(); //muestra la respuesta al usuario
}
void explica_el_programa(void) /*explica el programa al usuario*/
{
printf("Este programa calcula el area de un circulo.\n");
printf("Introduzca el valor del radio y pulse -INTRO- \n");
printf("\n"); /*imprime una línea en blanco*/
}
float obtener_valor(void) //Pide el radio al usuario
{
float valor_de _entrada; //valor introducido por el usuario
printf("Valor del radio --> ");
scanf("%f", &valor_de_entrada);
return(valor_de_entrada);
}
float area_del_circulo(float radio) //Calcula el área del círculo
{
float area; //area del circulo
area = PI * CUADRADO(radio);
return(area);
}
void mostrar_la_respuesta(void)
{
printf("\n\n"); /*imprime dos lineas en blanco*/
printf("El area del circulo es %f unidades.", area);
}
M. C. Bertha López Azamar Modulo 4 pag. 3
1.2 Concepto de función
Las funciones son bloques constructores de C y el lugar donde se produce toda la actividad
del programa.
Una función es una colección independiente de declaraciones1 y
sentencias(instrucciones).
Una función es un segmento independiente de código fuente diseñado para realizar
una tarea específica.
Cualquier programador puede hacer sus propias funciones en C, la única función obligatoria
es main(), y a partir de ella, se llaman todas las demás. Debe tenerse cuidado de escribir los
prototipos de funciones, las llamadas deben hacerse correctamente y mandando los argumentos
correctos, en el orden correcto, con los tipos de datos correctos; y devolviendo(retornando) los
valores de acuerdo al tipo de dato de la variable que recibirá el valor en la llamada a la función;
igualmente, las cabeceras de las funciones y los prototipos de las mismas, deben tener los tipos de
datos de las variables en el orden correcto e iguales, ya que sino, se incurre en errores de sintaxis,
los cuales deben de ser detectados por el programador.
No es un trabajo complicado el manejo de funciones, pero si es delicado en el aspecto de
manejo de variables, ya que deben considerarse los tipos de datos, para que no se tengan
inconsistencias y el programa mantenga la integridad.
Si queremos que nuestro programa tenga mayor legibilidad y podamos mantener bloques de
código consistentes, podemos estar seguros de que el manejo de las funciones en la programación en
C proporciona las mayores ventajas. Recordemos que tratamos en este curso la programación
estructurada.
Cada función es un bloque de código discreto. Por lo que una función define un ámbito de
bloque. Lo que significa que el código de una función es privado a esa función, y no se puede
acceder a él mediante una instrucción de otra función, a menos que se haga a través de una llamada
a esa función.
La declaración de una función se realiza mediante lo que se denomina prototipo de una
función. Un prototipo de función consta del nombre de la función y de información importante
relativa a la misma. Los prototipos de las funciones aparecen al comienzo del programa y antes de la
función main().
Cuando se define una función, se indica de nuevo el nombre de la función y la información
relativa a la misma (al igual que en el prototipo de la función) y el cuerpo de la función, que
contiene todo el código fuente utilizado por la función.
El cuerpo de la función está oculto al resto del programa. Las variables de la función son
locales al código, a menos que la variable se defina como global.
Los parámetros formales de una función también tienen la función como ámbito. Esto
significa que los parámetros se conocen en toda la función.
Todas las funciones tienen un ámbito de archivo, es decir son locales al archivo.
No se puede definir una función dentro de otra función.
1 Una declaración establece la relación entre el nombre y el tipo de una variable u otra función.
M. C. Bertha López Azamar Modulo 4 pag. 4
Todas las funciones deben estar declaradas antes de ser utilizadas. Esto normalmente se
lleva a cabo mediante los prototipos de funciones. Aunque los prototipos no son técnicamente
obligatorios, su uso se recomienda insistentemente. (en C++, su uso si es obligatorio)
Los prototipos permiten que el compilador lleve a cabo una fuerte comprobación de tipos.
Cuando se usan, el compilador puede encontrar e informar sobre conversiones de tipo ilegales entre
el tipo de los argumentos usados en la llamada a la función y las definiciones de tipos de sus
parámetros.
La forma general de un prototipo de función es:
Tipo nombre_de_la_funcion(tipo de parámetro1, tipo de parámetro2,…, tipo de parámetroN, );
En el prototipo, colocar los parámetros es opcional, pero esto permite que el compilador
identifique la discordancia de tipo por su nombre, cuando se dé un error, por lo que es una buena
idea incluirlos.
La forma general de una función es:
Tipo_dev nombre_de_la_funcion(lista de parámetros)
{
cuerpo de la función
}
donde:
tipo_dev especifica el tipo de dato que devuelve la función. Una función puede
devolver cualquier tipo de dato, excepto un array.
Nombre_de_funcion, cuando se crea una función, es mejor darle un nombre
descriptivo. Recordemos que el nombre es un identificador, por lo que debe
cumplir las reglas de los identificadores.
Lista de parámetros es una lista de nombres de variables separados por comas con
sus tipos asociados. Los parámetros reciben los valores de los argumentos
cuando se llama a la función. Puede no tener parámetros una función, y se
especifica colocando la palabra clave void entre los paréntesis. Si los
parámetros son del mismos tipo, deben declararse individualmente, la forma
general es la siguiente:
f(tipo var1, tipo var2 …,, tipo varN)
Ejemplos:
Correcto: f(int i, int k, int j);
Incorrecto: f(int i, k, float j); /*a k le falta el tipo de dato*/
Si una función va a aceptar argumentos, debe declarar variables que reciban los valores de
los argumentos.
M. C. Bertha López Azamar Modulo 4 pag. 5
Ejemplo:
#include <stdio.h>
int cuadrado(int Y); /*prototipo de la función*/
int main(void)
{
int X=10;
printf(“El cuadrado de %d, es: %d”, t, cuadrado(t)); /*llamada de la función*/
return 0;
}
int cuadrado(int Y) /*declaración de la función*/
{
y = y * y;
return(Y);
}
La instrucción return se usa para devolver de una función. Se trata de una instrucción de
salto porque hace que la ejecución vuelva al punto en que se hizo la llamada a la función. Puede
tener o no uno y solo un valor asociado, en una función con valor de vuelta de tipo distinto de void.
En este caso, el valor asociado con return es el valor de vuelta de la función. El return sin valor de
vuelta se utiliza para volver de las funciones de tipo void. La sintaxis general es:
return expresión;
donde:
expresión estará presente sólo si se ha declarado la función como devolviendo un valor.
Pueden usarse tantas instrucciones return como se quiera en una función, pero, la función
terminará al encontrarse la primera línea con la función return. Si no se va a devolver un valor
(porque la función se declaro como void), y se encuentra primero la llave de cierre de la función
(“}“), esto provoca que se termine la función y se vuelva de ella, equivale a un return sin valor
especifico.
Todas las funciónes, excepto aquellas de tipo void, devuelven un valor. Este valor se
especifica explícitamente en la instrucción return. Una función que no sea de tipo void debe
devolver un valor por medio de una instrucción return. Si la ejecución de una función que no sea
void llega al final de la función (esto es, si encuentra la llave de cierre al final de la función), se
devuelve basura como valor de vuelta. Pero esto es una mala práctica y se debe evitar.
Ahora bien, cualquier función de biblioteca estandar que se utilice en el programa, debe
estar prototipada. Para ello se debe incluir la cabecera (archivo de cabecera) apropiada para cada
función de biblioteca. En C, las bibliotecas de funciones generalmente tienen archivos de extensión
.h.
M. C. Bertha López Azamar Modulo 4 pag. 6
1.3 Concepto de procedimiento
El caso de las subrutinas o procedimientos, estos, son subprogramas que ejecutan un proceso
específico.
Ningún valor esta asociado con el nombre del procedimiento, por lo que, no puede ocurrir en
una expresión.
Un procedimiento puede devolver muchos valores al salir de el, un valor o ningún valor y en
forma de lista de parámetros.
En realidad, los procedimientos ya se conservan sólo en algunos lenguajes procedimentales
como Pascal. En otros lenguajes, sólo se implementan funciones y los procedimientos son
equivalentes a funciones que no devuelven valor (En C, se denomina función que devuelve un valor
de tipo void).
M. C. Bertha López Azamar Modulo 4 pag. 7
1.4 Variables globales y locales
Existen tres sitios básicos donde se declaran variables:
dentro de las funciones, y son llamadas variables locales.
en la definición de parámetros de funciones y son llamados parámetros formales; y
fuera de todas las funciones y se les llama variables globales.
Las variables locales pueden ser utilizadas sólo en las instrucciones que estén dentro del
bloque en el que han sido declaradas. No se conocen fuera de su propio bloque de código. Es más,
otra variable en otro bloque de código puede llamarse igual, y no tiene nada que ver con ella. El
bloque más normal en el que se declaran las variables locales es la función.
Ejemplo:
void funciónX(void)
{
int X;
X = 30;
}
void funciónYvoid)
{
int X;
X = 10;
}
Las variables locales, sólo existen mientras se está ejecutando el bloque en el que son
declaradas. Se crean al entrar en el bloque y se destruye al salir de él, es decir, su contenido se
pierde al salir de él. Esto significa que no pueden retener sus valores entre llamadas. Por esto, al
darse un valor inicial a una variable local estática, este valor se asignará cada vez que vuelva a
llamarse a la función. Aunque se puede indicar al compilador que retenga sus valores mediante el
uso del modificador static.
A menos que se especifique lo contrario, las variables locales se guardan en la pila. Y por lo
tanto, terminar la llamada a la función, los valores no se pueden mantener, y se borran de la pila.
La ventaja de las variables locales es que hace a los subprogramas independientes,
permitiendo la comunicación, entre el programa principal y los subprogramas manipulados
estructuralmente, a través de la lista de parámetros ( lo cual se conoce como paso de parámetros)
NOTA: el ámbito de un identificador (variable, constante, procedimiento) es la parte del
programa donde se conoce el identificador.
M. C. Bertha López Azamar Modulo 4 pag. 8
Figura 1 Ejemplificación del ámbito de las variables.
En la figura superior, puede observarse claramente el ámbito de las variables; los bloques de
código marcados por los círculos internos, determinan claramente el lugar donde son vistas cada una
de las variables locales, por ejemplo: las variables VAR5 y VAR6, son empleadas únicamente por la
FUNCION C, y ninguna de las otras funciones puede ver a tales variables. Lo contrario pasa con la
funcion VAR0, la cual se encuentra en el bloque del código principal del programa, y puede ser
vista tanto por FUNCION A, FUNCION B y FUNCION C, ya que es una variable global.
Las variables globales, se conocen a lo largo de todo el programa y se pueden usar en
cualquier parte del código. Además de que mantienen sus valores durante toda la ejecución del
programa. Se crean al declararlas en cualquier parte fuera de una función.(recordemos que main() es
una función igualmente de C).
Pueden ser accedidas por cualquier expresión, independientemente de la función en la que se
encuentre la expresión. Si una variable global y una variable local tienen el mismo nombre, todas las
referencias a ese nombre de variable dentro de la función donde se ha declarado la variable local se
refieren a esa variable local y no tienen efecto sobre la variable global.
Las variables globales, tienen la ventaja de compartir información de diferentes
subprogramas, sin una correspondiente entrada en la lista de parámetros.
El almacenamiento de las variables globales se hace en una región de memoria fija
establecida para este propósito por el compilador. Son muy útiles cuando se usan los mismos datos
FUNCION
A
var1, var2
FUNCION C
VAR5,VAR6
FUNCION
B
var3,var4 PROGRAMA
PRINCIPAL
VAR0
M. C. Bertha López Azamar Modulo 4 pag. 9
en varias funciones del programa, sin embargo el uso de variables globales innecesarias, provoca
que se utilice memoria durante todo el tiempo de la ejecución del programa.
C define tres categorías de enlace: externo, interno y nulo.
En general las funciones y las variables globales se ven afectadas por un enlace
externo. Esto significa que están disponibles para todos los archivos que constituyen
el programa.
Los objetos con ámbito de archivo declarados como static2 tienen un enlace interno.
Sólo son conocidos dentro del archivo en el que están declarados. Las variables
locales no se ven afectadas por el enlace y por lo tanto son conocidas sólo dentro de
su propio bloque.
C contempla cuatro especificadores de clase de almacenamiento para las variables: extern,
static, register, auto.
El uso de extern es el de especificar que un objeto está declarado con enlace externo en
alguna otra parte del programa. En la mayoria de los casos, al declarar una variable, también se dice
que se esta definiendo (es decir, que se esta disponiendo de almacenamiento para la variable), sin
embargo, al usar el especificador extern, se puede declarar una variable sin definirla. Pero, si se da
un valor a la variable, la declaración extern se convierte en una definición.
Por ejemplo, cuando se declara una variable, dentro del bloque de la función main(), puede
ser declarada como extern, para que si en algun bloque de codigo externo al main(), se llega a
definir, se pueda hacer, y se pueda usar, incluso antes de la línea de código donde se inicializan los
valores.
Ejemplo:
int main(void)
{
extern int primero, ultimo; /*uso de variables globales*/
printf(“%d, %d”), primero, ultimo);
return 0;
}
…
/*definición global de primero y ultimo en otra linea fuera del main()*/
int primero = 10, ultimo = 20;
Aquí lo que el printf mostrará será los valores 10, 20.
El mayor uso de extern es el que se le da con los programas multiarchivo, los cuales son
compilador por separado y enlazados luego juntos.
Las variables static son variables permanentes. Difieren de las variables globales en que no
2 Las variables static son variables permanentes. Difieren de las variables globales en que no son conocidas
fuera de su función o archivo, aunque mantienen sus valores entre llamadas.
M. C. Bertha López Azamar Modulo 4 pag. 10
son conocidas fuera de su función o archivo, aunque mantienen sus valores entre llamadas.
Las variables locales static sólo se conocen en la función o bloque de código en el que son
declaradas; los nombres de las variables globales static sólo se conocen en el archivo en que residen.
Las variables static permiten al programador ocultar partes de un programa a otras partes del mismo.
Al aplicarse el especificador static a una variable local, el compilador crea un
almacenamiento permanente para ella de forma que sólo sea conocida por el bloque de código donde
es declarada. Pero que al realizar llamadas sucesivas a la función, el valor de la variable en la
llamada anterior a la función, pueda ser recuperado en la llamada actual. Puede darse un valor inicial
a una variable local estática, pero este valor se asignará sólo una vez; y no cada vez que vuelva a
llamarse a la función.
Al aplicarse el especificador static a una variable global, lo que se hace es indicarle al
compilador que cree una variable global conocida solo en el archivo en el que se declara la variable
global estática. Lo que ocasiona que las rutinas de otros archivos no la reconocerán y no podrán
alterar sus valores. Así una variable global estática tiene enlace interno.
El especificador de almacenamiento register, originalmente pedía al compilador que
mantuviera el valor de una variable declarada con ese especificador en un registro de la CPU en
lugar de en memoria, que es donde se almacenan las variables. Actualmente, la definición de
register se ha ampliado, pudiendo ser aplicado a cualquier tipo de variable. Simplemente establece
que el acceso al objeto sea lo más rápido posible. Dependiendo de la implementación del
compilador de C y del entorno de operación, las variables register pueden ser manejadas de algún
modo establecido por el creador del compilador. Solo puede aplicarse el especificador register a
variables locales y a parámetros formales de una función. No se permiten variables globales
register.
El especificador auto, se usa para declarar variables globales. Sin embargo, como todas las
variables que no son globales son, por defecto asumidas como auto, este especificador casi ni se usa.
M. C. Bertha López Azamar Modulo 4 pag. 11
1.5 Paso de parámetros
Muchas funciones usan argumentos, por lo cual debe declarar las variables que van a aceptar
esos valores de los argumentos, a estas variables se les llama propiamente parámetros formales de la
función. Estos, se comportan como cualquier otra variable local de la función.
Figura 2 Llamadas a funciones
Como puede verse en la figura 6, las funciones pueden ser llamadas desde el programa
principal, en la parte de la función main(), así como también pueden llamarse desde otra función. El
objetivo del uso de funciones es poder modularizar el código, permitiendo con ello simplificar la
implementación de la solución del problema. Para permitir que las funciones sean generales, y
puedan manipular valores o referencias de valores externos, se emplea el paso de parámetros.
Los parámetros de una manera simple, permiten mantener aislado código y funcionalidad,
permitiendo que el código pueda reutilizarse.
El uso del paso de parámetros permite que el programador afecte o no los valores de las
variables originales.
Veamos el siguiente diagrama, que nos muestra claramente el uso de los parámetros y los
argumentos.
FUNCION A()
var1, var2
invoca a
FUNCION B()
FUNCION B()
var3,var4
PROGRAMA PRINCIPAL
VAR0
FUNCION main()
VAR10,VAR11
Invoca a
FUNCION A()
FUNCION C() FUNCION C()
VAR5,VAR6
invoca a
FUNCION A()
M. C. Bertha López Azamar Modulo 4 pag. 12
Figura 3 Ejemplificación gráfica del paso de parámetros.
Como podemos ver en la figura, existe un programa principal, una variable global llamada
VAR0, la cual, es pasada como argumento a la función A, por referencia, es decir, se pasa su
dirección de memoria; esto, quizá pueda parecer innecesario, ya que sabemos que una variable
global puede ser vista por cualquier parte del programa, es decir, por cualquier función. El objetivo
de que la función A reciba la dirección de memoria de la variable VAR0, en el parámetro formal “x”
(el cual es un puntero), es permitir que de una u otra forma, la función pueda modificar el valor de la
variable(VAR0) que se encuentra fuera del bloque de código, es decir, fuera del ámbito de la
función, ya que puede llamarse a la función desde cualquier otra parte de código y pasarse por
referencia cualquier otra variable no global; podemos ver el ejemplo de esto con la llamada a la
función A, desde la función C, la cual le pasa como argumento en la llamada la dirección de
memoria de la variable VAR6.
Las declaraciones de los parámetros formales se dan tras el nombre de la función y entre los
paréntesis.
Ejemplo:
FUNCION main()
VAR10,VAR11
Invoca a
FUNCION A(&VAR0)
FUNCION C(VAR10, VAR11)
FUNCION A(*x)
var1, var2
invoca a
FUNCION B(&var1, var2)
FUNCION C(m, l)
VAR5,VAR6
invoca a
FUNCION A(&VAR6)
FUNCION B(*a, b)
var3,var4
PROGRAMA PRINCIPAL
VAR0
M. C. Bertha López Azamar Modulo 4 pag. 13
void funcionX(int X) //aquí se muestra un parámetro X en la función funcionX.
{
int Y;
X = 10;
Y +=X;
return (Y);
}
Los parámetros formales reciben los valores de los argumentos que se pasan a la función,
pero en sí, se comportan como cualquier otra variable local, por lo que igualmente tienen la misma
característica de destruirse al salir de de la función.
Existe el paso de argumentos a la función por valor y por referencia.
El paso por valor, copia el valor de un argumento en el parámetro formal de la subrutina. En
este caso, los cambios realizados sobre el parámetro no afectan al argumento.
Ejemplo:
#include <stdio.h>
int cuadrado(int Y);
int main(void)
{
int X=10;
printf(“El cuadrado de %d, es: %d”, t, cuadrado(t));
return 0;
}
int cuadrado(int Y)
{
y = y * y;
return(Y);
}
El resultado mostrado sería: El cuadrado de 10 es 100.
La llamada por referencia, copia la dirección del argumento en el parámetro. Dentro de la
subrutina se usa la dirección para acceder realmente al argumento usado en la llamada, con lo que
los cambios sufridos por el parámetro se reflejan en el argumento.
Se puede crear una llamada por referencia pasando un puntero al argumento, en lugar de
pasar el propio argumento. Como lo que se pasa a la función es la dirección del argumento, el
código de la función puede cambiar el valor del argumento externo a la función.
M. C. Bertha López Azamar Modulo 4 pag. 14
Los punteros se pasan a las funciones como cualquier otro argumento. Por supuesto, es
necesario declarar los parámetros como de tipo puntero.
Ejemplo:
#include <stdio.h>
void interambio(int *x, int *y);
int main(void)
{
int I, j;
i=10;
j=20;
printf(“ i y j antes del intercambio: %d, %d \n”, i, j);
inter(&i, &j); /*se pasan las direcciones de i y j */
/* se usa el operador monario & para obtener la dirección de las
variables.*/
printf(“ i y j después del intercambio: %d, %d \n”, i, j);
return 0;
}
void intercambio(int *x, int *y);
{
int temp;
temp = *x; /*guarda el valor de la dirección de X */
*x = *y; /*poner y en x */
*y = temp; /*poner x en y*/
}
La salida del programa es:
i y j antes del intercambio: 10, 20
i y j después del intercambio: 20,10
M. C. Bertha López Azamar Modulo 4 pag. 15
2 Primitivas de entrada y salida
C dispone de una biblioteca de funciones de E/S (entrada/salida) muy completa. Estas rutinas
de E/S permiten leer y escribir datos en archivos y dispositivos. Sin embargo, el propio lenguaje C
no incluye estructuras de archivos predefinidas. C trata todos los datos como secuencias de bytes.
Existen tres tipos básicos de funciones de E/S:
De flujo
Por consola y puerto, y
De bajo nivel.
Todas las funciones de E/S de flujo tratan los archivos de datos o los elementos de datos
como un flujo de caracteres individuales. Seleccionando la función de flujo apropiada, la aplicación
puede procesar los datos en cualquier orden o formato requerido, desde caracteres simples a
estructuras de datos grandes y complicadas.
Técnicamente, cuando un programa abre un archivo para utilizar las funciones de flujo de
E/S, el archivo abierto se asocia con una estructura de tipo FILE (predefinido en stdio.h) que
contiene información básica sobre el archivo. Una vez que se abre el flujo, se devuelve un puntero a
la estructura del archivo. El puntero del archivo, a veces llamado puntero de flujo o flujo, se utiliza
para hacer referencia al archivo en todas las sucesivas operaciones de E/S. Todas las funciones de
E/S por flujo proporcionan E/S por buffer, con o sin formato. Un formato por buffer proporciona
una posición de almacenamiento intermedia para toda la información que se introduce en el flujo y
que se extrae del mismo.
Las rutinas de E/S por consola o puerto, tienen un funcionamiento similar a las de flujo,
incluso pueden considerarse como una extensión de estas. Las funciones para la consola y los
puertos de E/S, ejecutan las operaciones de lectura y escritura sobre la consola(teclado/pantalla) o
sobre un puerto específico (como puerto de impresoras). Las funciones de E/S por puerto
simplemente leen o escriben los datos por bytes. Las funciones de E/S por consola ofrecen varias
opciones adicionales, por ejemplo, se puede detectar si se ha escrito un carácter en la consola y si los
caracteres introducidos se muestran o no en la pantalla mientras se leen.
De las funciones de entrada y salida de bajo nivel, ninguna realiza su operación a través de
un buffer o con formato; en su lugar, llaman directamente a las capacidades de entrada y salida del
sistema operativo. Estas rutinas permiten acceder a los archivos y los dispositivos periféricos a un
nivel mas básico que las funciones de flujo. Los archivos abiertos de esta forma devuelven un
controlador de archivo. Este controlador es un valor entero que se utiliza para hacer referencia al
archivo en las sucesivas operaciones.
FUNCIONES DE FLUJO
Para utilizar las funciones de flujo, la aplicación debe incluir el archivo “stdio.h”. Este
archivo contiene la definición de constantes, tipos y estructuras utilizados en las funciones de flujo,
y contiene los prototipos de funcion y las definiciones de macro para las rutinas de flujo.
Cuando comienza a ejecutarse una aplicación, automáticamente se abren cinco flujos. Estos
son el estándar de entrada (stdin), el estándar de salida (stdout), el estándar de error (stderr), el
estándar de impresión (stdprn) y el estandar auxiliar (stdaux).
M. C. Bertha López Azamar Modulo 4 pag. 16
Por omisión, el estándar de entrada, el estándar de salida y el estándar de error hacen
referencia al terminal del usuario. Esto significa que siempre que un programador espere una entrada
desde el estándar de entrada, entiende que la entrada es desde el terminal. De la misma forma, un
programa que escribe en el estándar de salida muestra sus datos en el terminal. Cualquier mensaje de
error que generen las rutinas de las bibliotecas se envía al flujo estándar de error, indicando que el
mensaje de error aparece en el terminal de usuario.
Los sistemas operativos actuales consideran el teclado y el visualizador de video como
archivos. Esto, porque el sistema puede leer desde el teclado de la misma forma que lo hace desde
un archivo de disco o de cinta. De forma similar, el sistema puede escribir en un visualizador de
video tal y como lo hace en un archivo de disco o de cinta.
Todos los archivos abiertos que utilizan las funciones de flujo (stdin(), stdout() y stdprn())
por omisión utilizan un buffer excepto para los flujos abiertos previamente stderr y stdaux, estos
flujos, por omisión no utilizan un buffer a menos que se utilicen en la familia de funciones printf() o
scanf(). En este caso, se les asigna un buffer temporal.
Existen ciertas funciones de entrada y salida de caracteres definidas en el estandar ANSI de
C que son suministradas con todos los compiladores de C. Estas funciones ofrecen la entrada y
salida estándar, y se consideran rutinas de alto nivel (en contraste con las rutinas de bajo nivel, que
acceden al hardware de la máquina mas directamente) La E/S en C está implementada a traves de
funciones suministradas por el fabricante mas que como palabras reservadas definidas como parte
del lenguaje.
Las más básicas de todas las funciones de E/S son aquellas de entrada y salida de un único
carácter.
getc() y putc():
La funcion getc() (que realmente es una macro) introduce un carácter desde un flujo de
archivo especificado, de la siguiente forma :
int ic;
ic=getc(stdin);
El carácter de entrada se devuelve en el nombre de la funcion getc() y, a continuación, asigna
el valor devuelto a ic.
La función getc() convierte el entero en un carácter sin signo. Este uso de un carácter sin
signo almacenado como entero garantiza que los valores ASCII superiores a 127 no se representan
como valores negativos. Por tanto, se pueden utilizar los valores negativos para representar
situaciones inusuales como errores y el final de un archivo de entrada.
Aunque pueda parecer extraño un entero en una función de caracteres, el lenguaje C
realmente considera una distinción mínima entre caracteres y enteros. Si se proporciona un carácter
cuando se necesita un entero, el carácter se convertira en un entero.
El complemento de la función getc() es putc(). Ésta, extrae un carácter del flujo de archivo
representado por el puntero de archivo especificado. Para enviar el mismo carácter que se había
leido anteriormente al estándar de salida, se utiliza la instrucción:
putc(ic,stdout);
M. C. Bertha López Azamar Modulo 4 pag. 17
Ejemplo de un programa:
#include <stdio.h>
void main()
{
int ic;
ic=getc(stdin);
putc(ic,stdout);
}
Una observación, la función getc() normalmente utiliza un buffer, lo que significa que
cuando la aplicación solicita un carácter, no se devuelve el control al programa hasta que se haya
introducido un retorno de carro (ENTER) en el flujo del archivo estándar de entrada.
Las dos macros getchar() y putchar() realmente son implementaciones especificas de las
macros getc() y putc(), respectivamente. Siempre estan asociadas con el estándar de entrada (stdin) y
con el estándar de salida (stdout).
getchar() y putchar():
getchar() .- Mediante esta función se puede conseguir la entrada de caracteres uno a uno. Esta
función es parte de la biblioteca de C de entrada/salida standard. Devuelve un carácter leído
del dispositivo de entrada standard (típicamente el teclado).
En general una referencia a esta función se escribe: variable_de_carácter = getchar();
putchar().- Se puede visualizar un carácter utilizando esta función de biblioteca. Transmite un
carácter al dispositivo de salida standard (típicamente el monitor).
En general una referencia a esta función se escribe: putchar(variable de carácter);
Ejemplo de un programa:
#include <stdio.h>
void main()
{
int ic;
ic=getchar();
putchar(ic);
}
La funcion putchar() se ha escrito para que devuelva un valor EOF (fin de archivo) siempre
que tenga lugar una condicion de error. Se puede utilizar el siguiente codigo para comprobar una
condicion de error de salida. Debido a que EOF se comprueba en la salida, puede parecer un poco
confuso, aunque es técnicamente correcto.
If(putchar(ic) == EOF)
printf(“Ha ocurrido un error escribiendo en stdout”);
M. C. Bertha López Azamar Modulo 4 pag. 18
scanf().- Esta función se puede utilizar para la introducción de cualquier combinación de valores
numéricos o caracteres.
En términos generales la función scanf se escribe: scanf(cadena de control, arg1,arg2,...,argn);
Donde cadena de control hace referencia a una cadena de caracteres que contiene cierta
información sobre el formato de los datos y arg1,arg2,...,argn son argumentos que representan los
datos. (En realidad los argumentos representan punteros que indican las direcciones de memoria en
donde se encuentran los datos. ).
En la cadena de control se incluyen grupos de caracteres, uno por cada dato de entrada. Cada
grupo debe comenzar con el signo de porcentaje, que irá seguido, en su forma más sencilla, de un
carácter de conversión que indica el tipo de dato correspondiente.
Carácter de
conversión
Significado
c El dato es un carácter.
d El dato es un entero decimal.
e El dato es un valor en coma flotante.
f El dato es un valor en coma flotante.
g El dato es un valor en coma flotante.
h El dato es un entero corto.
i El dato es un entero decimal, octal o hexadecimal.
o El dato es un entero octal.
s El dato es una cadena de caracteres.
u El dato es un entero decimal sin signo.
x El dato es un entero hexadecimal.
[...] El dato es una cadena de caracteres que puede incluir caracteres de espaciado.
Cada nombre de variable debe ir precedido por un ampersand (&).
Los datos que se introducen deben corresponderse en tipo y orden con los argumentos de la función
scanf.
Ejemplo de utilización de scanf:
int i;
float j;
scanf("%d %f ",&i,&j);
Al introducir dos o más datos, éstos deben ir separados por caracteres de espaciado (el
carácter de nueva línea se considera como un carácter de espaciado).
Los caracteres consecutivos que no sean de espaciado componen un dato. Es posible limitar el
número de los caracteres especificando una longitud máxima para ese dato. El dato puede estar
compuesto por menos caracteres de los que especifique la longitud y no se leerán los caracteres que
estén más allá de dicha longitud. Hay que tener en cuenta que en este caso los caracteres sobrantes
pueden ser interpretados de manera errónea para el siguiente dato. (ya que caen en el buffer).
Ejemplos: scanf("%3d %3d %3d",&a,&b,&c);
Si los datos se introducen: 1 2 3 las asignaciones que se llevan a cabo son: a=1, b=2, c=3
Si se introducen 123 456 789 las asignaciones son: a=123, b=456, c=789
M. C. Bertha López Azamar Modulo 4 pag. 19
Si se introduce 123456789 las asignaciones son: a=123, b=456, c=789
Si se introduce 1234 5678 9 las asignaciones son: a=123, b=4, c=567 y los otros dos
dígitos restantes (8 y 9) se ignoran, a no ser que se lean a continuación en otra sentencia scanf.
La mayoría de las versiones de C permiten que ciertos caracteres de conversión en la cadena
de control sean precedidos por un prefijo de una sola letra. Así, una l se utiliza para indicar un
argumento entero largo con o sin signo. Una h se utiliza para indicar un argumento entero corto con
o sin signo
printf().- Se pueden escribir datos en el dispositivo de salida standard utilizando la función de
biblioteca printf. Es análoga a la función scanf, con la diferencia que su propósito es
visualizar datos en vez de introducirlos.
En general la función printf se escribe: printf(cadena de control, arg1,arg2,...,argn);
En contraste con la función scanf() los argumentos en la función printf() no representan
direcciones de memoria y por tanto no van precedidos de ampersands.
Se puede especificar una longitud mínima anteponiendo al carácter de conversión un entero
sin signo. Si el número de caracteres del dato correspondiente es menor que la longitud especificada,
entonces el dato será precedido por los espacios en blanco necesarios para que se consiga la longitud
especificada. Si el número de caracteres del dato excede la longitud especificada, se visualizará el
dato completo. Esto es justo lo contrario al comportamiento del indicador de longitud en la función
scanf(), que especifica una longitud máxima. También es posible especificar el máximo número de
cifras decimales para un valor de coma flotante. Esta especificación se denomina precisión. La
precisión es un entero sin signo que siempre es precedido por un punto decimal. Un número en
coma flotante se redondeará si se debe recortar para ajustarse a la precisión especificada.
Ejemplo:
#include <stdio.h>
void main()
{
int entero;
double real;
printf(“Introducir un número entero y un numero real: \n”);