Vous êtes sur la page 1sur 29

76

Chapter 5
Funciones
5.1 Introducci on
En este captulo estudiaremos una de las capacidades mas importantes de cualquier lenguaje de
programacion estructurado: las funciones. Conjuntamente con las sentencias de control de ujo, son
las dos estructuras que hacen de C un lenjuage apropiado para redactar programas estructurados.
Las funciones, como se las denomina en C, tambien llamadas subrutinas en FORTRAN o Basic, o
modulos o subprogramas en Pascal, son subprogramas dise nados y redactados con el prop osito de
realizar un tarea unica y especca.
5.2 Programacion estructurada y funciones en C
El paradigma de programacion que utilizamos en este curso es el denomnado programacion es-
tructurada. La programacion estructurada nos permite organizar nuestros programas de manera
que sean faciles de leer, entender y modicar. C posee los mecanismos b asicos para programar en
froma estructurada. En particular, las sentencias de selecci on y repetici on. Un tercer mecanismo de
importancia capital es la capacidad de proveer de funciones, el tema de este Captulo.
La programacion estructurada obedece una serie de reglas, a saber
el programa tiene dise no modular
los modulos tienen dise no descendente
la codicacion usa solo las siguientes estructuras b asicas
secuencias
selecion
repetici on
Seg un Dijkstra, la programacion estructurada sigue el siguiente conjunto de reglas
rescursos abstractos
dise no descendente
estructuras b asicas
Por dise no descendente se entiende a la descomposicion del problema en una serie de niveles o
pasos de renamiento sucesivo. Los pasos de un nivel est an relacionados con los pasos de un nivel
subordinado mediante las entrada y salidas
78
La programacion modular estable que el programa debe subdividirse en modulos de jerarqua
descendente, comenzando con un unico modulo, el modulo o programa principal. Este llama a su vez
a submodulos o subprogramas, subrutinas o funciones, que a su vez pueden llamar a otros del mismo
tipo. Los distintos modulos son totalmente independdientes unos de otros y no tienen acceso a sus
respectivos datos. Terminada la tarea devuelven el control del programa al modulo que los llamara.
Este metodo se ha denominado con el nombre de la estrategia poltico/militar atribuida a los romanos
divide y venceras o divide y reina, (derivada del latin divide et impera ), aunque mayormente
aplicada por el Imperio Brit anico
Hasta ahora hemos trabajado con un unico modulo o funci on, la funci on de maxima jerarqua, la
funci on main. No obstante, implcitamente hemos usado otras funciones, tales como la funci on printf
o scanf y alguna de las funciones matematicas.
Esto nos lleva a hablar de dos tipos de funciones que llamaremos aqu
Funciones intrnsecas o funciones de libreras estandard
1
.
Funciones denidas por el usuario.
Le llamamos funciones intrnsecas a aquellas que de alguna manera vienen provistas por la versi on
de C que usted utiliza. La otra categora se reere a las funciones programadas por cada programador
y aprenderemos a escribirlas y usarlas.
Antes de entrar en detalles analicemos el siguiente ejemplo a los efectos de comparar el uso de funciones
intrinsecas, en particular las matematicas y el uso de funciones del programador.
5.2.1 Ejemplo: uso de funciones estandar
Consideremos el caso en que la tarea de un programa es producir una tabla con los valores de x
i
vs.
f(x
i
) para una secuencia de valores de x dada por x
i
= x
i1
+ dx i = 1...N con x
0
= x0 un valor
conocido y dx
Por ejemplo, sea la funci on f(x) = x
3
, y queremos calcular los diez primeros pares (x, x
3
) desde x = 0
a x = 10 con incrementos dx = 1. La tabla resultante sera el conjunto de pares ordenados (0, 0),
(1, 1),(2, 8),(3, 27),(4, 64),(5, 125),(6, 216),(7, 343),(8, 512),(9, 729),(10, 1000)
El siguiente programa realiza el c alculo necesario
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 main()
5 {
6 float x0,xf,x,dx;
7 x0=0.;
8 xf=10.;
9 dx=1.;
10 x=x0;
11 for (x=x0;x<=xf;x+=1)
12 printf("%f %f\n",x,pow(x,3.));
13 return;
14 }
El programa tiene, ademas de la declaracion e inicializacion de la variables usadas, dos aspectos a
notar: el lazo de repetici on en la lnea 11 y el c alculo de la funci on en la lnea 12. El programa es tan
sencillo por que existe ya programada la funci on intrnseca pow() (y la funci on printf) y solo hizo
falta llamarla a ejecuci on.
La salida del programa fon mismo es la siguiente
1
Tal vez el nombre es mas apropiado en otros lenguajes que en C
cursoC/curso/funciones.tex -August 24, 2012 79
Figure 5.1: transferencia de control
cardonviejo@cardo:~/cardon/A-cursos/cursoC/curso> ./fon
0.000000 0.000000
1.000000 1.000000
2.000000 8.000000
3.000000 27.000000
4.000000 64.000000
5.000000 125.000000
6.000000 216.000000
7.000000 343.000000
8.000000 512.000000
9.000000 729.000000
10.000000 1000.000000
En el ejemplo anterior, la estructura simple del programa deriva del hecho que el c odigo que calcula
la funci on potenciacion es transparente al usuario, es decir el usuaro no lo ve, ni necesita hacerlo.
Este c odigo fue precompilado y almacenado en alguna librera de funciones y luego ensamblado y
almacenado con el resto del programa en la etapa de compilaci on. No obstante, el conocimiento de
todos estos detalles no son necesarios al escribir el programa principal, solo es necesario saber que en
tiempo de ejecuci on, o tiempo de maquina, cuando el programa este corriendo y la secuencia llegue a
la sentencia de llamada a la funci on ( pow(),
printf("%f %f\n",x,pow(x,3.));
el programa devolvera en su lugar el valor correspondiente a la potencia calculada.
El funcionamiento de un programa cuando llama a ejecutar a la funcion es como sigue: alcanzada la
sentencia de llama a la funci on, o dicho de otra manera, cuando la funci on es invocada, el programa
transere control al c odigo de denicion de la misma. Tambien se copian los datos o argumentos a
nuevas posiciones de memoria asequibles a la funci on.
Transferido el control a la funci on, esta trabaja como un programa independiente. Se reserva lugar
para las variables en ella denidas y se ejecutan las sentencias de la funci on misma hasta encontrar
una sentencia return, o el n del bloque de denicion de la funci on. En este punto, se transere el
control al programa que llamo la funci on, en este caso al programa principal, al mismo lugar de donde
fuera llamado la funci on y se hace le diponible all el valor de retorno, que podra ser usado como
cualquier expresion dentro de la sentencia de llamada.
La gura 5.1 muestra un esquema del proceso de transferencia de control y retorno.
5.2.2 Ejemplo: programacion de la funcion x
3
Consideremos ahora el mismo caso pero programemos la funci on x
3
. El programa principal sera el
mismo, con la unica diferencia que, en ves de llamar a pow(x,3.) llamaremos nuestra propia funci on
pow3(x)
80
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 main()
5 {
6 float x0,xf,x,dx;
7 x0=0.;
8 xf=10.;
9 dx=1.;
10 x=x0;
11 for (x=x0;x<=xf;x+=1)
12 printf("%f %f\n",x,pow3(x));
13 return;
14 }
Ahora, debe escribirse el c odigo correspondiente al c alculo de x
3
. La siguiente funci on es adecuada
para ello oat pow3(oat x) return x*x*x;
Por ultimo debemos observar los siguiente. Antes de usar la funci on, debe indicarse al preprocesador
como se usa la funci on, inclyendo, antes de la sentencia main el prototipo de la funci on. El proptotipo
de la funci on es similar al encabezado de la funci on en su declaracion, seguido del terminador.
float pow3(float x);
o
float pow3(float);
Por ultimo, todas las piezas juntas:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 float pow3(float);
5
6 main()
7 {
8 float x0,xf,x,dx;
9 x0=0.;
10 xf=10.;
11 dx=1.;
12 x=x0;
13 for (x=x0;x<=xf;x+=1)
14 printf("%f %f\n",x,pow3(x));
15 return;
16 }
17 float pow3(float x)
18 {
19 return x*x*x;
20 }
5.2.3 Ejemplo: programacion de una funcion
Consideremos ahora el mismo caso pero con una funci on arbitraria, por ejemplo sea la funci on i(t)
denida como sigue
i = i
m
e
Rt/2L
sin(2f
1
t) (5.1)
con
i
m
= 2f
2
0
Q/f
1
(5.2)
cursoC/curso/funciones.tex -August 24, 2012 81
f
0
=
1
2

(1/LC) (5.3)
f
1
=
1
2

(1/LC R
2
/4L) (5.4)
con Q, R, C, L, todas constantes conocidas.
Hemos elegido una funci on mas complicada con el prop osito de hacer mas evidente, la estructura y
simpleza que ofrece el uso de funciones.
Ahora, nuestro programa debe incluir el c alculo de la funci on dentro del lazo de control. Una posible
implementacion del c alculo es la siguiente:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 main()
5 {
6 float i,t,dt;
7 float t0,tf;
8 float im,f0,f1;
9 float pi=3.141516;
10 float factora;
11 float Q,R,C,L;
12 Q=0.00001;
13 R=1.;
14 C=0.00001;
15 L=0.002;
16 t0=0.;
17 tf=0.01;
18 dt=0.00001;
19
20 factora=1./(2.*pi);
21 f0=factora *sqrt(1./(L*C));
22 f1=factora *sqrt(1./(L*C) - R*R/(4.*L));
23 im=2.*pi * f0*f0 *Q /f1;
24 for (t=t0;t<=tf;t=t+dt)
25 {
26 i=im* exp(- R*t/(2.*L))* sin(2.*pi *f1*t);
27 printf("%f %e\n",t,i);
28 }
29 return;
30 }
En esta implementacion, la funci on i(t) se cacula ahora dentro del bloque del lazo for, en la lnea
26. las constantes se calcularon antes de comenzar el lazo. Si bien esto evita la repetici on innecesaria
de las tres constantes, se quita estructura al programa, al mantener en forma simult anea la logica del
proceso de generaci on de la tabla, la sentenca de repetici on en este caso, con los detalles del c alculo
de la funci on. Otra forma de programa hubiera sido la siguinete, en la que se aumenta estructura,
aunque se repite el c alculo de las constantes
20 for (t=t0;t<=tf;t=t+dt)
21 {
22 factora=1./(2.*pi);
23 f0=factora *sqrt(1./(L*C));
24 f1=factora *sqrt(1./(L*C) - R*R/(4.*L));
25 im=2.*pi * f0*f0 *Q /f1;
26 i=im* exp(- R*t/(2.*L))* sin(2.*pi *f1*t);
27 printf("%f %e\n",t,i);
28 }
82
Ahora, si dispusieramos de una funci on que calcule i(t) seg un las ecuaciones ?? a ??, que podemos
llamar por ejemplo fonelec(t), podriamos usarla de la misma manera que hicimos en el ejemplo
precedente y volver a la simplicidad de su programa principal. Tal implementacion luce como el
siguiente programa
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 // falta la declaracion de la funcion fonelec(t)
5 main()
6 {
7 float i,t,dt;
8 float t0,tf;
9 t0=0.;
10 tf=0.01;
11 dt=0.00001;
12 for (t=t0;t<=tf;t=t+dt)
13 printf("%f %e\n",t,fonelec(t));
14 return;
15 }
16 // falta la definicion de la funcion fonelec(t)
Nuevamente, en las lneas 12 y 13 se programa la impresion de la tabla. como argumento de printf
se llama al calculo de fonoe(t). El calculo mismo de la funci on i(t) ser realiza en otra funci on, en
otra parte del programa.
Ahora nos queda la tarea de implementar la funci on fonoe. Adelant andonos a la descripcion de los
detalles y la formalizaci on, presentaremos el programa fonoele-2 en donde se hizo la implentacion
requerida
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4
5 float fonoe(float t);
6 main()
7 {
8 float t,dt;
9 float t0,tf;
10 t0=0.;
11 tf=0.01;
12 dt=0.00001;
13
14 for (t=t0;t<=tf;t=t+dt)
15 printf("%f %e\n",t,fonoe(t));
16
17 return;
18 }
19 float fonoe(float t)
20 {
21 float i;
22 float im,f0,f1;
23 float pi=3.141516;
24 float factora;
25 float Q,R,C,L;
26 Q=0.00001;
27 R=1.;
28 C=0.00001;
29 L=0.002;
cursoC/curso/funciones.tex -August 24, 2012 83
30 factora=1./(2.*pi);
31 f0=factora *sqrt(1./(L*C));
32 f1=factora *sqrt(1./(L*C) - R*R/(4.*L));
33 im=2.*pi * f0*f0 *Q /f1;
34 i=im* exp(- R*t/(2.*L))* sin(2.*pi *f1*t);
35 return i;
36 }
La nueva funci on fonoe(t) se declara en la lnea 5, se ha denido en las lneas 19 a 36 y se llama en
la lnea 15.
El resultado del programa, la tabla requerida, ha sido archivado y se muestra gracado en la gura
5.2.3
5.2.4 Ejemplo: calculo de la conductividad promedio
Las tareas especcas de una funci on son de muy variada naturaleza. Por ejemplo, en nuestro programa
de vol umenes de control que presentaremos mas adelante, se requiere calcular las conductancias D
e
entre dos nodos seg un la siguiente expresion
D
e
= k
e
y
x
e
(5.5)
La conductividad k
e
debe calcularse en las caras entre vol umenes de control y para ello es com un
promediar el valor de la propiedades de nodos aleda nos, llamemoslos k
1
y k
2
. Se usa el promedio
aritmetico
k =
k
1
+ k
2
2
(5.6)
y mejor a un la media armonica
k =
2k
1
k
2
k
1
+ k
2
(5.7)
La siguiente es una implementacion del c alculo de estos coecientes como aparecera en un verdadero
programa. Pare el promedio aritmetico
for( j=1;j<=Ny;j++)
for( i=1;i<=Nx;i++)
{De[i][j] = 0.5*(kna1[i][j]+kna1[i+1][j]) *dy / dxe;
Do[i][j]= 0.5*(kna1[i][j]+kna1[i-1][j]) *dy / dxo;
Dn[i][j] = 0.5*(kna2[i][j]+kna2[i][j+1]) *dx / dyn;
Ds[i][j]= 0.5*(kna2[i][j]+kna2[i][j-1]) *dx / dys;
}
y para la media armonica.
for( j=1;j<=Ny;j++)
for( i=1;i<=Nx;i++)
{De[i][j] = 2*kna1[i][j]*kna1[i+1][j]/(kna1[i][j]+kna1[i+1][j]) *dy / dxe;
Do[i][j]= 2*kna1[i][j]*kna1[i-1][j]/(kna1[i][j]+kna1[i-1][j]) *dy / dxo;
Dn[i][j] = 2*kna2[i][j]*kna2[i][j+1]/kna2[i][j]+kna2[i][j+1]) *dx / dyn;
Ds[i][j]= 2*kna2[i][j]*kna2[i][j-1]/(kna2[i][j]+kna2[i][j-1]) *dx / dys;
}
Para cambiar de uno a otro promedio hace falta cambiar la programacion anterior. En cambio, si
dispusieramos de una funci on que haga la tarea de promediar, por ejemplo la funci on fmedia, que
podra llamarse como
84
fmedia(k1,k2)
ambos c odigos precedentes estaran igualmente representados por el siguiente
for( j=1;j<=Ny;j++)
for( i=1;i<=Nx;i++)
{De[i][j] = kmedia(kna1[i][j],kna1[i+1][j]) *dy / dxe;
Do[i][j]= kmedia(kna1[i][j],kna1[i-1][j]) *dy / dxo;
Dn[i][j] = kmedia(kna2[i][j],kna2[i][j+1]) *dx / dyn;
Ds[i][j]= kmedia(kna2[i][j],kna2[i][j-1]) *dx / dys;
}
La funci on kmedia encapsula el c odigo para hacer el promedio. Si hiciera falta cambiarlo, solo habra
que cambiar el c odigo de la funci on, sin que sea necesario tocar el el programa principal.
5.2.5 Ejemplo: una funcion para impresion de matrices
Para imprimir un vector o una matriz, resultado de nuestros c alculos, o para resolver un sistema de
ecuaciones algebraicas, o para calcular los elementos de una matriz relacionada con un determinado
problema fsico, o para aplicar un determinado procesamiento a una im agen digital, etc. La lista
podra seguir al innito.
5.2.6 Mas sobre la utilidad
El uso de funciones tiene muchas ventajas que enunciaremos luego, pero una de las fundamentales, es
que colaboran en realizar el dise no y la implementacion de un algoritmo complejo de manera modular
y estructurada. Permite organizar la resolucion de un problema complejo en sus distintas partes
constiuyentes. Estas partes pueden ser mas simples o a un mas complejas que el problema completo,
pero se pueden tratar en forma independiente, de manera que el programador puede concentrarse en
una tarea con objetivos mas delimitados.
Pongamos por ejemplo nuestro programa, que presentaremos mas adelante, para el tratamiento digital
de im agenes. Supongamos que el objeto del programa es restaurar una im agen aplicando una serie de
ltros. Existen varias tareas que deben realizarse: la lectura de la imagen, el c alculo del histograma
de la imagen, el ltrado de la imagen y generaci on de la imagen nueva.
Las tres tareas tienen en com un la estructura de datos con la que trabajaran, pero el tratamiento
que har an sobre estos datos es totalmente distinto en cada caso. La lectura de la im agen est a rela-
cionada con el acceso a un archivo con la informacion. La obencion del histograma de la im agen, esta
relacionada con un tratamiento estadstico de los niveles de gris de los pxeles de la imagen, mientras
que el ltrado de la im agen est a relacionado con la modicacion de los pxeles de la imagen. Por
ultimo la generaci on de la imagen est a relacionda con la escritura de un archivo. Las cuatro tareas
son totalmente diferentes, pero deben hacerse en orden, los datos con que trabaja cada tarea son
independientes de los datos requeridos por la otra, salvo los datos que deben compartir, que seran
transferidos al modulo superior mediante una iterface.
5.3 Errores comunes.
5.3.1 Que argumentos pasar a la funcion
Hemos dicho la funci on deebe realizar una tarea concreta, bien denida. Pongamos por caso de estudio
la evaluacion de la funci on
Esta es la conocida Ley de Planck- Los valores de C
1
, C
2
est an relacionados con constantes universales
de la fsica, y si bien, con los a nos, pueden reevaluarse a medida que se hacen mediciones o c alculos
cursoC/curso/funciones.tex -August 24, 2012 85
mas precisos, para un problema de aplicacion particuar, no cambiaran. En consecuencia, son parte
de la denicion de la funci on y no deben pasarse como argumentos.
Una posible implementacion de la funci on sera esta:
Por el contrario esta otra, si bien har a la misma tarea que la anterior, pasao dos argumentos innece-
sarios a la funci on. Esto, no solo usa mas recursos de lo necesario, sino resulta por lo general una
fuente adicional de errores.
5.3.2 Como nombrar los argumentos de las funciones
Como regla general, los nombres de las variables que se utilizan en un programa, deben estar rela-
cionados con el nombre de la cantidad que representan:
Conisderemos por ejemplo la siguiente relacion
Nu =
hD
k
(5.8)
donde Nu, el n umero de Nusselt, h es el coeciente de transferencia de calor, D es una longitud
caracterstica, a deducier de la notaci on es probablemente el diametro, k es la conductividad termica.
Probablemente, la interpretaci on en C mas adecuada es
1 float Nu,D,h,k;
2
3 Nu=h*D/k;
esta utiliza para las variables los mismos nombres que se utilizan comunmente para las cantidades
fsicas. La sentencia sera entendida inmediatamente por cualquir persona que conozca elproblema
fsico que se quiere resolver.
Se podra a nadir, para ayuda del lector menos experto, algunos comentarios con las deniciones de
las variables
1 float Nu,D,h,k;
2
3 // Nu numero de Nusselt, adimensional
4 // D diametro, m
5 // h coeficiente convectivo, W/m^2 K
6 // k conductividad termica, W/m K
7
8 Nu=h*D/k;
A un, a expensas de hacer nuestro programas mas verboso, podemos hacer nuestras variables mas
explicitas o autoreferentes
1 float Nusselt,Diametro,ceficiente_convectivo,kconductividad;
2
3 Nusselt=ceficiente_convectivo*Diametro/conductividad;
Estos nombres dar an origen a sentencias mas largas, lo que dicultara la lectura.
Por ultimo, debemos evitar utilizar nombres abstractos, sin relacion con el contexto del problema, por
ejemplo,
1 float u,v,w, x;
2
3 // u numero de Nusselt, adimensional
4 // v diametro, m
86
5 // w coeficiente convectivo, W/m^2 K
6 // x conductividad termica, W/m K
7
8 u=w*v/x;
este peque no c odigo, si bien raeliza el mismo c alculo que los anteriores, y salvo que usted tenga una
memoria privilegiada, es la receta para el desastre. Necesitar a llevar tablas de signicado todo a lo
largo de su programa y no podra leer y pensar sus sentencias en terminos fsicos, que es de la manera
que se supone piensa o pensar a usted muy pronto.
5.4 Las funciones estandard de C
Se denominan as
2
a aquellas funciones implementadas en alguna de las libreras est andares de C.
(Debe tenerse en cuenta que estas pueden ser distintas para UNIX o DOS).
La siguiente es la clasifacion de las subrutinas que hace Joyanez Aguilar:
Asignacion de memoria:
Manejo de Cadenas
Clasicaci on de caracteres
Calendario
Control de Directorios
Control de procesos
Conversion de datos
Entrada y salida
Bajo nivel
Consola y puertos
Gestion de archivos
Matem aticas
Manipulacion de bloques de memoria
Presentacion de texto
Cada vez que se requiere usar las funciones de estas libreras debe insertarse la directiva #include
correspondiente. En algunos casos el prototipo de una funci on est a en mas de un archivo de cabecera.
Es suciente que este solo unos de ellos.
La siguiente es una lista de las libreras disponibles para C, que llamaremos por el nombre del en-
cabezado
Librera de entradas y salidas: stdio, stdio.h
Librera estandar: stdlib, stdlib.h
Librera de funciones matematicas: math, math.h
completar
completar
completar
2
En realidad no hay funciones intrnsecas en el sentido estricto en C.
cursoC/curso/funciones.tex -August 24, 2012 87
5.5 Funciones matematicas estandard
Nos interesaremos aqu en las funciones matematicas disponibles en la librera math.
5.5.1 Funciones trigonometricas
acos double acos( double x) devuelve el arco coseno de x, que debe estar en el rango 1 y 1, el
resultado es el valor de un angulo en radianes.
asin dounble asin(double x); devuelve el arco eno de x
atan double atan(double x);
atan2 double atan(double y,double x,); Calcula el arco tangente de y/x
cos double cos(double x); Calcula el coseno de x, x debe estar en radiantes
sin double sin (double x);
tan double tan (double x);
Ejemplo
1 angulo_radianes= anggulo_grados * 2. * PI/ 360.;
2 g0=GSC * ( 1. + 0.033 * cos(angulo_radiantes) );
3
5.5.2 Funciones hiperbolicas
cosh double cosh(double x); Calcula el coseno hiperb olico de x, x debe estar en radiantes
sinh double sinh (double x);
tanh double tanh (double x);
5.5.3 Funciones de exponenciaci on y logartmicas
pow double pow(double x, double y);
sqrt double sqrt (double x);
exp double exp (double x);
log double log (double x); Logaritmo natural o neperiano
log10 double log10(double x); Logaritmo en base 10
hypot hypot(doublex,doubley); Calcula la hipotenusa de un triangulo rectangulo de lados x e y.
ldesp,ldespl double ldesp(double x,int exp); calcula el valor de xe
exp
Ejemplos:
f
0
=
1
2

(1/LC) (5.9)
f
1
=
1
2

(1/LC R
2
/4L) (5.10)
i
m
= 2f
2
0
Q/f
1
(5.11)
i = i
m
e
Rt/2L
sin(2f
1
t) (5.12)
88
f0=factora *sqrt(1./(L*C));
f1=factora *sqrt(1./(L*C) - R*R/(4.*L));
im=2.*pi * f0*f0 *Q /f1;
for (t=t0;t<=tf;t=t+dt)
i=im* exp(- R*t/(2.*L))* sin(2.*pi *f1*t);
Ejemplo
a = x
3
(5.13)
a=pow(x,3.);
5.5.4 Maximos y mnimos, valor absoluto
abs int abs( int x); Devuelve el valor absoluto de x. El argumento x debe ser un entero.
abs long int labs( long int x); Devuelve el valor absoluto de x. El argumento x debe ser un entero.
fabs double fabs( double x); Devuelve el valor absoluto de x. El argumento x puede ser un doble o
un otatnte.
fabsl long double fabsl( long double x); Devuelve el valor absoluto de x.
max (tipo) manx(a,b); devuelve el mayor de dos valores, necesita conio.h ojo!
min (tipo) min(a,b); devuelve el menor de dos valores, necesita sdtlib.h
ceil double ceil(double x) Redondea a un entero por exceso
oor double oor(double x) Redondea a un entero por defecto
fmod double fmod(double x,double y)calcula el resto de la divisi on real x/y.
5.5.5 Funciones aleatoria
rand int rand(void); Genera un n umero pseudoaleatorio entre 0 y RAND
M
AX;
random int random(int x); Genera un n umero aleatorio entre 0 y x 1
randomize void randomize()void; Inicializa el generador de n umeros aleatorios.
srand srand()unsigned x); Inicializa le generador de nueros aleatorios con la semilla x.
5.5.6 Compilacion con funciones matematicas
Las funcions matematicas requieren el uso del encabezado <math.h>, ademas, deben compilarse con
la opcion -lm, como se muestra en el ejemplo siguiente
1 >gcc -o nombre nombre.c -lm
5.5.7 Ejemplo: funciones trigonometricas. Radiaci on solar extraterrestre
Consideremos el problema de calcular la la radiaci on solar extraterrestre. (Due y Beckman, Solar
Engineering of Thermal Processes, Wiley 1980) A los efectos practicos, la radiaci on que emite el sol
se considera constante. La radiaci on del sol que llega a la tierra, debido a la variacion de la distancia
tierra-sol, depende con el tiempo. La siguiente ecuaci on muestra la dependencia de la radiaci on solar
extraterrestre con el dia del a no,
G
on
= G
sc
(1 + 0.0033 cos(x)) (5.14)
cursoC/curso/funciones.tex -August 24, 2012 89
con
x =
360n
365
en grados (5.15)
y
G
on
radiaci on extraterrestre sobre plano normal, W/m
2
G
sc
constante solar, 1395. W/m
2
n n umero de dia del a no
(5.16)
Basicamente es una funci on cosenoidal cuyo argumento x est a relacionado con los das del a no.
Las funciones trigonometricas requieren como argumento el angulo en radianes y retorna un valor
comprendido entre 1 < cos(x) < 1. Si se dipone del angulo en grados, debe hacerse la siguinet
conversi on
rad = grad 2. PI/360. (5.17)
.
El siguiente programa implenta el c aculo de G
on
en funci on de n, el da del a no.
1 #include <stdio.h>
2 #include <math.h>
3 #define PI 3.1415
4 #define GSC 1353.
5 // GSC constante solar, W/m^2, DyB, pp 4.
6
7 float Gon(int n);
8
9 main()
10 {
11 // radiacion extraterrestre sobre plano horizontal
12 // DyB, pp 22, ec. 1.8.1
13
14 // ang angulo engrados
15 // g0 radiacion extraterrestre, W/m^2
16
17 float g0,ang,angrad;
18 int n;
19 for (n=1;n<=365;n++)
20 {
21 ang=360.* n / 365.; // DyB angulo en grados
22 angrad= ang * 2. * PI/ 360.; // angulo en radianes
23 g0=GSC * ( 1. + 0.033 * cos(angrad) );
24 printf("%d %f \n",n,g0);
25 }
26 }
El programa hace un lazo sobre los dias del a no y para cada uno calcula G
on
. La salida del programa
puede derivarse a un archivo y gracarse con gnuplot. La gura ?? muestra la evoluci on anual de la
radiaci on extraterrestre calculada por el programa de arriba
5.6 Funciones denidas por el usuario ORGANIZAR MEJOR
Hemos visto que las funciones intrnsecas vistas precedentemente se han usado para realizar tareas
sumamente especcas, tan denidas como calcular la funci on seno o la funci on exponencial, o mandar
una salida a la impresora o a la pantalla y que son de utilidad com un a muchsimas aplicaciones.
En el desarrollo de una aplicacion o software particular, existen muchas tareas especcas que se real-
izan frecuentemente o que se pueden reutilizar en otros programas. Por ello, casi todos los lenguajes de
programacion disponen la capacidad de programa funciones tambien llamadas modulos o subrutinas.
Las funciones no son otra cosa que un programa que realiza una tarea especca. Nos sirvan para
90
1300
1310
1320
1330
1340
1350
1360
1370
1380
1390
1400
0 50 100 150 200 250 300 350 400
G
on
n
dat
Figure 5.2: La funci on radiaci on extraterrestre sobre plano normal.
modularizar un programa
evitar repeticiones de c odigo,
asegurar claridad y logica a nuestro programa
aumentar la reusabilidad
aumentar la portabilidad
En este curso presentaremos dos ejemplos de usos de conjuntos subrutinas: en el captulo ?? una
referida a las propiedades termodinamicas del aire h umedo y en el captulo ??, otra referida al
tratamiento digital de im agenes. Presentaremos tambien en el captulo ?? un programa para el
c alculo de la conduccion bidimensional de calor organizado en forma modular mediante funciones.
5.6.1 Denicion de una funcion
Antes que nada recordemos que la funci on main que estuvimos programando hasta ahora, es una
funci on, de manera que su programacion no es enteramente nueva para nosotros.
Como las variables, las funciones deben denirse y deben declararse.
En la denicion de una funci on intervienen el nombre, una lista de argumentos, un valor de
retorno y un cuerpo.
En la declaracion, llamada prototio de la funcion intervienen nombre, una lista de argumentos,
un valor de retorno.
Para ser ejecutadas, las funciones se llaman o referencias o invocan desde el programa principal o
desde otras funciones.
Las funciones se llaman por su nombre. El nombre de la funci on puede empezar por un gui on bajo o
cualquier letra may uscula o min uscula. El nombre puede contener n umeros tambien. Como en todo
C, las letras may usculas y min usculas son distintas. No se pueden usar para los nombres de funciones
las palabras reservadas. El n umero de caracteres del nombre de una funci on no est a limitado por el
lenguaje, no obstante a partir de caracter 32 el compilador no est a obligado a distinguir los nombres.
Algunos ejemplos de nombres admisibles:
cof(...)
cursoC/curso/funciones.tex -August 24, 2012 91
kmedia(...)
_modulo
leer(...)
leer_numero(...)
leerCodigo(...)
LeerCodigo(...)
fon1()
fon2(...)
Debido al ambito de visibilidad de las funciones (global) sus nombres no pueden utilizarse de ninguna
otra manera dentro de todo el ambito del programa.
El retorno es el valor que la funci on devuelve al ser invocada, de la misma manera que las funciones
intrnsecas que vimos arriba devuelven un valor al ser llamadas.
Para que una funci on retorne se utiliza la sentencia return con la expresion de retorno como argu-
mento.
return a+b;
return x;
return;
En la ultima lnea se ejemplica el retorno vaco.
El cuerpo de la funci on es donde se programa la tarea que debe hacer o donde se eval ua el valor de
retorno. Permite:
realizar la tarea especca de la funci on.
evaluar el valor de retorno
La lista de argumentos es un lista de datos (valores por ahora) con los que la funci on trabajara.
Las funciones pueden denirse en cualquier lugar del programa, arriba o abajo de la funci on main, o
en un archivo separado. La declaraci on de la funci on, en cambio, siempre debe estar antes de que la
funci on se dena. Usualmente declaramos las funciones arriba del main. Las declaracion de funciones
hechas en archivos separados se escriben al comienzo del archivo.
La denicion de un funci on consiste en una primera lnea en donde se da el nombre de la funci on, se
especica el tipo de la variable de retorno y se da la lista de argumentos. A continuacion del nombre,
se programa el cuerpo de la funci on. El siguiente es un ejemplo que muestra la estructura de una
funci on
(tipo) nombre (tipo arg1, tipo arg2.. )
{
cuerpo de la funci\on
.
.
return variable de retorno;
}
Una funci on a su vez puede llamar a otras funciones.
Las funci ones deben declararse, esto se hace antes del main, copiando la primera lnea de denicion
de la funci on. La declaracion, al contrario de la primera lnea de la funci on, debe terminar en dos
puntos. En la declaracion de la funci on no hace falta escribir el nombre de la variable, solo el tipo.
3
(tipo) nombre (tipo , tipo , ... )
3
Salvo en el caso de los arreglos que veremos luego
92
5.6.2 Acceso a una funcion
La funci on se llama o invoca desde otra funci on del programa, que puede ser la funci on main o
cualquier otra.
Por ejemplo
1 #include <stdio.h>
2 int mifuncion (int);
3 main()
4 {
5 int a1,a2,b;
6 b=5;
7 a1= mifuncion(b);
8 a2= mifuncion(b)*2;
9 printf("b=%d a1=%d a2=%d \n",b,a1,a2);
10 }
11 int mifuncion( int x)
12 {/* esta es la definicion de la funcion mifuncion */
13 /* la funcion toma x, y lo devuelve multiplicado por 2*/
14 x=x*2;
15 return x;
16 }
la salida de este programa es la siguiente
cardon@cardo:~/A-cursos/cursoC/curso> ./mf
b=5 a1=10 a2=20
cardon@cardo:~/A-cursos/cursoC/curso>
En la lnea 2 se declara la funci on mifuncion. Observe que la declaracion o prototipo de la funci on
lleva el terminador punto y coma. Ademas no se ha indicado el nombre de la variable entera del
argumento. En la lnea 7 se invoca la funci on. El valor retornado por la funci on se asigna a la variable
a1. En la lnea 8, en cambio se utiliza el valor de retorno de la funci on para hacer una operaci on
aritmetica, se lo multiplica por dos, luego se asigna a la variable a2. En la lnea 11 y hasta la lnea 17
se dene la funci on.
5.6.3 Argumentos
Hemos visto que al llamarse una funci on se le pasa ciertos valores, variables o contantes, que de-
nominamos argumentos reales. Por otro lado, en la denicion de la funci on, se ha dado nombre
a las variables que de entrada a la funci on, y a estas se las denomina par ametros o argumentos
formales. Para claricar la nomenclatura voy a repetir el c odigo anterior utilizando la nomenclatura
introducida.
Programa mf.c en A-cursos/cursoC/curso
1 #include <stdio.h>
2 int mifuncion (int);
3 main()
4 {
5 int a1,a2,b;
6 b=5;
7 /* cuidado, esto no puede programarse asi
8 a1= mifuncion(argumento real o aparametro b);
9 a2=2*mifuncion(argumento real o aparametro b);
10 */
cursoC/curso/funciones.tex -August 24, 2012 93
11 printf("b %d a1 %d a2 %d \n",b,a1,a2);
12 }
13 /* Cuidado, esto no puede programarse as
14 int mifuncion( int argumento formal x)
15 */
16 {/* esta es la definicion de la funcion mifuncion */
17 /* la funcion toma x, y lo devuelve multiplicado por 2*/
18 x=x*2;
19 return x;
20 }
Existe una correspondencia uno a uno entre los argumentos reales y los formales, no obstante, ambos
son entidades distintas.
Los argumentos reales son constantes o variables declaradas en el bloque de c odigo (el bloque de
denicion del main, por ejemplo) desde donde se llama a la funci on. En cambio los argumentos
formales son variables que solo tienen existencia dentro de la funcion.
Cuando se llama una funci on, se hace una copia de los argumentos reales y esta copia es asignada a los
argumentos formales. De manera que en realidad no hay ninguna coneccion entre unos y otros. Esto
asegura independencia entre las variables que usamos como argumentos en las funciones y la variables
al las cuales se copia los valores de las primeras.
Cuando los argumentos formales se modican, no implica que se modican los argumentos reales.
A este tipo de paso de argumentos se le denomina por valor.
A traves de las variables o constantes en la lista de argumentos, el programa principal o el que llama
a la funci on podra darle datos a la misma.
En el ejemplo anterior, cuando en el programa principal se llama a la funci on, se especica un argu-
mento real. Cuando el control pasa a la funci on, esta hace una copia del valor real, de la variable real
y este valor se asigna a la variable o argumento formal, que es el que se usa dentro de la funci on.
5.6.4 Ejemplo
En el siguiente ejemplo se han programado tres funciones,
lee: solilicita la entrada e un valor por teclado
cuadrado: calcula el cuadrado del argumento
imprime imprime el valor del argumento
El programa llama a la funci on lee mediante la cual se le asigna un valor a la variable b. La funci on
lee no necesita argumento por tanto la lsita entre arentecis es nula, est a vaca. Luego se llama a
la funci on cuadrado que calcula el cuadrado de b. El valor retornado se asigna a la variable b. Por
ultimo se llama a la funci on imprime para que imprima el valor actual de b.
Oservese que, como la funci on imprime no requiere retornar ning un valor la funci on que la llama, en
su declaracion est a precedida del tipo void, vaco, es para indicar justamente esto, que no habr a valor
de retorno.
Debe tenerse en cuenta que a diferencia de otros lenguajes de programacion (en particulat fortran, no
se puede usar el nombre de la funci on como nombre de la variable de retorno.
1 #include <stdio.h>
2
3 float lee();
4 float cuadrado(float);
5 void imprime(float);
6
94
7 main()
8 {/* mf2.c */
9 float b;
10 b=lee();
11 b=cuadrado(b);
12 imprime(b);
13 }
14
15 float lee()
16 {
17 /* lee un valor del teclado*/
18 float x;
19 printf("Entre un flotante \n");
20 scanf("%f",&x);
21 return x;
22 }
23 float cuadrado(float x)
24 {
25 /* calcula el cuadrado de x*/
26 x=x*x;
27 return x;
28 }
29 void imprime(float x)
30 {
31 printf("%f\n",x);
32 }
5.7 Visibilidad de las variables
Las variables denidas en una funci on, solo son visibles dentro de esa funci on
La visibilidad es la propiedad por la cual una variable es asequible solo dentro de un cierto entorno
del programa que depende del lugar de declaracion de la variable.
La variables se pueden declarar en distintos lugares
Arriba de la funci on main
Al comienzo de una funci on
En cualquier lugar dentro de una funci on
Al comienzo de un bloque de sentencias
5.7.1 Variables globales y locales
Una variable denida antes de la funci on main se denomina una variable global. Esto quiere decir
que puede ser accedida desde cualquier funci on. Se dice que la visibilidad de esta variable es global.
Es visible para todas las funciones del programa. Sus valores estan disponible y pueden ser cambiados
desde cualquiera de las funciones de un programa.
Salvo casos muy bien justicados, no es recomendable el uso de variables globales. Esto rompe con
todo intento de modularidad de un programa.
Por ejemplo, si una variable fue declarada en la funci on main su visibilidad est a restringida a esa
funci on. Esto quiere decir que la variable solo puede ser accedida desde dentro de esa funci on. Se
podran denir otras variables, con el mismo nombre en otras funciones,
Cualquier otro lugar de dinicion de una variable dda lugar a una variable local. Esto quiere decir
que tienen visibilidad parcial, restringida al bloque de sentencias donde fue denida.
cursoC/curso/funciones.tex -August 24, 2012 95
Ejemplo: variable local a un bloque
El siguiente ejemplo muestra una variable denida dentro de un bloque de sentencias dentro del main.
1 #include <stdio.h>
2 main()
3 {
4 int a=5;
5 printf("a en main %d\n",a);
6 {
7 int a=10;
8 printf("a en un bloque interno %d\n",a);
9 }
10 printf("a en main %d\n",a);
11 }
cuya salida es la siguiente
cardon@linux-pijg:~/A-cursos/cursoC/curso/programas> ./loca
a en main 5
a en un bloque interno 10
a en main 5
cardon@linux-pijg:~/A-cursos/cursoC/curso/programas>
Observe que la variable a denida en la lnea 4 mantiene su identidad y su valor (5) a pesar de que fue
denida otra variable a, inicializada con el valor 10 en la lnea 6 dentro del bloque entre las lneas 6 y
9. En este caso, la variable a denida en el bloque entre las lneas 6 y 9 tiene su visibilidad restringida
a ese mismo bloque.
El bloque de denicion de una variable puede ser el mismo bloque del cuerpo de una funci on.
Ejemplo:
El siguiente ejemplo esta dise nado para mostrar como una funci on copia los alrgumentos reales al
argumento formal, y los mantiene independdientes.
1 #include <stdio.h>
2 float lee();
3 void imprime(float);
4 void nada();
5 main()
6 {/* mf3.c */
7 float a;
8 a=lee();
9 printf("Valor de \"a\" dentro de la funcion \"main\" ");
10
11 imprime(a);
12 nada();
13 }
14 float lee()
15 {
16 /* lee un valor del teclado*/
17 float x;
18 printf("Entre un flotante \n");
19 scanf("%f",&x);
20 return x;
96
21 }
22 void imprime(float x)
23 {
24 printf("%f\n",x);
25 }
26 void nada()
27 {/* Declara e inicializa a, e imprime su valor*/
28 float a=9999.;
29 printf("Valor de \"a\" dentro de la funcion \"nada\" ");
30 imprime(a);
31 }
Ejemplo:
El siguiente programa muestra la independencia entre los argumentos formales y los par ametros, aun
en el caso de que estos tengan el mismo nombre.
Se declara a y se la asigna un valor en el programa principal o funci on main. Esto se hace a traves
de la funci on lee. Se usa la variable a como argumento de la funci on real cambia. La cambia toma
este valor y se lo asigna a la variable formal tambien llamada a. Pero debe notarse que la variable a
en funci on main no cambia su valor aunque en la funcion cambia se haya cambiado el valor de a.
1 #include <stdio.h>
2
3 float lee();
4 void imprime(float);
5 void cambia(float);
6 main()
7 {/* mf4.c */
8 float a;
9 a=lee();
10 printf("main: Valor de \"a\", %f \n",a);
11 cambia(a);
12 printf("main: Valor de \"a\", %f \n",a);
13 imprime(a);
14 }
15 float lee()
16 {
17 /* lee un valor del teclado*/
18 float x;
19 printf("Entre un flotante \n");
20 scanf("%f",&x);
21 return x;
22 }
23 void imprime(float x)
24 {
25 printf("%f\n",x);
26 }
27 void cambia(float a)
28 {/* Declara e inicializa a, e imprime su valor*/
29 printf("funcion cambia: Valor de \"a\" introducido como par ametro %f \n",a);
30 a=9999.;
31 printf("funcion cambia: Valor de \"a\" luego de cambiarlo %f\n",a);
32 }
Se muestra aqu la salida del programa
cardon@cardo:~/A-cursos/cursoC/curso> ./mf4
cursoC/curso/funciones.tex -August 24, 2012 97
Entre un flotante
1234.
main: Valor de "a", 1234.000000
funcion cambia: Valor de "a" introducido como par ametro 1234.000000
funcion cambia: Valor de "a" luego de cambiarlo 9999.000000
main: Valor de "a", 1234.000000
1234.000000
cardon@cardo:~/A-cursos/cursoC/curso>
5.8 Visibilidad en programas y funciones en varios archivos
Es frecuente, que como paso previo a la creacion de una librera de funciones, se divida un programa
y las funciones asociadas en varios archivos en donde se agupan tematicamente las funciones involu-
cradas. Consideremos de nuevo las cuatro funciones que hemos usado en los ejemplos mf-1 a 4, estas
fueron
lee
imprime
cuadrado
nada
Las deniciones de estas subrutinas se incluyeron todas en el archivo llamado subvarias.c y sus
prototipos en el archivo subvarias.h.
El archivo subvarias.c as como el archivo donde recide el programa principal debe tener una sen-
tencia include que incluya el archivo de encabezados subvarias.h.
El listado siguiente muestra como queda el archivo con el programa principal, lamado mf5.c y el
archivo de encabezados subvarias.h y el archivo con las subrutinas, subvarias.h.
1 #include <stdio.h>
2 #include "mfsubs.h"
3
4 main()
5 {/* mf5.c */
6 float a;
7 a=lee();
8 printf("main: Valor de \"a\", %f \n",a);
9 cambia(a);
10 printf("main: Valor de \"a\", %f \n",a);
11 imprime(a);
12 }
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include "mfsubs.h"
4 float lee()
5 {
6 /* lee un valor del teclado*/
7 float x;
8 printf("Entre un flotante \n");
9 scanf("%f",&x);
10 return x;
11 }
12 float cuadrado(float x)
98
13 {
14 /* calcula el cuadrado de x*/
15 x=x*x;
16 return x;
17 }
18 void imprime(float x)
19 {
20 printf("%f\n",x);
21 }
22 void cambia(float a)
23 {/* Declara e inicializa a, e imprime su valor*/
24 printf("funcion cambia: Valor de \"a\" introducido como par ametro %f \n",a);
25 a=9999.;
26 printf("funcion cambia: Valor de \"a\" luego de cambiarlo %f\n",a);
27 }
28 void nada()
29 {/* Declara e inicializa a, e imprime su valor*/
30 float a=9999.;
31 printf("Valor de \"a\" dentro de la funcion \"nada\" ");
32 imprime(a);
33 }
34
1 float lee();
2 float cuadrado(float x);
3 void imprime(float x);
4 void cambia(float a);
5 void nada();
Para compililar con m ultiples archivos se utiliza el comando
cardon@cardo:~/A-cursos/cursoC/curso> gcc -o mf5 mf5.c mfsubs.c -lm
cardon@cardo:~/A-cursos/cursoC/curso>
5.8.1 Ejemplo: nuevamente la radiacion solar extraterrestre
Usaremos nuevamente el rpoblema de la secci on 5.5.7 para demostar el uso de funciones. Ahora se ha
programado el c alculo de G
on
en una funci on, con los que se gana mejor organizaci on y legibilidad.
La funci on Gon puede usarse en otros c alculos donde fuera necesaria. Eventualmente podra incluirse
en otro archivo, junto con otras funciones similares, o en una librera de subrutinas.
1 #include <stdio.h>
2 #include <math.h>
3 #define PI 3.1415
4 #define GSC 1353.
5 // GSC constante solar, W/m^2, DyB, pp 4.
6
7 float Gon(int n);
8
9 main()
10 {
11 int n;
12 for (n=1;n<=365;n++)
13 printf("%d %f \n",n,Gon(n));
14
15 }
16 float Gon(int n)
cursoC/curso/funciones.tex -August 24, 2012 99
17 {
18 // radiacion extraterrestre sobre plano horizontal
19 // DyB, pp 22, ec. 1.8.1
20
21 // ang angulo engrados
22 // g0 radiacion extraterrestre, W/m^2
23
24 float g0,ang,angrad;
25 ang=360.* n / 365.; // DyB angulo en grados
26 angrad= ang * 2. * PI/ 360.;
27 g0=GSC * ( 1. + 0.033 * cos(angrad) );
28 return g0;
29 }
5.9 Vida util de las variables
Las variables tienen lo que se llama vida util. La vida de las variables comienza cuando la secuencia
del programa alcanza su declaracion. En ese momento se reserva en memoria un lugar para la variable
en cuestion y se asocia el nombre a esa memoria. La variable cesa de existir cuando se alcanza el
nal dedl bloque donde se denion la variable. Terminada la vida util de una variable se recupera la
memoria reservada para ella.
Las variables locales tienen vida acotada por su bloque de denicion. Las variables denidas en una
subrutina, solo tenienen vida mientras se ejecuta la funci on. Luego de eso las variables desaparecen.
Las variables globales terminan junto con la ejecuci on de programa.
5.10 Paso de argumentos: paso por referencia
En las secci on 5.6.3 vimos como los argumentos reales se pasan a una funci on copiando su valor al
argumento formal correspondiente en la lista de variables incluida en la denicion de la subrutina.
Vimos que este tipo de paso de variables se denomina por valor.
Existe otra forma de pasar argumentos a una funci on, el paso por referencia. En el paso de ar-
gumentos por referencia, no se pasa el valor que tiene una variable sino su direcci on. Esto permite
modicar el contenido o valor de la variable referenciada.
Esta caracterstica es util sobremanera en dos casos:
Cuando es necesario que la subrutina produzca mas de un resultado que debe transferirse al
programa que la llama. Estos resultados se transeren al programa principal no como un retorno
de la subrutina sino a traves de las variables pasadas por referencia en la lista de ergumentos.
En el paso de arreglos a la funci on o desde la funci on. Puede suponerse que en la mayora de
los casos los arreglos tienen muchos elementos. Pasarlos a todos por copia sera una perdida de
tiempo importante, por ello, solo se pasa la direcci on de la cabecera del arreglo, haciendo asi
accesible a la funci on los posciones de los demes elementos.
La caracterstica que hace ultil el paso por referencia es tambien, en otros casos, su principal desven-
taja. Las variables pasadas por referencia y trabajadas en la funci on ya no est an aisladas del programa
principal y si sus valores son modicados inadvertidamente, la modicacion pasar a al programa prin-
cipal.
El paso por referencia se hace a travez del uso de dos operadores que introduciremos aqu. El operador
direccion de y el operador contenido de, no obstante, para una explicaci on coherente debemos
introducir tambien el tema de punteros. .
100
5.10.1 Operador direcci on
5.10.2 El operador contenido de
El siguiente programa muestra el paso de argumentos por referencia.
1 #include <stdio.h>
2 #include <math.h>
3 void cuadrado(int * x);
4 void raiz(float * y);
5
6 /* funciones: paso por referencia */
7
8 main()
9 {
10 int a,b=5;
11 printf("valor de b: %d\n",b);
12 cuadrado(&b);
13 printf("valor de b: %d\n",b);
14 printf("\n Observe que se modifico el valor de b, sin que haya reasignacion.\n\n");
15 raiz(&b);
16 printf("valor de b: %d\n",b);
17
18 return 0;
19 }
20 void cuadrado(int * x)
21 { // se declara el par ametro x de tipo puntero. Apunta a un entero.
22
23 // el operador * precediendo al par amtero puntero
24 // devuelve el contenido de la variable apuntada.
25
26 *x=(*x)* (*x); //el contenido de x es multiplicado por si mismo y
27 //asignadao a la misma variable x.
28 }
29 void raiz(float * y)
30 {
31 *y = sqrt(*y);
32 }
Debe notarse que para el cso del ejemplo mostrado, el paso por referencia no es lo mas conveniente,
ya que modica el valor de la variable pasada como argumento.
5.11 Punteros y direcciones de memoria
5.11.1 Operador direcci on de
Cuando declaramos una variable, el compilador reserva un espacio de memoria seg un el tipo de la
variable declarada. Por ejemplo si declaramos una variable como entero, se reservaran 2 bytes de
memoria para ella.
Cada vez que usamos la variable accedemos al valor que tienen almacenado.
En la mayora de las aplicaciones no necesitamos saber donde est a hubicada la memoria reservada,
pero por supuesto, esta memoria tendra una direcci on conocida por el compilador.
Si quisieramos saber la direcci on de la memoria asignada a la variable podemos usar el operador
direccion, &. El operador direcci on siempre antecede a la variable cuya direcci on nos interesa.
cursoC/curso/funciones.tex -August 24, 2012 101
Hemos visto que funciones como scanf requiere por argumentos las direcciones de las variables donde
se guardara el dato entrado.
En realidad hemos usado este operador cuando llamamos a la funci on scanf
printf("Entre a y b (floats) \n");
scanf("%f %f",&a,&b);
Esta funci on requiere que se pase la direcci on de la variable, en el ejemplo, de las variables a y b, que
son respectivamente &a y &b. La funci on modica el contenido de esas variables, asign andoles los
valores entrados por teclado.
Es posible que necesitemos tambien guardar una direcci on de memoria, y para ello existe un tipo de
variable adecuado. A este tipo de variables se les atribuye el tipo denominado puntero o apunta-
dor(pointers). La raz on del nombre es obvia, contiene la direcci on de otra variable, apunta o hace
referencia a otra variable.
Las variables de tipo puntero o, lo que es lo mismo, los punteros, deben declararse. En la declaracion
indicamos el tipo de variable al cual apuntar a el puntero, es decir el tipo de variable cuya direcci on
de memoria se guardara en el puntero.
Se usa el smbolo * para indicar que la variable es de tipo puntero.
En el ejemplo siguiente se denen como puntero a las variables n, ip que apuntan a un un entero y
un otante respectivamente:
int * n
float * ip
Con respecto al estilo, puede usarse cualquiera de las formas siguientes
int * n
int* n
int *n
indistintamente.
5.11.2 Asignacion de punteros
Para asignar valores (es decir direcciones) a un puntero usamos como siempre el operador asignacion,
=. Como dijimos solo podemos asignar la direcci on de una variable, que obtenemos con el operador
indireccion, simbolizado con &, entonces, para asignar a un puntero, pongamos por caso pi, la
direcci on de la variable i, usaremos una secuencia como la siguiente
int i;
int *pi;
pi = &i;
Siendo un puntero una variable, podemos asignarle valores una y otra vez. En efecto, en el ejemplo
siguiente, declaramos dos variables enteras, i y j, luego declaramos un puntero a una variable entera.
El puntero sera llamado punt. En la lnea tres asignamos al puntero la direcci on de la variable i, en
la lnea cuatro, asignamos la direcci on de la variable j
1 int i,j;
2 int *punt;
3 p=&i;
4 p=&j
102
5.11.3 El operador contenido de
El operador contenido de, es un operador unario que se simboliza con un asterisco adelante del
nombre de una variable de tipo puntero. Permite obtener el valor de la variable apuntada por dicho
puntero. Por ejemplo a, permite obener el valor de una variable a que debe ser de tipo puntero
El siguiente c odigo trata de ejemplicar estos conceptos:
1 #include <stdio.h>
2 // operadir.c
3 /* demustra el direccionamiento indirecto*/
4
5 main()
6 {
7 int aux, a=5;
8 int * p;
9 p=&a;
10 aux=*p;
11 printf("valor de a=%d\n",aux);
12 }
La salida del programa es la siguiente:
cardon@linux-pijg:~/A-cursos/cursoMN/programas/cuadraturas> ./ope
valor de a 5
En la lnea 7 se inicializa la variable a de tipo entera. En la linea 8 se declara la variable p como un
puntero que apunta a un entero. En la lnea 9 se asigna a puntero p la direcci on de la variable a. Por
ultimo, el contenido de la variable apuntada por p (que es el contenido de la variable entera a, ya que
es la direcci on de esa variable la que contienen p) se asigna a la variable aux.
5.11.4 Ejemplo: paso de argumentos por referencia
Volviendo a las funciones, el siguiente programa muestra como se pasan argumentos por referencia:
1 #include <stdio.h>
2 #include <math.h>
3 // swap.c
4 /* demustra la funcion intercambio */
5
6 void swap(int * a, int * b);
7 main()
8 {
9 int a=1,b=2;
10 printf("Segun inicializacion: a= %d b=%d \n",a,b);
11 swap(&a,&b);
12 printf("Despues del swap : a= %d b=%d \n",a,b);
13 }
14 void swap(int * x, int * y)
15 {
16 int aux;
17 aux=*y;
18 *y=*x;
19 *x=aux;
20 }
En la lnea 9 se denen dos variables enteras. En la denicion de la funci on, la lista de argumentos
(lnea 12) muestra la declaracion de dos punteros x y y. Consecuentemente, al llamar la funci on
cursoC/curso/funciones.tex -August 24, 2012 103
swap, los par ametros reales deben ser dos direcciones de memoria, por eso en la lnea 12 introdugimos
&a y &b
Dentro de la funci on, est an denidas las variable de tipo puntero x y y. Para acceder a los valores de
las variables a las que estos punteros apuntan, utilizamos el operador contenido de, como se muestra
en las lneas 17 a 19.
Como pasamos las direcciones de a y b a la funci on swap, estas direcciones est an est an disponibles
a traves de los punteros x y y. Al modicar los contendidos de las variables por ellos apuntadas,
lineas 17 a 19, modicamos los valores de a y b
5.11.5 Ejemplo: otro ejemplo
1 #include <stdio.h>
2 #include <math.h>
3 void cuadrado(int * x);
4 void raiz(float * y);
5
6 /* funciones: paso por referencia */
7
8 main()
9 {
10 int a,b=5;
11 printf("valor de b: %d\n",b);
12 cuadrado(&b);
13 printf("valor de b: %d\n",b);
14 printf("\n Observe que se modifico el valor de b, sin que haya reasignacion.\n\n");
15 raiz(&b);
16 printf("valor de b: %d\n",b);
17
18 return 0;
19 }
20 void cuadrado(int * x)
21 { // se declara el par ametro x de tipo puntero. Apunta a un entero.
22
23 // el operador * precediendo al par amtero puntero
24 // devuelve el contenido de la variable apuntada.
25
26 *x=(*x)* (*x); //el contenido de x es multiplicado por si mismo y
27 //asignadao a la misma variable x.
28 }
29 void raiz(float * y)
30 {
31 *y = sqrt(*y);
32 }
Debe notarse que para el coso del ejemplo mostrado, el paso por referencia no es lo mas conveniente,
ya que modica el valor de la variable pasada como argumento.
Bibliography
[1] rothberg.
[2] The american heritage science dictionary. Aug 2010.
[3] Dictionary of algorithms and data structures. Aug 2010.
[4] Dictionary.com unabridged. Aug 2010.
[5] Merriam-webster dictionary. Aug 2010.
[6] P. Chaudhuri. Parallel Algorithms. Design and An alisis. Prentice Hall, 1992.
[7] Dijtstra.
[8] R. W. Hamming. Numerical Methods for Scientists and Engineers. Dover, second edition, 1973.
[9] K. Hirose. Earths missing ingredient. Scientic American, june 2010.
[10] S.L.S Jacoby and J.S. Kowalik. Mathematical modeling with computers. Prentice-hall, Inc., 1980.
[11] Kernighan and Ritchie.
[12] H. L. Langhaar. Dimensional Analysis amd Theory of Models. John Wiley and Sons, 1951.
[13] C. Pursell. The machine in America. A social history of Technology. Johns Hopkins University
Press, 1995.
[14] B. Winston. Media Technology and Society. A History: From the Telegraph to the Internet.
Routledge, London, 1998.

Vous aimerez peut-être aussi