Академический Документы
Профессиональный Документы
Культура Документы
1. Introduccin.
4. Punteros a funciones.
5. Recursividad.
6. Tipos de almacenamiento.
1
1. Introduccin.
En un captulo anterior han sido tratados algunos conceptos bsicos
sobre las funciones. Una vez que se han explicado los arrays y los punteros,
ahora pueden ser detallados otros conceptos ms avanzados.
- paso por valor: un parmetro pasado por valor slo podr ser usado por la
funcin para recibir un dato de entrada a la misma.
- paso por referencia: un parmetro pasado por referencia podr ser usado
por la funcin tanto para recibir un dato de entrada a la misma como para
devolver un resultado de salida de la funcin, que lo podr usar el mdulo
llamante.
Pseudocdigo.
Inicio.
Radio
Longitud
2
Como vemos, cuando no se indica lo contrario un parmetro est
pasado por valor. Si colocamos Ref. delante del parmetro ser pasado por
referencia. En ese ejemplo, la variable original es Longitud, que se pasa por
referencia. Esto implica que las modificaciones que la funcin realice sobre L,
se aplican realmente sobre Longitud. Se podra decir que L es simplemente
otro nombre de la variable Longitud. Por tanto, el paso por referencia puede ser
utilizado para pasar datos a una funcin y para que sta devuelva resultados.
#include <stdio.h>
#include <conio.h>
#define PI 3.1416
3
Longitud; es decir que *L coincide con Longitud, por tanto la funcin est
trabajando directamente con la variable original Longitud, as si *L es
modificado en la funcin, se modifica Longitud.
#include <stdio.h>
#include <conio.h>
#define PI 3.1416
void main(void)
{
float Radio, Longitud, Area, Volumen;
clrscr();
printf(Teclee el radio:);
scanf(%d, &Radio);fflush(stdin);
Volumen = CALCULOS(Radio, &Longitud, &Area);
//El volumen es devuelto con return, mientras que
//para la longitud y el rea se usa paso por
//referencia.
printf(\nLa longitud es: %.4f, Longitud);
printf(\nEl area es: %.4f, Area);
printf(\nEl volumen es: %.4f, Volumen);
}
4
#include <stdio.h>
#include <conio.h>
void main(void)
{
int arr[2];
clrscr();
printf(\n Elemento 0:);
scanf(%d, &arr[0]);fflush(stdin);
//Podra usarse arr en lugar de &arr[0].
printf(\n Elemento 1:);
scanf(%d, &arr[1]);fflush(stdin);
//Podra usarse arr+1 en lugar de &arr[1].
SUMAR(arr[0], &arr[1]);
//La segunda componente se pasa por referencia.
//Podra usarse arr+1 en lugar de &arr[1].
printf(\nResultado de la suma:%d, arr[1]);
}
Veamos un ejemplo:
Ej.
#include <stdio.h>
5
#include <conio.h>
void main(void)
{
int arr[4] = {1,2,3,4};
//Array original de tamao 4.
clrscr();
PRODUCTO(arr); //Pasa el array completo.
}
#include <stdio.h>
#include <conio.h>
void CARGA (int *arr);
void main(void)
{
int arr[4];
clrscr();
CARGA(arr);
}
Ej. Programa que al ejecutarlo obliga a teclear una clave despus del
nombre del programa (la clave es CLAVE).
#include <stdio.h>
...
void main(int argc, char *argv[])
{
//Declaraciones
...
if (argc == 2)
if (strcmp(CLAVE, argv[1]) == 0)
printf(Clave correcta. Puede continuar.);
else
{
printf(Clave incorrecta.);
exit(0); //Finaliza la ejecucin.
}
else
7
printf(Debe teclear C:\>Nom_Prog Clave);
...
}
C:\>ENTRADA CLAVE
Ej.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void DINAMICA (char *nombre);
void main(void)
{
8
char *nombre;
clrscr();
DINAMICA(nombre); //nombre es el puntero original.
printf(Nombre tecleado: %30s, nombre); //ERROR!!!
//No se visualiza el nombre tecleado en la funcin.
Ej.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
char * DINAMICA (void); //Retorna un puntero.
void main(void)
{
char *nombre;
clrscr();
nombre = DINAMICA(); //El puntero nombre se guarda
//la direccin que retorna la funcin.
printf(Nombre tecleado: %30s, nombre);
free(nombre); //Libera la memoria reservada en la
//funcin.
}
char * DINAMICA(void)
{
char *nombre; //Puntero local de la funcin.
nombre = (char *)malloc(30*sizeof(char));
scanf(%29[^\n], nombre); fflush(stdin);
return(nombre); //Retorna la direccin de memoria
} //dinmica, donde se ha cargado el nombre.
9
4. Punteros a funciones.
Una caracterstica particularmente confusa pero muy potente del C es el
puntero a funcin.
puntero = nombre_funcin;
#include <stdio.h>
#include <conio.h>
long potencia(int, int);
10
void main(void)
{
int base, exponente;
long resultado;
long (*pf)(); //Declaracin de puntero a funcin
//que retorna un dato de tipo long.
clrscr();
printf(\n Base: );
scanf(%2d, &base); fflush(stdin);
printf(\n Exponente: );
scanf(%2d, &exponente); fflush(stdin);
pf = potencia; //El puntero pf apunta a la
//direccin de inicio de la funcin.
resultado = (*pf)(base, exponente);
//LLamada a la funcin usando el puntero. Se le
//pasan 2 parmetros int y retorna un dato long.
// Potencia: baseexponente
long potencia(int base, int exponente)
{
int i = 1;
long resultado = 1;
for ( ; i <= exponente ; i++)
resultado *= base;
return(resultado);
}
Debe tenerse en cuenta que C++ (fichero fuente con extensin .CPP)
realiza un chequeo ms exhaustivo en el proceso de compilacin que C
(fichero fuente con extensin .C). Esto implica que en la declaracin de un
puntero a funcin, en C++ deben indicarse los tipos de los parmetros de la
funcin a la que va a apuntar dicho puntero, ya que en caso contrario se
producir el correspondiente error de compilacin.
En el ejemplo anterior, el puntero habra que declararlo con dos tipos int
como parmetros, porque la funcin a la que va a apuntar tiene esos dos
parmetros, long potencia(int base, int exponente).
11
ejecutar, de entre un conjunto de funciones. Se podra decir que es una
llamada a una funcin variable, no siempre a la misma como ocurrira si se
usara el nombre de la funcin en lugar de un puntero.
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
long factorial(int);
long sumatorio(int);
void main(void)
{
int numero;
char operacion;
long resultado;
long (*pf)(); //Puntero a funcin de retorna long.
//En C++ sera: long (*pf)(int);
clrscr();
printf(\n S=Sumatorio F=Factorial Elija S/F:);
operacion = toupper(getche());
switch (operacion)
{
case S:
pf = sumatorio; //pf apunta a sumatorio.
break;
case F:
pf = factorial; //pf apunta a factorial
break;
default:
pf = NULL; //Operacin errnea.
}
if (pf != NULL) //Si es operacin correcta...
{
printf(\n Numero: );
scanf(%2d, &numero); fflush(stdin);
//La siguiente llamada a funcin con pf, est
//ejecutando factorial o sumatorio.
resultado = (*pf)(numero); //Llamada a funcin
printf(\n Resultado: %ld, resultado);
}
else
printf(\nOperacin errnea...);
}//Fin main.
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
long factorial(int);
long sumatorio(int);
void calcular(int, long (*)() );
//Un parmetro es punt. a funcin. En C++ sera:
// void calcular(int, long (*)(int) );
void main(void)
{
int numero;
char operacion;
long resultado;
long (*pf)(); //En C++: long (*pf)(int);
clrscr();
printf(\n S=Sumatorio F=Factorial Elija S/F:);
operacion = toupper(getche());
switch (operacion)
{
case S:
pf = sumatorio; //pf apunta a sumatorio.
break;
case F:
pf = factorial; //pf apunta a factorial
break;
default:
pf = NULL; //Operacin errnea.
}
14
Ej.
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
long factorial(int);
long sumatorio(int);
void main(void)
{
int numero, operacion;
long resultado;
long (*pf[2])(); //En C++: long (*pf[2])(int);
//Array de 2 punteros a funciones de tipo long.
clrscr();
pf[0] = sumatorio; //Un puntero apunta a sumatorio.
pf[1] = factorial; //Un puntero apunta a factorial.
calcular(numero, pf[operacion]);
5. Recursividad.
15
Se dice que una funcin es recursiva cuando se llama a s misma, es
decir entre sus instrucciones existe una llamada al propio nombre de la funcin.
El lenguaje C permite la creacin de funciones recursivas.
#include <stdio.h>
#include <conio.h>
long potencia(int, int);
void main(void)
{
int base, exponente;
long resultado;
clrscr();
printf(\nBase......:);
scanf(%2d, &base);fflush(stdin);
printf(\nExponente.:);
scanf(%2d, &exponente);fflush(stdin);
resultado = potencia(base, exponente);
printf(\nResultado: %ld, resultado);
getch();
16
} //Fin main.
long potencia(int A, int n)
{
long pot;
if (n == 1) //condicin de convergencia.
pot = A;
else
pot = A * potencia( A, n-1 );
//Se llama a s misma.
return(pot);
}
6. Tipos de almacenamiento.
El tipo de almacenamiento se especifica al declarar una variable o
funcin. En C existen 4 tipos de almacenamiento, que se aplican a los
siguientes elementos:
Como sabemos, las variables locales son las declaradas dentro de algn
bloque de programa, es decir dentro de dos llaves {...}, ya sea en el bloque
main o en cualquier otro. Mientras que las variables globales son las que se
declaran fuera de todos los bloques, generalmente antes del bloque main. Las
funciones en C estn declaradas a nivel global, es decir no existe una funcin
declarada dentro de otra, todas estn al mismo nivel. Esto implica que una
funcin puede ser llamada desde cualquier punto del programa, ya sea desde
dentro del main o desde otra funcin.
17
variables. La variable existe solamente dentro del bloque donde se haya
declarado. Al finalizar dicho bloque, la variable ser destruida.
Ej.
void Funcion(void)
{
int Suma;
auto float Nota; //Tanto Suma como Nota son auto.
...
}
//Al finalizar el bloque, se destruyen esas variables.
Ej.
void Funcion(void)
{
register int Suma; //Se almacena en registro.
float Nota; //Es auto. Se almacena en RAM.
//El acceso a Suma es mucho ms rpido.
...
}
//Al finalizar el bloque, se destruyen esas variables.
Ej.
Fichero1.C
#include <stdio.h>
...
extern void Funcion(void);
//Funcin desarrollada en otro fuente.
int Clave;
//Clave es Variable global.
18
void main(void)
{
float Contador; //Variable local.
...
}
Fichero2.C
#include <stdio.h>
... //Aqu no hay main. Est en Fichero1.C.
Ej.
#include <stdio.h>
...
void Funcion(void);
void main(void)
{
...;
Funcion(); //Primera llamada: Contador comienza
... //con el valor 10 y acaba con 15.
Funcion();
//Segunda llamada: Contador comienza con el valor
//15, de la llamada anterior, y acaba con 20.
}
void Funcion(void)
{
static int Contador = 10; //Var.local y static.
//Inicializar a 10 se ejecuta en la primera llamada
...
Contador = Contador + 5;
}
19
Por otra parte, cuando se utiliza static en una variable global o funcin
(las funciones son todas globales) indicar que dicha variable global o funcin
slo podr ser utilizada en el fichero fuente donde est declarada. Obviamente,
esto tiene sentido cuando se utilizan varios fuentes para crear un ejecutable.
Por ejemplo, si en un fichero fuente se declara la funcin Funcion(), en otro
fichero fuente no podr existir una funcin con ese mismo nombre, Funcion().
Pero utilizando el tipo static s podr existir. Igual ocurre con variables globales.
Ej.
Fichero1.C
#include <stdio.h>
...
static void Funcion(void);
//Esta Funcion() slo se usar en este Fichero1.C
int Clave;
//Variable global. Se podr usar en otros fuentes.
void main(void)
{
Funcion();//Se llama a Funcion() de este Fichero1.C
} //Visualiza un 1.
void Funcion(void)
{
Clave = 1; //Usa Clave de este fuente: Fichero1.C
printf(\n %d, Clave);
}
Fichero2.C
#include <stdio.h>
...
static int Clave;
//Declara Clave global en Fichero2.C para ser
usada //slo en este Fichero2.C. Es una variable
distinta de //Clave de Fichero1.C aunque tengan el
mismo nombre.
void Funcion(void)
{
Clave = 2; //Usa Clave de este fuente Fichero2.C
printf(\n %d, Clave);
}
//Esta Funcion() puede ser usada en otros fuentes. Es
//una funcin distinta de la de Fichero1.C, aunque
//tengan el mismo nombre.
Fichero3.C
#include <stdio.h>
...
int Clave; //Dara ERROR, ya que Clave ya est usada
//en Fichero1.C
extern int Clave; //Usara Clave de Fichero1.C
extern void Funcion(void); //Funcin externa.
20
void Funcion2(void)
{
Funcion();
//Llama a Funcion de Fichero2.C. Visualiza un 2.
printf(\n %d, Clave);
//Usa Clave de Fichero1.C. Visualiza un 1.
}
Esa misma tarea puede llevarse a cabo sin salir del IDE, con la opcin
Project. Para crear un proyecto nuevo se elige Open, se introduce una ruta y un
nuevo nombre de proyecto, con lo que se abre la ventana de nuevo proyecto.
Con la tecla <Ins> se abrir una nueva ventana para seleccionar los ficheros
fuentes que formarn el proyecto. Una vez aadidos todos los fuentes, con la
tecla <Esc> se regresa a la ventana de proyecto, en la que aparecen los
nombres de todos los fuentes aadidos. Con la tecla <Supr> (o <Del>) se
pueden quitar fuentes previamente aadidos al proyecto. Finalmente con la
tecla <F10> se activa el men que permite compilar, enlazar y ejecutar. El
nombre del ejecutable ser el dado al proyecto. La opcin Open citada
anteriormente tambin permite abrir un proyecto ya existente, con lo cual se
podr modificar la lista de fuentes que lo forman, siguiente el mismo mtodo.
Si el fichero .h se coloca entre los smbolos < > (por ejemplo, #include
<stdio.h>) el compilador buscar dicho fichero en la carpeta introducida en el
campo Include Directories. Este campo se halla dentro de Options ms
Directories del men del IDE. Cuando el fichero .h se escribe entre comillas
(por ejemplo, #include micabec.h), el compilador lo buscar primero en la
carpeta actual de trabajo y despus en la carpeta definida en Include
Directories del IDE. Tambin puede indicarse entre las comillas la ruta
completa donde se encuentra el fichero cabecera (por ejemplo, #include
21
C:\CPP\CABECERA\micabece.h), con lo cual el compilador buscar en la ruta
indicada.
Ej.
Fichero1.C (fichero fuente)
#include <stdio.h>
#include micabec.h
void main(void)
{
Funcion1(); //Llamadas a 2 funciones no declaradas
Funcion2(); //en este fichero fuente.
Clave = 123; //Variable global.
}
void Funcion1(void) //Definicin de Funcion1.
{...}
Ej.
Fichero1.C (fichero fuente)
#include micabec.h
void main(void)
{
Funcion1(); //Llamadas a 2 funciones no declaradas
Funcion2(); //en este fichero fuente.
Clave = 123; //Variable global.
}
micabec.H (fichero cabecera)
#include <stdio.h>
int Clave; //Declaracin de variable global.
void Funcion1(void) //Definicin de Funcion1.
{
...
}
void Funcion2(void) //Definicin de Funcion2.
{
...
22
}
23
EJERCICIOS - CAPITULO 10:
1. Funcin que intercambie los valores de dos variables float. Ponerle clave al
programa en el momento de ejecutarlo.
4. Funcin que cuenta cuntas vocales tiene la cadena tecleada despus del
nombre del programa, al ejecutarlo.
11. Teclear una serie de nmeros hasta que se teclee un cero. Para cada
nmero tecleado visualizar su factorial: N! = 1 * 2 * 3 * ...* (N-1) * N,
calculado de forma recursiva.
14. Programa para hacer apuestas de lotera primitiva. Debe crearse el men
siguiente:
LOTERIA PRIMITIVA:
1. Establecer coste/apuesta.
2. Apuesta manual
3. Apuesta automtica
4. Crear apuesta premiada.
5. Consultar nmero de aciertos.
6. Salir.
25
EJERCICIOS ADICIONALES DE REPASO:
16. Mantener una lista de espera con un array dinmico con el tamao justo
para las personas que hay en la lista de espera. La informacin que se
guarda en el array ser el DNI. Debe usarse un men con las opciones: 1.
Apuntar a la lista; 2. Avisar (Borrar el primero de la lista); 3. Eliminar (Borrar
un DNI que puede no ser el primero); 4. Visualizar la lista completa; y 5.
Salir. Deben hacerse las siguientes funciones: una funcin recibe un DNI
como parmetro y devuelve si est en la lista y en qu posicin.; una
funcin visualiza el men y pide teclear opcin hasta que sea correcta
(entre 1 y 5), devolviendo la opcin tecleada; una funcin para cada opcin
del men. Debe recordarse que para aumentar o reducir el tamao del array
dinmico, debe crearse uno nuevo con el nuevo tamao(malloc), copiar el
viejo en el nuevo y despus eliminar el viejo (free).
26