Este sitio web usa cookies de terceros para analizar el tráfico y personalizar los anuncios. Si no está de acuerdo, abandone el sitio y no siga navegando por él. ×


Tema 8: Procedimientos y funciones.

Tema 8.1: Procedimientos.

La programación estructurada trata de dividir el programa en bloques más pequeños, buscando una mayor legibilidad, y más comodidad a la hora de corregir o ampliar.

Por ejemplo, en el caso de nuestra maravillosa agenda, podemos empezar a teclear directamente y crear un programa de 2000 líneas que quizás incluso funcione, o dividirlo en partes, de modo que el cuerpo del programa sea


begin
  InicializaVariables;
  PantallaPresentacion;
  Repeat
  PideOpcion;
  case Opcion of
      '1': MasDatos;
      '2': CorregirActual;
      '3': Imprimir;
    ...
    end;
  Until Opcion = OpcionDeSalida;
  GuardaCambios;
  LiberaMemoria
end.

begin
InicializaVariables;
PantallaPresentacion;
Repeat
PideOpcion;
case Opcion of
'1': MasDatos;
'2': CorregirActual;
'3': Imprimir;
...
end;
Until Opcion = OpcionDeSalida;
GuardaCambios;
LiberaMemoria
end.


Bastante más fácil de seguir, ¿verdad?

En nuestro caso (en el lenguaje Pascal), estos bloques serán de dos tipos: procedimientos (procedure) y funciones (function).

La diferencia entre ellos es que un procedimiento ejecuta una serie de acciones que están relacionadas entre sí, y no devuelve ningún valor, mientras que la función sí que va a devolver valores. Veamoslo con un par de ejemplos:


procedure Acceso;
var
    clave: string; (* Esta variable es local *)
begin
    writeln(' Bienvenido a SuperAgenda ');
    writeln('=========================='); (* Para subrayar *)
    writeln; writeln; (* Dos líneas en blanco *)
    writeln('Introduzca su clave de acceso');
    readln( clave ); (* Lee un valor *)
    if clave <> ClaveCorrecta then (* Compara con el correcto *)
        begin (* Si no lo es *)
        writeln('La clave no es correcta!'); (* avisa y *)
        exit (* abandona el programa *)
        end
end;

Primeros comentarios sobre este ejemplo:

Ejercicio propuesto: Crear un procedimiento "LimpiarPantalla", que escriba 25 líneas en blanco en la pantalla, de modo que el texto que estaba escrito anteriormente en pantalla deje de estar visible (en una pantalla de texto convencional de 80x25 caracteres).

Tema 8.2: Funciones.

Veamos el segundo ejemplo: una función que eleve un número a otro (esa posibilidad no existe "de forma nativa" en Pascal), se podría hacer así, si ambos son enteros:


function potencia(a,b: integer): integer; (* a elevado a b *)
var
    i: integer;        (* para bucles *)
    temporal: integer; (* para el valor temporal *)
begin
    temporal := 1;             (* incialización *)
    for i := 1 to b do
    temporal := temporal * a;  (* hacemos 'b' veces 'a*a' *)
    potencia := temporal;      (* y finalmente damos el valor *)
end;


Comentemos cosas también:

Ejercicio propuesto: Crear una función "triple", que reciba un número real como parámetro, y devuelva como resultado ese número multiplicado por tres.
Ejercicio propuesto: Crear una función "media", que reciba dos números reales como parámetros, y devuelva como resultado su media artimética.

(Nota: al final de este apartado tienes la lista de funciones matemáticas y de manipulación de cadenas que incluye Turbo Pascal)


Tema 8.3: Uso de las funciones.

Pero vamos a ver un programita que use esta función, para que quede un poco más claro:


 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Primer ejemplo de     }
 {    función: potencia     }
 {    POTENCIA.PAS          }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Turbo Pascal 5.0    }
 {    - Surpas 1.00         }
 {--------------------------}

 program PruebaDePotencia;

 var
   numero1, numero2: integer;                (* Variables globales *)

 function potencia(a,b: integer): integer;  (* Definimos la función *)
 var
   i: integer;                      (* Locales: para bucles *)
   temporal: integer;               (* y para el valor temporal *)
 begin
   temporal := 1;                   (* incialización *)
   for i := 1 to b do
     temporal := temporal * a;      (* hacemos "b" veces "a*a" *)
   potencia := temporal;            (* y finalmente damos el valor *)
 end;

 begin                                       (* Cuerpo del programa *)
   writeln('Potencia de un número entero');
   writeln;
   writeln('Introduce el primer número');
   readln( numero1 );
   writeln('Introduce el segundo número');
   readln( numero2 );
   writeln( numero1 ,' elevado a ', numero2 ,' vale ',
     potencia (numero1, numero2) )
 end. 


Tema 8.4: Procedimientos con parámetros.

Un procedimiento también puede tener "parámetros", igual que la función que acabamos de ver:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Ejemplo de procedi-   }
 {    miento al que se le   }
 {    pasan parámetros      }
 {    PROCPAR.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Turbo Pascal 5.0    }
 {--------------------------}

 program ProcConParametros;
 { Para usarlo con SURPAS 1.00 habría    }
 { definir un tipo "str20", por ejemplo, }
 { que usar en vez de "string".          }

 procedure saludo (nombre: string);     (* Nuestro procedimiento *)
 begin
   writeln('Hola ', nombre, ' ¿qué tal estás?');
 end;

 begin                  (* Comienzo del programa *)
   writeln;             (* Linea en blanco *)
   saludo( 'Aurora' );  (* Saludamos a Aurora *)
 end.                   (* Y se acabó *) 

En el próximo apartado veremos la diferencia entre pasar parámetros por valor (lo que hemos estado haciendo) y por referencia (para poder modificarlos), y jugaremos un poco con la recursividad.

Ejercicio propuesto: Crear una función "potenciaReal", que trabaje con números reales, y permita cálculos como 3.2 ^ 1.7 (pista; hay que usar una par de funciones matemáticas: las exponenciales y los logaritmos; si te rindes, puedes mirar la ampliación 1 del curso).
Ejercicio propuesto: Hacer una función que halle la raíz cúbica del número que se le indique (pista: hallar una raíz cúbica es lo mismo que elevar a 1/3).
Ejercicio propuesto: Definir las funciones suma y producto de tres números, y crear un programa que haga una operación u otra según le indiquemos (empleando "case", etc).
Ejercicio propuesto: Un programita que halle la letra (NIF) que corresponde a un cierto DNI (documento nacional de identidad) español.
Ejercicio propuesto: Crea un programa que sume dos números "grandes", de 30 cifras. Esos números deberemos leerlos como "string" y sumarlos "letra a letra". Para ello, deberás crear una función "sumar", que reciba como parámetros dos "strings", y que devuelva su resultado en un nuevo "string".
Ejercicio propuesto: Crea un programa que multiplique dos números "grandes", de entre 30 y 100 cifras, por ejemplo. Para esos números no nos basta con los tipos numéricos que incorpora Pascal, sino que deberemos leerlos como "string" y pensar cómo multiplicar dos strings: ir cifra por cifra en cada uno de los factores y tener en cuenta lo que "me llevo"...


Tema 8.5: Modificación de parámetros.

Ya habíamos visto qué era eso de los procedimientos y las funciones, pero habíamos dejado aparcados dos temas importantes: los tipos de parámetros y la recursividad.

Vamos con el primero. Ya habíamos visto, sin entrar en detalles, qué es eso de los parámetros: una serie de datos extra que indicábamos entre paréntesis en la cabecera de un procedimiento o función.

Es algo que estamos usando, sin saberlo, desde el primer día, cuando empezamos a usar "WriteLn":

writeln( 'Hola' );

Esta línea es una llamada al procedimiento "WriteLn", y como parámetros le estamos indicando lo que queremos que escriba, en este caso, el texto "Hola".

Pero vamos a ver qué ocurre si hacemos cosas como ésta:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Primer procedimiento  }
 {    que modif. variables  }
 {    PROCMOD1.PAS          }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Turbo Pascal 5.0    }
 {    - Surpas 1.00         }
 {--------------------------}

 program PruebaDeParametros;

 var dato: integer;

 procedure modifica( variable : integer);
 begin
   variable := 3 ;
   writeln( 'Dentro: ', variable );
 end;

 begin
   dato := 2;
   writeln( 'Antes: ', dato );
   modifica( dato );
   writeln( 'Después: ', dato );
 end. 

¿Qué podemos esperar que pase? Vamos a ir siguiendo cada instrucción:


¡¡¡¡NO!!!! Escribe un 2. Las modificaciones que hagamos a "dato" dentro del procedimiento modifica sólo son válidas mientras estemos dentro de ese procedimiento. Lo que modificamos es la variable genérica que hemos llamado "variable", y que no existe fuera del procedimiento.

Eso es pasar un parámetro por valor. Podemos leer su valor, pero no podemos alterarlo.

Pero, ¿cómo lo hacemos si realmente queremos modificar el parámetro. Pues nada más que añadir la palabra "var" delante de cada parámetro que queremos permitir que se pueda modificar...


Tema 8.6: Parámetros por referencia.

El programa quedaría:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Segundo proc. que     }
 {    modifica variables    }
 {    PROCMOD2.PAS          }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Turbo Pascal 5.0    }
 {    - Surpas 1.00         }
 {--------------------------}

 program PruebaDeParametros2;

 var dato: integer;

 procedure modifica( var variable : integer);
 begin
   variable := 3 ;
   writeln( 'Dentro: ', variable );
 end;

 begin
   dato := 2;
   writeln( 'Antes: ', dato );
   modifica( dato );
   writeln( 'Después: ', dato );
 end.


Esta vez la última línea del programa sí que escribe un 3 y no un 2, porque hemos permitido que los cambios hechos a la variable salgan del procedimiento (para eso hemos añadido la palabra "var"). Esto es pasar un parámetro por referencia.

El nombre "referencia" alude a que no se pasa realmente al procedimiento o función el valor de la variable, sino la dirección de memoria en la que se encuentra, algo que más adelante llamaremos un "puntero".

Una de las aplicaciones más habituales de pasar parámetros por referencia es cuando una función debe devolver más de un valor. Habíamos visto que una función era como un procedimiento, pero además devolvía un valor (pero sólo uno). Si queremos obtener más de un valor de salida, una de las formas de hacerlo es pasándolos como parámetros, precedidos por la palabra "var".

Ejercicio propuesto: Crear una función "intercambia", que intercambie el valor de los dos números enteros que se le indiquen como parámetro.
Ejercicio propuesto: Crear una función "iniciales", que reciba una cadena como "Nacho Cabanes" y devuelva las letras N y C (primera letra, y letra situada tras el primer espacio), usando parámetros por referencia.


Tema 8.7: Parámetros con el mismo nombre que las variables locales.

Y como ejercicio queda un caso un poco más "enrevesado". Qué ocurre si el primer programa lo modificamos para que sea así:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Tercer proc. que      }
 {    modifica variables    }
 {    PROCMOD3.PAS          }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Turbo Pascal 5.0    }
 {    - Surpas 1.00         }
 {--------------------------}

 program PruebaDeParametros3;

 var dato: integer;

 procedure modifica( dato : integer);
 begin
   dato := 3 ;
   writeln( 'Dentro: ', dato );
 end;

 begin
   dato := 2;
   writeln( 'Antes: ', dato );
   modifica( dato );
   writeln( 'Después: ', dato );
 end.
  

 

(Puedes consultar la respuesta)


Tema 8.8: Recursividad.

Vamos al segundo apartado de hoy: qué es eso de la "recursividad". Pues la idea en sí es muy sencilla: un procedimiento o función es recursivo si se llama a sí mismo.

¿Y qué utilidad puede tener eso? Habrá muchos problemas que son más fáciles de resolver si se descomponen en pasos cada vez más sencillos.

Vamos a verlo con un ejemplo clásico: el factorial de un número.

Partimos de la definición de factorial de un número n:

n! = n · (n-1) · (n-2) · ... · 3 · 2 · 1

Por otra parte, el factorial del siguiente número más pequeño (n-1) es

(n-1)! = (n-1) · (n-2) · ... · 3 · 2 · 1

Se parecen mucho. Luego podemos escribir cada factorial en función del factorial del siguiente número:

n! = n · (n-1)!

¡Acabamos de dar la definición recursiva del factorial! Así vamos "delegando" para que el problema lo resuelva el siguiente número, y este a su vez se lo pasa al siguiente, y este al otro, y así sucesivamente hasta llegar a algún caso que sea muy fácil.

Pues ahora sólo queda ver cómo se haría eso programando:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Factorial, ejemplo de }
 {    recursividad          }
 {    FACT.PAS              }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Turbo Pascal 5.0    }
 {    - Surpas 1.00         }
 {--------------------------}

 program PruebaDeFactorial;

 var numero: integer;

 function factorial( num : integer) : integer;
 begin
   if num = 1 then
     factorial := 1        (* Aseguramos que tenga salida siempre *)
   else
     factorial := num * factorial( num-1 );       (* Caso general *)
 end;

 begin
   writeln( 'Introduce un número entero (no muy grande)  ;-)' );
   readln(numero);
   writeln( 'Su factorial es ', factorial(numero) );
 end. 


Un par de comentarios sobre este programilla:

Si este límite del tamaño de los enteros os parece preocupante, no le deis muchas vueltas, porque en la próxima lección veremos que hay otros tipos de datos que almacenan números más grandes o que nos permiten realizar ciertas cosas con más comodidad.

Ejercicio propuesto: Crear una función recursiva que halle el producto de dos números enteros.
Ejercicio propuesto: Crear otra función que halle la potencia (a elevado a b), también recursiva.
Ejercicio propuesto: Hacer un programa que halle de forma recursiva el factorial de cualquier número, por grande que sea. (Pista: habrá que usar la rutina de multiplicar números grandes, que se propuso como ejemplo en el apartado anterior)
Ejercicio propuesto: Crear un programa que emplee recursividad para calcular un número de la serie Fibonacci (en la que los dos primeros elementos valen 1, y para los restantes, cada elemento es la suma de los dos anteriores).
Ejercicio propuesto: Crea un programa que emplee recursividad para calcular la suma de los elementos de un vector.
Ejercicio propuesto: Crear un programa que encuentre el máximo común divisor de dos números usando el algoritmo de Euclides: Dados dos números enteros positivos m y n, tal que m > n, para encontrar su máximo común divisor, es decir, el mayor entero positivo que divide a ambos: - Dividir m por n para obtener el resto r (0 ? r < n) ; - Si r = 0, el MCD es n.; - Si no, el máximo común divisor es MCD(n,r).

Tema 8.9: La sentencia "forward".

La sentencia "forward" es necesaria sólo en un caso muy concreto, y cada vez menos, gracias a la programación modular, pero aun así vamos a comentar su uso, por si alguien llega a necesitarla:

Cuando desde un procedimiento A se llama a otro B, este otro procedimiento B debe haberse declarado antes, o el compilador "no lo conocerá". Esto nos supone llevar un poco de cuidado, pero no suele ser problemático.

Eso sí, puede llegar a ocurrir (aunque es muy poco probable) que a su vez, el procedimiento B llame a A, de modo que A debería haberse declarado antes que B, o el compilador protestará porque "no conoce" a A.

En este (poco habitual) caso de que cada uno de los procedimientos exigiría que el otro se hubiese detallado antes, la única solución es decirle que uno de los dos (por ejemplo "A") ya lo detallaremos más adelante, pero que existe. Así ya podemos escribir "B" y después dar los detalles sobre cómo es "A", así:

{--------------------------}
{  Ejemplo en Pascal:      }
{                          }
{    Ejemplo de "Forward"  }
{    FORW.PAS              }
{                          }
{  Este fuente procede de  }
{  CUPAS, curso de Pascal  }
{  por Nacho Cabanes       }
{                          }
{  Comprobado con:         }
{    - Turbo Pascal 7.0    }
{--------------------------}

program forw;

procedure A(n: byte); forward;  { No detallamos cómo es "A", porque
                                  "A" necesita a "B", que el compilador
                                  aún no conoce; por eso sólo  "declaramos"
                                  "A", e indicamos con "forward" que
                                  más adelante lo detallaremos }

procedure B (n: byte);          { "B" ya puede llamar a "A" }
begin
  writeLn('Entrando a B, con parámetro ', n);
  if n>0 then A (n-1);
end;

procedure A;                   { Y aquí detallamos "A"; ya no hace falta }
begin                          { volver a indicar los parámetros }
  writeLn('Entrando a A, con parámetro ', n);
  if n>0 then B (n-1);
end;

begin
  A(10);
end. 

 

Nota: en los Pascal actuales, más modulares, si usamos "unidades" (que veremos en el tema 12) se evita la necesidad de emplear "forward", porque primero se dan las "cabeceras" de todos los procedimientos (lo que se conocerá como "interface") y más adelante los detalles de todos ellos (lo que será la "implementation").


 


 

Curso de Pascal. Tema 8.10. Funciones matemáticas: abs, sin, cos, arctan, round, trunc, sqr, sqrt, exp, ln, odd, potencias.

La mayoría de las que vamos a ver son funciones matemáticas que están ya predefinidas en Pascal.  Muchas de ellas son muy evidentes, pero precisamente por eso no podía dejarlas sin mencionar al menos:

{--------------------------} 
{  Ejemplo en Pascal:      } 
{                          } 
{    Elevar un número real } 
{    a otro                } 
{    ELEVAR.PAS            } 
{                          } 
{  Este fuente procede de  } 
{  CUPAS, curso de Pascal  } 
{  por Nacho Cabanes       } 
{                          } 
{  Comprobado con:         } 
{    - Free Pascal 2.2.0w  }
{    - Turbo Pascal 7.0    } 
{--------------------------}

program elevar;

function elevado(a,b: real): real; 
begin 
  elevado := exp(b *ln(a) ); 
end;

begin 
  writeln(elevado(2,3)); 
end. 


 

La deducción de esta fórmula es fácil, conociendo las propiedades de los logaritmos y las exponenciales

  a^b = exp ( ln ( a^b )) = exp ( b * ln ( a ))
 


Curso de Pascal. Tema 8.11. Cadenas de texto.

En Turbo Pascal tenemos facilidades para trabajar con cadenas de texto, y desde luego, con más comodidad que desde otros lenguajes como C.

Las funciones incorporadas para el manejo de cadenas son:
 

Vamos a ver un ejemplo que las use:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Ejemplo de funciones  }
 {    de cadenas            }
 {    CADENAS.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {--------------------------}

 program cadenas;

 var
   frase: string;

 begin
   frase := 'Esta es una frase de ejemplo';
   writeln('La primera palabra (letras 1 a 4) es: ', copy(frase, 1, 4) );
   writeln('Si añadimos más texto: ', concat(frase, ' facilito') );

   delete(frase, 6, 2);
   writeln('Si borramos la segunda palabra (letras 5 a 7) es: ', frase );

   insert('si es', frase, 6);
   writeln('Y si insertamos una nueva segunda (y tercera) palabra: ',  frase);
   writeln('La longitud de la frase es: ', length(frase) );
   writeln('Y la primera a parece en la posición: ', pos('a', frase) );
 end. 

Que daría como resultado


La primera palabra (letras 1 a 4) es: Esta
Si añadimos más texto: Esta es una frase de ejemplo facilito
Si borramos la segunda palabra (letras 5 a 7) es: Esta  una frase de ejemplo
Y si insertamos una nueva segunda (y tercera) palabra: Esta si es una frase de ejemplo
La longitud de la frase es: 31
Y la primera a parece en la posición: 4

Pero esto tampoco es perfecto, y quien venga de programar en Basic echará de menos construcciones como Left$ (extraer varias letras de la izquierda) o Rigth$ (varias letras de la derecha).  También podríamos hacernos alguna funcioncita para convertir a hexadecimal, o de texto a número y al revés, o para manejar la fecha, etc.

La mayoría no son difíciles, así que allá vamos...
 

(Nota: estas rutinas las hice allá por el 93, y en su momento me sirvieron, aunque posiblemente muchas de ellas no estén programadas de la forma más eficiente).


Vamos a crear una Unit y a hacer un ejemplo que la use:

{--------------------------} 
{  Ejemplo en Pascal:      } 
{                          } 
{    Unidad con funciones  } 
{    mejoradas para mane-  } 
{    jar cadenas           } 
{    NSTR.PAS              } 
{                          } 
{  Este fuente procede de  } 
{  CUPAS, curso de Pascal  } 
{  por Nacho Cabanes       } 
{                          } 
{  Comprobado con:         }
{    - Free Pascal 2.2.0w  } 
{    - Turbo Pascal 7.0    } 
{    - Tmt Pascal Lt 1.20  } 
{--------------------------} 

unit nSTR; 

{=====================} 
{                     } 
{    Unidad nSTR      } 
{  Manejo de cadenas  } 
{                     } 
{  Nacho Cabanes, 93  } 
{                     } 
{=====================}

interface

  type 
    TipoFecha = string[8];
  FUNCTION CADENA(const carc:char;             {Cadena de caracteres repetidos} 
    const veces:byte):string; 
  FUNCTION COMAS(var s:string): string;        {Cambia , por . para hallar valor} 
  FUNCTION CONPUNTO(const num:longint):string; {Nº como cadena con puntos: x.xxx.xxx} 
  FUNCTION FECHA(const separ:char):tipofecha;  {Fecha, indicando el separador} 
  FUNCTION HEX(const a:byte):string;           {Pasa byte a hexadecimal} 
  FUNCTION LEFT(const cad:string;              {Letras de la izquierda} 
    const n:byte):string; 
  FUNCTION MAYUSC(const cad:string):string;    {Convierte a mayúsculas} 
  FUNCTION RIGHT(const cad:string;             {Letras de la derecha} 
    const n:byte):string; 
  FUNCTION SPC(const n:byte):string;           {Espacios en blanco} 
  FUNCTION STRS(const valor:longint):string;   {Como STR$ de Basic} 
  FUNCTION STRSR(const valor:real):string;     {STRS$ para reales} 
  FUNCTION VALORLI(const cad:string):longint;  {Valor de un string como LongInt} 
  FUNCTION VALORR(const cad:string):real;      {Valor de un string como REAL} 
  FUNCTION VALORW(const cad:string):word;      {Valor de un string como WORD}

implementation

  uses dos;
  
  FUNCTION CADENA(const carc:char; const veces:byte):string; 
  { Crea una cadena formada por un mismo carácter repetido varias veces } 
  var 
    cadtmp: string; 
    i: byte; 
  begin 
    cadtmp := '';                               { Cadena vacía } 
    for i := 1 to veces do cadtmp[i] := carc;   { Voy dando valores } 
    cadtmp[0] := chr(veces);                    { Ajusto la longitud } 
    { Las dos líneas anteriores se podrían 
    reemplazar también por: 
    for i := 1 to veces do cadtmp := cadtmp + carc; 
    } 
    cadena := cadtmp                            { Valor definitivo } 
  end;
  
  FUNCTION COMAS(var s:string): string; 
  { Cambia comas por puntos (decimales en formato americano) para poder 
    introducir un número en formato español y hallar su valor} 
  var 
    i: byte; 
    t: string; 
  begin 
    t := s;                            { Copio la cadena inicial } 
    for i :=1 to length(t) do          { La recorro } 
      if t[i]=',' then t[i] := '.';    { Y si encuentro , pongo . } 
    comas := t; 
  end;
  
  FUNCTION CONPUNTO(const num:longint):string; 
  { Devuelve un número como cadena con puntos: x.xxx.xxx } 
  var 
    cadena: string; 
    d: byte; 
  const 
    punto: char = '.'; 
  begin 
    str(abs(num),cadena);              { Empiezo a trabajar sin signo } 
    d := length(cadena);               { Veo la longitud } 
    if d>3 then                        { Si es mayor de 1.000 } 
      insert(punto,cadena,d-2);        { inserto un punto } 
    d := length(cadena);               { Vuelvo a mirar } 
    if d>7 then                        { Si es mayor de 1.000.000 } 
      insert(punto,cadena,d-6);        { pongo otro punto } 
    if num<0 then cadena:='-'+cadena;  { Si es negativo, le pongo signo } 
    ConPunto := cadena; 
  end;
  
  FUNCTION FECHA(const separ:char):tipofecha; 
  { Para ver la fecha como DD/MM/AA, o DD-MM-AA, etc. } 
  var 
    dia,mes,ano,disem: word;          { Fecha leida del DOS } 
    temporal: string[8];              { Temporal, para valor final } 
    tempo2: string[2];                { Temporal, para cada dato } 
  begin 
    getdate(ano,mes,dia,disem);       { Leo la fecha del DOS } 
    str(dia,tempo2);                  { Paso el día a cadena } 
    temporal:=tempo2+separ;           { Y le añado el separador } 
    str(mes,tempo2);                  { Paso el mes } 
    temporal:=temporal+tempo2+separ;  { Y lo añado } 
    str(ano mod 100,tempo2);          { Paso el año (dos ultimas cifras) } 
    temporal:=temporal+tempo2;        { Lo añado } 
    fecha:=temporal;                  { Y se acabó } 
  end;
  FUNCTION HEX(const a:byte):string; 
  { Convierte un byte a hexadecimal } 
  const 
    cadena: string[16] = '0123456789ABCDEF'; 
  begin 
    hex := cadena[a div 16 + 1]       { La primera letra: dividir entre 16 } 
      + cadena[a mod 16 + 1];         { La segunda: resto de la división } 
  end;
  
  FUNCTION LEFT(const cad:string; const n:byte):string; 
  { Cadena formada por los n caracteres más a la izquierda } 
  var 
    temp: string; 
  begin 
    If n > length(cad) then         { Si piden más que la longitud } 
      temp := cad                  { La cojo entera } 
    else 
      temp := copy(cad,1,n);       { Si no, una subcadena } 
    Left := temp; 
  end;
  
  FUNCTION MAYUSC(const cad:string):string; 
  { Convierte una cadena a mayúsculas.  La forma de tratar los caracteres 
    internacionales no es la más adecuada, porque pueden variar en las 
    distintas páginas de códigos, pero sirva al menos como ejemplo de 
    cómo comprobar si un valor está entre varios dados  O:-) } 
  var 
    buc: byte; 
    cad2: string; 
  begin 
    cad2 := cad; 
    for buc := 1 to length(cad2) do 
      begin 
      if cad2[buc] in ['a'..'z'] then           { Letras "normales" } 
        cad2[buc] := upcase(cad2[buc]); 
      { Internacionales: esto es lo que puede dar problemas } 
      if cad2[buc] in ['á','à','ä','â','Ä'] then cad2[buc]:='A'; 
      if cad2[buc] in ['é','è','ë','ê','É'] then cad2[buc]:='E'; 
      if cad2[buc] in ['í','ì','ï','î'] then cad2[buc]:='I'; 
      if cad2[buc] in ['ó','ò','ö','ô','Ö'] then cad2[buc]:='O'; 
      if cad2[buc] in ['ú','ù','ü','û','Ü'] then cad2[buc]:='U'; 
      if cad2[buc] = 'ñ' then cad2[buc]:='Ñ' 
      end; 
      mayusc := cad2                             { Valor definitivo } 
  end;
  
  FUNCTION RIGHT(const cad:string; const n:byte):string; 
  { Cadena formada por los n caracteres más a la derecha } 
  var 
    temp: string; 
  begin 
    If n > length(cad) then                   { Si piden más que la longitud } 
      temp := cad                            { La cojo entera } 
    else 
      temp := copy(cad, length(cad)-n+1, n); { Si no, subcadena } 
    right := temp; 
  end;
  
  FUNCTION SPC(const n: byte):string; 
  { Cadena formada por n espacios en blanco } 
  var 
    t: string; 
    i: byte; 
  begin 
    t := ' ';                         { Al menos uno } 
    for i := 2 to n do t:=t+' ';      { Si hay dos o más, añado } 
    spc := t 
  end;
  
  FUNCTION STRS(const valor:longint):string; 
  { Simplemente porque me gusta más usar STR como función que como 
    procedimiento (recuerdos del Basic, supongo) } 
  var 
    temporal: string; 
  begin 
    str(valor,temporal);             { Llamo al procedimiento STR } 
    strs := temporal; 
  end;
  
  FUNCTION STRSR(const valor:real):string; 
  { Igual que STRS, pero para números reales (deja 2 decimales) } 
  var 
    temporal: string; 
  begin 
    str(valor:3:2,temporal); 
    strsr := temporal; 
  end;
  
  FUNCTION VALORW(const cad:string):word; 
  { Valor de un string como WORD, para evitar usar VAL como procedimiento 
    que es más potente pero también más incómodo a veces (posiblemente, 
    esto también está aquí por culpa del Basic ;-) ) } 
  var 
    uno:word; 
    code:integer; 
  begin 
    val(cad,uno,code); 
    valorw:=uno; 
  end;
  
  FUNCTION VALORLI(const cad:string):longint; 
  { Igual que VALORW, pero para LongInt } 
  var 
    uno:longint; 
    code:integer; 
  begin 
    val(cad,uno,code); 
    valorli:=uno; 
  end;
  
  FUNCTION VALORR(const cad:string):real; 
  { Igual que VALORW, pero para reales.  Primero cambia las , por . } 
  var 
    uno:real; 
    code:integer; 
    cad2:string; 
  begin 
    cad2:=cad; 
    while Pos(',', cad2) > 0 do               { Le cambio , por . (si hay) } 
      cad2[Pos(',', cad2)]:= '.'; 
    val(cad2,uno,code);                       { Y llamo al procedimiento } 
    valorr:=uno; 
  end;

end. 

 

Un ejemplo de programa que usaría estas funciones sería:

{--------------------------} 
{  Ejemplo en Pascal:      } 
{                          } 
{    Prueba de la unidad   } 
{    nStr                  } 
{    USASTR.PAS            } 
{                          } 
{  Este fuente procede de  } 
{  CUPAS, curso de Pascal  } 
{  por Nacho Cabanes       } 
{                          } 
{  Comprobado con:         }
{    - Free Pascal 2.2.0w  } 
{    - Turbo Pascal 7.0    } 
{    - Tmt Pascal Lt 1.20  } 
{--------------------------}

program UsaStr;  { Ejemplo de la unidad nStr }

uses 
  crt, nSTR;
  
var 
  texto: string; 
  numero1: longint; 
  numero2: real;
  
begin 
  texto := 'Este será el texto inicial.'; 
  numero1 := 1234567; 
  numero2 := 1234567.895; 
  clrscr; 
  writeln('  ----- Prueba de la Unidad nSTR, día '+ fecha('-')+ ' -----'); 
  writeln; 
  writeln( texto ); 
  writeln('Convertido a mayúsculas: ', mayusc(texto) ); 
  writeln('Sus 8 primeras letras: ', left(texto,8) ); 
  writeln('Las 7 últimas: ', right(texto,7) ); 
  writeln('La 3ª y las 5 siguientes: ', copy(texto,3,5) ); 
  writeln; 
  writeln('Siete espacios y 10 X: ', spc(7), cadena('X',10), '.'); 
  writeln; 
  writeln('El primer número es: ', numero1); 
  writeln('Si le ponemos puntos separadores: ', ConPunto(numero1) ); 
  writeln('Las dos últimas cifras son: ', numero1 mod 100, 
    ', que en hexadecimal es: $', hex(numero1 mod 100) ); 
  writeln('La segunda y la tercera cifra, como cadena: ', 
    copy(strs(numero1),2,2) ); 
  writeln; 
  writeln('El segundo número: ', numero2 ); 
  writeln('En notación "normal": ', numero2:10:3 ); 
  writeln('Como cadena: ', strsr(numero2) ); 
  writeln('El valor de "123,5" es: ', valorr('123,5') :6:1 ); 
end. 

Que mostraría algo como


  ----- Prueba de la Unidad nSTR, día 16-6-10 -----

Este será el texto inicial.
Convertido a mayúsculas: ESTE SERA EL TEXTO INICIAL.
Sus 8 primeras letras: Este ser
Las 7 últimas: nicial.
La 3ª y las 5 siguientes: te se

Siete espacios y 10 X:        XXXXXXXXXX.

El primer número es: 1234567
Si le ponemos puntos separadores: 1.234.567
Las dos últimas cifras son: 67, que en hexadecimal es: $43
La segunda y la tercera cifra, como cadena: 23

El segundo número:  1.234567895000000E+006
En notación "normal": 1234567.895
Como cadena: 1234567.90
El valor de "123,5" es:  123.5


Curso de Pascal. Tema 8.12. Ejemplo: mini-agenda, con funciones.

Vamos ampliar un poco la mini-agenda que hicimos como ejemplo en el tema 7. Esta nueva versión usará funciones, para que el programa sea más modular. Algunas variables tendrán que ser globales, o bien pasarse como parámetros. Si somos cuidadosos y lo único que se comparte es el array con los datos, no es un gran problema el que esa variable sea global (realmente, dos lo serán: el array y el contador de datos usados).

Podría quedar así:

{--------------------------}
{  Ejemplo en Pascal:      }
{                          }
{    Ejemplo de "Agenda":  }
{    Permite añadir datos, }
{    mostrar, buscar.      }
{    Usa funciones.        }
{    AGENDA2.PAS           }
{                          }
{  Este fuente procede de  }
{  CUPAS, curso de Pascal  }
{  por Nacho Cabanes       }
{                          }
{  Comprobado con:         }
{    - Free Pascal 2.4.0   }
{--------------------------}

program Agenda2;

type
    tipoPersona = record
        nombre: string;
        email: string;
        anyoNacimiento: integer;
    end;

const
    capacidad = 1000;

var
    gente: array[1..capacidad] of tipoPersona;  { Los datos }
    cantidad: integer;       { Cantidad de datos existentes }
    terminado: boolean;

procedure MostrarMenu;
begin
    WriteLn('Agenda');
    WriteLn;
    WriteLn('1- Añadir una nueva persona');
    WriteLn('2- Ver nombres de todos');
    WriteLn('3- Buscar una persona');
    WriteLn('0- Salir');
end;

function LeerOpcion: integer;
var
    opcion: integer;
begin
    Write('Escoja una opción: ');
    ReadLn(opcion);
    WriteLn;
    if (opcion = 0) then terminado := true;
    LeerOpcion := opcion;    
end;

procedure NuevoDato;
begin
    if (cantidad < capacidad) then
    begin
        inc(cantidad);
        WriteLn('Introduciendo la persona ', cantidad);

        Write('Introduzca el nombre: ');
        ReadLn(gente[cantidad].nombre);

        Write('Introduzca el correo electrónico: ');
        ReadLn(gente[cantidad].email);

        Write('Introduzca el año de nacimiento: ');
        ReadLn(gente[cantidad].anyoNacimiento);

         WriteLn;
     end
     else
            WriteLn('Base de datos llena');
end;

procedure MostrarDatos;
var
    i: integer;
begin
    if cantidad = 0 then
        WriteLn('No hay datos')
    else
        for i := 1 to cantidad do
            WriteLn(i, ' ', gente[i].nombre);
    WriteLn;
end;

procedure BuscarDatos;
var
    textoBuscar: string;
    encontrado: boolean;
    i: integer;
begin
    Write('¿Qué texto busca? ');
    ReadLn( textoBuscar );
    encontrado := false;
    for i := 1 to cantidad do
        if pos (textoBuscar, gente[i].nombre) > 0 then
        begin
            encontrado := true;
            WriteLn( i,' - Nombre: ', gente[i].nombre,
              ', Email: ', gente[i].email,
              ', Nacido en: ', gente[i].anyoNacimiento);
        end;
    if not encontrado then
        WriteLn('No se ha encontrado.');
    WriteLn;
end;

procedure AvisarFin;
begin
    WriteLn;
    WriteLn('Saliendo...');
    WriteLn;
end;

procedure AvisarError;
begin
    WriteLn;
    WriteLn('Opción incorrecta!');
    WriteLn;
end;


{Cuerpo del programa principal}
begin
    terminado := false;
    cantidad := 0;
    repeat

        MostrarMenu;
        case LeerOpcion of
            1: NuevoDato;
            2: MostrarDatos;
            3: BuscarDatos;
            0: AvisarFin;                
            else AvisarError;
        end;  { Fin de "case" }

    until terminado;
end.