Monografias.com > Computación > Programación
Descargar Imprimir Comentar Ver trabajos relacionados

Trabajo de programación básica



    1. Lenguaje C++
    2. Características de
      Lenguaje C++
    3. Construcción de una
      aplicación básica
    4. Estructura de un Programa en
      Lenguaje C++
    5. Las
      variables
    6. Constantes
    7. Inclusión de
      ficheros
    8. Operadores aritméticos y
      de asignación
    9. Estructura
      SWITCH
    10. Bucles
    11. Funciones
    12. Ficheros
    13. Escritura y
      lectura
    14. Gestión Dinámica
      de Memoria
    15. Las listas
    16. Programación
      Gráfica
    17. Tipos
    18. Funciones y
      macros
    19. Bibliografía

    Investigar todo lo
    referente a Lenguaje
    C++

    Antecedentes Históricos

    C++ es un nuevo lenguaje de
    programación que está construido sobre un viejo
    lenguaje:
    el lenguaje de
    programación C. El lenguaje C fue
    desarrollado a principios de los
    1970 en los  Laboratorios Bell, construido originalmente
    como una herramienta dentro de  un sistema de
    programación (sistemas
    operativos por ejemplo) así como para el desarrollado
    de compiladores. No
    era necesario indicar el lenguaje
    del usuario final, es decir, que era un lenguaje para
    propósito general. Sin embargo, C se volvió
    extremadamente exitoso y es ahora ampliamente usado en la
    industria y la
    academia. Dennis Ritchie fue el primero en desarrollar un
    lenguaje C, el
    cual corría sobre una computadora
    DEC PDP-11. El desarrollo de
    C se baso en otro viejo lenguaje llamado B que a su vez tiene su
    origen en otro lenguaje aún más antiguo denominado
    BCPL.

    Sin embargo fue hasta 1978 cuando Brian Kernoghan y
    Ritchie Publicaron una descripción final de dicho lenguaje, esta
    descripción común mente denominada
    K&R C, contenía las características deseas del
    lenguaje.

    A mediados de 1980 el lenguaje tenía una
    popularidad extendida por todas partes, día a día
    se escribían, nuevos interpretes y compiladores para
    dicho lenguaje, inclusive programas
    escritos en otros lenguajes se rescribieron en C.
    C era un lenguaje que ofrecía a los programadores eficiencia y
    potencia en su
    trabajo, fue esto lo que haría que dicho lenguaje, ganara
    gran parte de su fama, este lenguaje fue clasificado por la
    comunidad
    informática como lenguaje de Medio Nivel,
    por que sus capacidades, lo hacían superior de otros
    lenguajes, tales como Pascal de
    Borland, Cobol,
    etc.

    ¿Qué es Lenguaje
    C++?

    Como todos sabemos, "C" es un lenguaje de alto nivel,
    basado en funciones, que
    permite desarrollos estructurados. Entre otras muchas características contempla la
    definición de estructuras de
    datos,
    recursividad o indirecciones a datos o código
    (punteros).

    "C ++", por su parte, es un superconjunto de "C", al que
    recubre con una capa de soporte a la POO. Permite por tanto la
    definición, creación y manipulación de
    objetos.

    El lenguaje C++ se conoce como un lenguaje compilado.
    Existen dos tipos de lenguaje: interpretados y compilados. Los
    interpretados son aquellos que necesitan del código
    fuente para funcionar (P.ej: Basic). Los compilados convierten el
    código fuente en un fichero objeto y éste en un
    fichero ejecutable. Este es el caso del lenguaje C++.

    Palabras reservadas

    Las 32 palabras reservadas de C se escriben todas en
    letras minúsculas, de acuerdo con el Comité de
    normalización internacional ANSI C, dichas
    palabras son:

    auto

    double

    int

    struct

    break

    else

    long

    switch

    case

    enum

    register

    typedef

    char

    extern

    return

    union

    const

    float

    short

    unsigned

    continue

    for

    signed

    void

    default

    goto

    sizeof

    volatile

    do

    if

    static

    while

    Adicionalmente, algunos compiladores de C
    han agregado algunas palabras reservadas para explotar mejor su
    sistema
    operativo.

    Por ejemplo, varios compiladores incluyen palabras clave
    para manejar la
    organización de la memoria de
    la familia de
    procesadores
    8086, soportar programación entre-lenguajes y acceso a
    interrupciones. La siguiente es una lista de esas palabras
    claves:

        asm

    interrupt

    cdecl

    _ds

    pascal

    _ss

    _cs

    near

    far

    huge

    ¿Qué necesito para correr C++?.

    Las características necesarias para poder correr
    un Programa en
    Lenguaje C++ son:

    • Un computador
      IBM PC AT o compatible.
    • MS-DOS 3.31 o una versión
      posterior.
    • Un ratón compatible con Microsoft.
    • Monitor EGA, VGA o mayor
      resolución.
    • Por lo menos 8 Mbytes libres en disco
      duro.

    Características de Lenguaje
    C++

    Podemos decir que el lenguaje C++ es un lenguaje de
    nivel medio, ya que combina elementos de lenguaje de alto nivel
    con la funcionalidad del lenguaje
    ensamblador.

    Es un lenguaje estructurado, ya que permite crear
    procedimientos
    en bloques dentro de otros procedimientos.
    Hay que destacar que el C++ es un lenguaje estándar, ya
    que permite utilizar el mismo código en diferentes equipos
    y sistemas
    informáticos: el lenguaje es independiente de la arquitectura de
    cualquier máquina en particular.

    El C++ se lo pude calificar como lenguaje relativamente
    pequeño; se puede describir en poco espacio y aprender
    rápidamente.

    Además se puede decir que:

    • C++ es fuertemente tipeado: Es decir que cada
      objeto debe   pertenecer a un cierto tipo y que cada
      operación tal como la asignación o la
      comparación son solamente permitidas entre objetos del
      mismo tipo. Dado que las funciones
      requieren entradas de un cierto tipo no aceptarán
      entradas de otro tipo. Sin embargo, esto no es totalmente
      cierto en un sentido estricto ya que hay algunas reglas que
      permiten conversiones entre tipos (por ejemplo, un entero puede
      temporalmente ser cambiado temporalmente a un número
      real para realizara alguna operación
      determinada).
    • C++ proporciona el concepto de
      clase
      : Un tipo de registro que
      combina datos y las funciones que operan sobre
      ellos.
    • Con C++ es posible sobrecargar operadores con
      clases definidas por el usuario
      . Por ejemplo una clase
      definida por el usuario podría ser una de números
      racionales que pudiera implementar la operación de
      adición ordinaria usando el operador +. Como
      consecuencia, estas clases pueden comportarse mas como tipos
      que incorporan tipos.
    • C++ soporta tipos parametrizados o templates.
      Las funciones templates pueden trabajar sobre diferentes tipos
      de entradas. Por ejemplo, es posible escribir una simple
      función swap que trabaje sobre todos los
      tipos posibles.  Sin embargo, las dos variables
      serán verificadas para asegurar la correspondencia entre
      sus tipos. Con los templates es posible definir que una clase
      de arreglos que trabaje en forma booleana, caracteres, enteros,
      reales, entre otros. 
    • C++ soporta herencia, un mecanismo que hace
      posible la construcción de nuevas clases (llamadas
      clases derivadas)
      sobre las clases existentes (llamadas las clases base) sin
      tener que repetir el código de la clase base para cada
      nueva clase. Herencia es un
      gran avance para la reutilización de
      código.
    • C++ soporta polimorfismo aún cuando es
      fuertemente tipeado
      : Una variable de apuntadores del tipo
      de la clase base puede dinámicamente asumir el tipo de
      la clase derivada. Junto con la herencia, esto
      vuelve a C++ un lenguaje orientado a objetos completamente
      maduro.
    • C++ viene con dos librerías Estándar
      Library y Estándar Template Library (STL)
      : Cada una
      de estas librerías extiende las capacidades del lenguaje
      base:
      • La Standard Library proporciona todas las
        viejas librerías de C así como
        también las facilidades de entrada y
        salida.
      • La STL proporciona una librería de tipos
        de contenedores (tipos que mantienen o "contienen"
        colecciones de objetos) así como también un
        conjunto de algoritmos de propósitos generales
        para estructuras de datos comunes que se
        denominan algoritmos tipo "attendant". Es decir, los
        suplementos de STL son tipos empotrados de C++ con
        vectores, listas ligadas, árboles balanceados y otros tipos
        útiles.
    • C++  permite variables de
      referencia, lo que hace posible llamadas por referencia
      , el
      compilador mejora mucho el costo de la
      asignación de memoria, ya
      que  permite a este accesos de solo lectura a
      úna área de almacenamiento particular

    Construcción
    de una aplicación básica

    Seguiremos los siguientes pasos:

    Crear un nuevo proyecto. Desde el menú
    "Fichero", en la opción "Nuevo".

    Seleccionar objetivo del
    proyecto. Seleccionaremos "aplicación basada en
    MFC"

    Nombrar el proyecto. Visual C++
    organiza los proyectos de
    manera que crea un subdirectorio nuevo con el nombre de cada
    proyecto.
    Aunque esta "regla" siempre puede modificarse, puede ser una
    buena forma de control de
    proyectos.

    En estos momentos aparecerá la secuencia de
    diálogos del generador ClassWizard. Veamos cuales
    serían los pasos a seguir para crear una aplicación
    sencilla:

    Paso 1. Permite identificar el modelo de
    ventana principal de nuestra aplicación: SDI, MDI o basada
    en diálogo.
    Nosotros elegiremos SDI.

    Paso 2. Permite incorporar soporte a Bases de Datos en
    la aplicación. Esto lo veremos más adelante.
    Seleccionaremos la opción sin soporte a bases de
    datos.

    Paso 3. Relativo al soporte OLE. Igual que en el
    caso anterior.

    Paso 4. Otras características de la
    aplicación (barra de botones, barra de estado,
    controles 3D …)

    Paso 5. Generación de comentarios en el
    código (si/no) y usos posibles de las MFC (como DLL o como
    LIB). Se recomienda la opción DLL en cuanto al
    tamaño y modularidad del programa, pero
    deberemos asegurarnos de distribuir la DLL junto con nuestro
    programa para que funcione correctamente.

    Paso 6. Permite modificar el nombre de las clases
    MFC que se van a generar, además de especificar los
    ficheros en los que se implementa y la clase base de la que
    derivan. Los nombres generados por AppWizard suelen ser
    bastantes significativos.

    A partir de este momento da comienzo la
    generación del código definido antes. Como se
    habrá observado, el nombre por defecto de las clases
    generadas tiene mucho que ver con el nombre que le hayamos dado
    al proyecto. De esta
    manera, si hubiésemos llamado "curso1" al proyecto
    tendríamos la siguiente situación:

    Clase CCurso1App (módulos curso1.h y curso1.cpp)
    que representa una aplicación Windows.

    Clase CMainFrame (ficheros mainfrm.h y mainfrm.cpp) que
    representan la ventana principal de la
    aplicación.

    Clases CCurso1Doc y CCurso1View (ficheros
    curso1doc.h/curso1doc.cpp y curso1view.h/curso1view.cpp
    respectivamente), representantes de lo que se conoce en el mundo
    Windows como
    interfaz "Documento/Vista" y que trataremos en
    adelante.

    Clase CAboutDlg que representa el típico diálogo de
    "Acerca de …" y que ha sido generado
    automáticamente por AppWizard, esta clase (rompiendo la
    norma habitual de la MFC) aparece definida e implementada dentro
    los mismos ficheros que la clase aplicación
    (módulos curso1.h y curso1.cpp). En el futuro evitaremos
    este tipo de construcciones.

    Estructura de un
    Programa en Lenguaje C++

    • Estructura.- Todo programa en C consta
      de una o más funciones, una de las cuales se llama
      main. El programa comienza en la función
      main, desde la cual es posible llamar a otras
      funciones.

    Cada función estará formada por la
    cabecera de la función, compuesta por el nombre de la
    misma y la lista de argumentos (si los hubiese), la
    declaración de las variables a utilizar y la secuencia
    de sentencias a ejecutar.

    Ejemplo:

    <> declaraciones globales

    main( ) {

    variables locales

    bloque

    }

    funcion1( ) {

    variables locales

    bloque

    }

    • Comentarios.- A la hora de
      programar es conveniente añadir comentarios (cuantos
      más mejor) para poder saber
      que función tiene cada parte del código, en caso
      de que no lo utilicemos durante algún tiempo.
      Además facilitaremos el trabajo a
      otros programadores que puedan utilizar nuestro archivo
      fuente.

    Para poner comentarios en un programa escrito en
    C usamos los símbolos /* y
    */:

    <> /* Este es un ejemplo de comentario
    */

    /* Un comentario también puede

    estar escrito en varias líneas */

    El símbolo /* se coloca al principio del
    comentario y el símbolo */ al final.
    El comentario, contenido entre estos dos símbolos, no
    será tenido en cuenta por el compilador.

    • Identificadores.- Un identificador es el
      nombre que damos a las variables y funciones. Está
      formado por una secuencia de letras y dígitos, aunque
      también acepta el carácter
      de subrayado _. Por contra no acepta los acentos ni la
      ñ/Ñ.

    El primer carácter
    de un identificador no puede ser un número, es decir que
    debe ser una letra o el símbolo _.

    Se diferencian las mayúsculas de las
    minúsculas, así num, Num y
    nuM son distintos identificadores.

    A continuación vemos algunos ejemplos de
    identificadores válidos y no válidos:

    <> Válidos No
    válidos

    <> _num 1num

    var1 número2

    fecha_nac año_nac

    Tipos de Datos<>  

    • Tipos

    En 'C' existen básicamente cuatro tipos de datos,
    aunque como se verá después, podremos definir
    nuestros propios tipos de datos
    a partir de estos cuatro. A continuación se detalla su
    nombre, el tamaño que ocupa en memoria y el
    rango de sus posibles valores.

    <> TIPO Tamaño Rango de
    valores

    <> char 1 byte -128 a 127

    int 2 bytes -32768 a 32767

    float 4 bytes 3'4 E-38 a 3'4 E+38

    double 8 bytes 1'7 E-308 a 1'7 E+308

    • Calificadores de tipo.- Los calificadores de
      tipo tienen la misión
      de modificar el rango de valores de
      un determinado tipo de variable. Estos calificadores son
      cuatro:

    Signed.-Le indica a la variable que va a llevar
    signo. Es el utilizado por defecto.

    • Tamaño rango de valores
    • signed char 1 byte -128 a 127
    • signed int 2 bytes -32768 a
      32767

    unsigned.- Le indica a la variable que no va a
    llevar signo (valor
    absoluto).

    Tamaño rango de valores

    • unsigned char 1 byte 0 a 255
    • unsigned int 2 bytes 0 a 65535

    short.- Rango de valores en formato corto
    (limitado). Es el utilizado por defecto.

    Tamaño rango de valores

      • short char<> 1
        byte -128 a 127
      • short int<> 2
        bytes -32768 a 32767
    • long.- Rango de valores en formato largo
      (ampliado).

    Tamaño rango de valores

    • Long int 4 bytes -2.147.483.648 a
      2.147.483.647
    • Long double<> 10
      bytes -3'36 E-4932 a 1'18 E+4932

         También es posible
    combinar calificadores entre sí:

    signed long int = long int = long

    unsigned long int = unsigned long 4 bytes 0 a
    4.294.967.295 (El mayor entero permitido en 'C')

    Las
    variables

    Una variable es un tipo de dato, referenciado mediante
    un identificador (que es el nombre de la variable). Su contenido
    podrá ser modificado a lo largo del programa.
    Una variable sólo puede pertenecer a un tipo de dato. Para
    poder utilizar una variable, primero tiene que ser
    declarada:

    [calificador] <tipo> <nombre>

    Es posible inicializar y declarar más de una
    variable del mismo tipo en la misma sentencia:

    [calificador] <tipo>

    <nombre1>,<nombre2>=<valor>,<nombre3>=<valor>,<nombre4>

    Ejemplo:

    /* Uso de las variables */

    #include <stdio.h>

    main() /* Suma dos valores */

    {

    int num1=4,num2,num3=6;

    printf("El valor de num1 es %d",num1);

    printf("nEl valor de num3 es %d",num3);

    num2=num1+num3;

    printf("nnum1 + num3 = %d",num2);

    }

    Declaración de variables

    Las variables pueden ser de dos tipos según el
    lugar en que las declaremos: globales o locales.

    La variable global se declara antes de la main( ). Puede
    ser utilizada en cualquier parte del programa y se destruye al
    finalizar éste.

    La variable local se declara después de la main(
    ), en la función en que vaya a ser utilizada. Sólo
    existe dentro de la función en que se declara y se
    destruye al finalizar dicha función.

    El identificador (nombre de la variable) no puede ser
    una palabra clave y los caracteres que podemos utilizar son las
    letras: a-z y A-Z (ojo! la ñ o Ñ no está
    permitida), los números: 0-9 y el símbolo de
    subrayado _. Además hay que tener en cuenta que el primer
    carácter no puede ser un número.

    /* Declaración de variables
    */

    #include <stdio.h>

    int a;

    main() /* Muestra dos
    valores */

    {

    int b=4;

    printf("b es local y vale %d",b);

    a=5;

    printf("na es global y vale
    %d",a);

    }

    Constantes
    Al
    contrario que las variables, las constantes mantienen su valor a
    lo largo de todo el programa.
    Para indicar al compilador que se trata de una constante,
    usaremos la directiva #define:

    <> #define <identificador>
    <valor>

    Observa que no se indica el punto y coma de final de
    sentencia ni tampoco el tipo de dato.
    La directiva #define no sólo nos permite sustituir
    un nombre por un valor numérico, sino también por
    una cadena de caracteres.

    El valor de una constante no puede ser modificado de
    ninguna manera.

    /* Uso de las constantes */

    #include <stdio.h>

    #define pi 3.1416

    #define escribe printf

    main() /* Calcula el perímetro
    */

    {

    int r;

    escribe("Introduce el radio:
    ");

    scanf("%d",&r);

    escribe("El perímetro es:
    %f",2*pi*r);

    }

    Secuencias de escape

    Ciertos caracteres no representados gráficamente
    se pueden representar mediante lo que se conoce como secuencia de
    escape.

    A continuación vemos una tabla de las más
    significativas:

    <> n<> salto de
    línea

    <>b<> retroceso

    <>t<> tabulación
    horizontal

    <>v<> tabulación
    vertical

    <>\<> contrabarra

    <>f<> salto
    de página

    <>'<> apóstrofe

    <>"<> comillas
    dobles

    <>0<> fin
    de una cadena de caracteres

    /* Uso de las secuencias de escape
    */

    #include <stdio.h>

    main() /* Escribe diversas sec. de escape
    */

    {

    printf("Me llamo "Nemo" el
    grande");

    printf("nDirección: C\ Mayor
    25");

    printf("nHa salido la letra
    'L'");

    printf("nRetrocesob");

    printf("ntEsto ha sido todo");

    }

    Inclusión de
    ficheros

    En la programación
    en C es posible utilizar funciones que no estén
    incluidas en el propio programa. Para ello utilizamos la
    directiva #include, que nos permite añadir
    librerías o funciones que se encuentran en otros ficheros
    a nuestro programa.

    Para indicar al compilador que vamos a incluir ficheros
    externos podemos hacerlo de dos maneras (siempre antes de las
    declaraciones).

         1. Indicándole al
    compilador la ruta donde se encuentra el fichero.

    <> #include "misfunc.h"

    #include "c:includesmisfunc.h"

         2. Indicando que se
    encuentran en el directorio por defecto del
    compilador.

    <> #include <misfunc.h>

    Operadores
    aritméticos y de
    asignación
    <>

    A continuación se explican los tipos de
    operadores (aritméticos y de asignación) que
    permiten realizar operaciones
    matemáticas en lenguaje C.

    Operadores aritméticos

    Existen dos tipos de operadores
    aritméticos:

    Los binarios:

    <> +<> Suma

    <> Resta

    *<> Multiplicación

    /<> División

    %<> Módulo
    (resto)

    Los unarios:

    <> ++<> Incremento (suma
    1)

    – –<> Decremento (resta
    1)

    <> Cambio de signo

    Su sintaxis es:

    <> binarios:

    <variable1><operador><variable2>

    <> unarios:

    <variable><operador> y al
    revés, <operador><variable>.

    /* Uso de los operadores aritméticos
    */

    #include <stdio.h>

    main() /* Realiza varias operaciones
    */

    <>

    {

    <> int a=1,b=2,c=3,r;

    r=a+b;

    printf("%d + %d = %dn",a,b,r);

    r=c-a;

    printf("%d – %d = %dn",c,a,r);

    b++;

    printf("b + 1 = %d",b);

    <>

    }

    Operadores de asignación

    La mayoría de los operadores aritméticos
    binarios explicados en el capítulo anterior tienen su
    correspondiente operador de asignación:

    <> =<> Asignación
    simple

    +=<> Suma

    -=<> Resta

    *=<> Multiplicación

    /=<> División

    %=<> Módulo
    (resto)

    Con estos operadores se pueden escribir, de forma
    más breve, expresiones del tipo:

    <> n=n+3 se puede escribir
    n+=3

    <> k=k*(x-2) lo podemos
    sustituir por k*=x-2

    /* Uso de los operadores de asignación
    */

    #include <stdio.h>

    main() /* Realiza varias operaciones
    */

    <>

    {

    <> int a=1,b=2,c=3,r;

    a+=5;

    printf("a + 5 = %dn",a);

    c-=1;

    printf("c – 1 = %dn",c);

    b*=3;

    printf("b * 3 = %d",b);

    <>

    }

    Jerarquía de los operadores

    Será importante tener en cuenta la precedencia de
    los operadores a la hora de trabajar con ellos:

    <> ( )<> Mayor
    precedencia

    ++, – –

    <> *, /, %

    <> +, –<> Menor
    precendencia

    Las operaciones con mayor precedencia se realizan antes
    que las de menor precedencia.
    Si en una operación encontramos signos del mismo nivel de
    precedencia, dicha operación se realiza de izquierda a
    derecha. A continuación se muestra un
    ejemplo sobre ello:

    <> a*b+c/d-e

    <> 1. a*b resultado =
    x

    2. c/d resultado = y

    3. x+y resultado = z

    4. z-e

    Fijarse que la multiplicación se resuelve antes
    que la división ya que está situada más a la
    izquierda en la operación. Lo mismo ocurre con la suma y
    la resta.

    /* Jerarquía de los operadores
    */

    #include <stdio.h>

    main() /* Realiza una operación
    */

    {

    int a=6,b=5,c=4,d=2,e=1,x,y,z,r;

    x=a*b;

    printf("%d * %d = %dn",a,b,x);

    y=c/d;

    printf("%d / %d = %dn",c,d,y);

    z=x+y;

    printf("%d + %d = %dn",x,y,z);

    r=z-e;

    printf("%d = %d",r,a*b+c/d-e);

    }

    Salida / Entrada

    Sentencia printf( )

    La rutina printf permite la aparición de valores
    numéricos, caracteres y cadenas de texto por
    pantalla.

    El prototipo de la sentencia printf es el
    siguiente:

    <> printf(control,arg1,arg2…);

     En la cadena de control indicamos la forma en que
    se mostrarán los argumentos posteriores. También
    podemos introducir una cadena de texto ( sin
    necesidad de argumentos ), o combinar ambas posibilidades,
    así como secuencias de escape.
    En el caso de que utilicemos argumentos deberemos indicar en la
    cadena de control tantos modificadores como argumentos vayamos a
    presentar.

    El modificador está compuesto por el caracter
    % seguido por un caracter de conversión, que indica
    de que tipo de dato se trata.

    /* Uso de la sentencia printf() 1.
    */

    #include <stdio.h>

    main() /* Saca por pantalla una suma
    */

    {

    int a=20,b=10;

    printf("El valor de a es %dn",a);

    printf("El valor de b es %dn",b);

    printf("Por tanto
    %d+%d=%d",a,b,a+b);

    }

    Los modificadores más utilizados
    son:

    <> %c<> Un único
    carácter

    %d<> Un entero con signo, en
    base decimal

    %u<> Un entero sin signo, en
    base decimal

    %o<> Un entero en base
    octal

    %x<> Un entero en base
    hexadecimal

    %e<> Un número real en
    coma flotante, con exponente

    %f<> Un número real en
    coma flotante, sin exponente

    %s<> Una cadena de
    caracteres

    %p<> Un puntero o dirección de memoria

    /* Uso de la sentencia printf() 2.
    */

    #include <stdio.h>

    main() /* Modificadores 1 */

    {

    char cad[]="El valor de";

    int a=-15;

    unsigned int b=3;

    float c=932.5;

    printf("%s a es %dn",cad,a);

    printf("%s b es %un",cad,b);

    printf("%s c es %e o %f",cad,c,c);

    }

    El formato completo de los modificadores es el
    siguiente:

    <> % [signo] [longitud] [.precisión]
    [l/L] conversión

    Signo: indicamos si el valor se ajustará a la
    izquierda, en cuyo caso utilizaremos el signo menos, o a la
    derecha ( por defecto ).

    Longitud: especifica la longitud máxima del valor
    que aparece por pantalla. Si la longitud es menor que el
    número de dígitos del valor, éste
    aparecerá ajustado a la izquierda.

    Precisión: indicamos el número
    máximo de decimales que tendrá el valor.

    l/L: utilizamos l cuando se trata de una variable de
    tipo long y L cuando es de tipo double.

    /* Uso de la sentencia printf() 3.
    */

    #include <stdio.h>

    main() /* Modificadores 2 */

    {

    char cad[ ]="El valor de";

    int a=25986;

    long int b=1976524;

    float c=9.57645;

    printf("%s a es %9dn",cad,a);

    printf("%s b es %ldn",cad,b);

    printf("%s c es
    %.3f",cad,c);

    <>

    }

    Sentencia scanf( )

    La rutina scanf permite entrar datos en la memoria del
    ordenador a través del teclado.
    El prototipo de la sentencia scanf es el
    siguiente:

    <> scanf(control,arg1,arg2…);

    En la cadena de control indicaremos, por regla general,
    los modificadores que harán referencia al tipo de dato de
    los argumentos. Al igual que en la sentencia printf los
    modificadores estarán formados por el carácter
    % seguido de un carácter de conversión. Los
    argumentos indicados serán, nuevamente, las variables.
    La principal característica de la sentencia scanf
    es que necesita saber la posición de la memoria del
    ordenador en que se encuentra la variable para poder almacenar la
    información obtenida. Para indicarle esta
    posición utilizaremos el símbolo ampersand (
    & ), que colocaremos delante del nombre de cada
    variable. ( Esto no será necesario en los arrays
    ).

    /* Uso de la sentencia scanf(). */

    #include <stdio.h>

    main() /* Solicita dos datos
    */

    <>

    {

    <> char nombre[10];

    int edad;

    printf("Introduce tu nombre: ");

    scanf("%s",nombre);

    printf("Introduce tu edad: ");

    scanf("%d",&edad);

    }

    Operadores Relaciónales

    Los operadores relacionales se utilizan para comparar el
    contenido de dos variables.
         En C++ existen seis operadores
    relacionales básicos:

    <> ><> Mayor
    que

    <<> Menor que

    >=<> Mayor o igual
    que

    <=<> Menor o igual
    que

    ==<> Igual que

    !=<> Distinto que

    El resultado que devuelven estos operadores es 1
    para Verdadero y 0 para Falso.
    Si hay más de un operador se evalúan de izquierda a
    derecha. Además los operadores == y !=
    están por debajo del resto en cuanto al orden de
    precedencia.

    /* Uso de los operadores relacionales.
    */

    #include <stdio.h>

    main() /* Compara dos números entre ellos
    */

    {

    int a,b;

    printf("Introduce el valor de A: ");

    scanf("%d",&a);

    printf("Introduce el valor de B: ");

    scanf("%d",&b);

    if(a>b)

    printf("A es mayor que B");

    else if(a<b)

    printf("B es mayor que A");

    else

    printf("A y B son iguales");

    }

    Sentencia Condicionales<>

    Este tipo de sentencias permiten variar el flujo del
    programa en base a unas determinadas condiciones.

    Existen varias estructuras diferentes:

    Estructura IF…ELSE

         Sintaxis:

    <> if (condición)
    sentencia;

    La sentencia solo se ejecuta si se cumple la
    condición. En caso contrario el programa sigue su curso
    sin ejecutar la sentencia.

         Otro formato:

    <> if (condición)
    sentencia1;

    else sentencia2;

    Si se cumple la condición ejecutará la
    sentencia1, sinó ejecutará la
    sentencia2. En cualquier caso, el programa
    continuará a partir de la sentencia2.

    /* Uso de la sentencia condicional IF.
    */

    #include <stdio.h>

    main() /* Simula una clave de acceso
    */

    {

    int usuario,clave=18276;

    printf("Introduce tu clave: ");

    scanf("%d",&usuario);

    if(usuario==clave)

    printf("Acceso permitido");

    else

    printf("Acceso denegado");

    }

    Otro formato:

    <> if (condición)
    sentencia1;

    else if (condición) sentencia2;

    else if (condición) sentencia3;

    else sentencia4;

    Con este formato el flujo del programa únicamente
    entra en una de las condiciones. Si una de ellas se cumple, se
    ejecuta la sentencia correspondiente y salta hasta el final de la
    estructura
    para continuar con el programa.

    Existe la posibilidad de utilizar llaves para ejecutar
    más de una sentencia dentro de la misma
    condición.

    /* Uso de la sentencia condicional ELSE…IF.
    */

    #include <stdio.h>

    main() /* Escribe bebé, niño o adulto
    */

    {

    int edad;

    printf("Introduce tu edad: ");

    scanf("%d",&edad);

    if (edad<1)

    printf("Lo siento, te has
    equivocado.");

    else if (edad<3) printf("Eres un
    bebé");

    else if (edad<13) printf("Eres un
    niño");

    else printf("Eres adulto");

    }

    Estructura
    SWITCH

    Esta estructura se
    suele utilizar en los menús, de manera que según la
    opción seleccionada se ejecuten una serie de
    sentencias.

    Su sintaxis es:

    <> switch (variable){

    case contenido_variable1:

    sentencias;

    break;

    case contenido_variable2:

    sentencias;

    break;

    default:

    sentencias;

    }

    Cada case puede incluir una o más sentencias sin
    necesidad de ir entre llaves, ya que se ejecutan todas hasta que
    se encuentra la sentencia break. La variable evaluada sólo
    puede ser de tipo entero o carácter.
    default ejecutará las sentencias que incluya, en
    caso de que la opción escogida no exista.

    /* Uso de la sentencia condicional SWITCH.
    */

    #include <stdio.h>

    main() /* Escribe el día de la semana
    */

    {

    int dia;

    printf("Introduce el día: ");

    scanf("%d",&dia);

    switch(dia){

    case 1: printf("Lunes"); break;

    case 2: printf("Martes"); break;

    case 3: printf("Miércoles");
    break;

    case 4: printf("Jueves"); break;

    case 5: printf("Viernes"); break;

    case 6: printf("Sábado");
    break;

    case 7: printf("Domingo"); break;

    }

    }

    Operadores Lógicos<>

    Los operadores lógicos básicos son
    tres:

    <> &&<> AND

    ||<> OR

    !<> NOT (El valor
    contrario)

    Estos operadores actúan sobre expresiones
    lógicas. Permiten unir expresiones lógicas simples
    formando otras más complejas.
    V = Verdadero F = Falso

    /* Uso de los op. lógicos AND,OR,NOT.
    */

    #include <stdio.h>

    main() /* Compara un número introducido
    */

    {

    int numero;

    printf("Introduce un número:
    ");

    scanf("%d",&numero);

    if(!(numero>=0))

    printf("El número es
    negativo");

    else
    if((numero<=100)&&(numero>=25))

    printf("El número está entre 25 y
    100");

    else
    if((numero<25)||(numero>100))

    printf("El número no está entre 25 y
    100");

    }


    Bucles 

    Los bucles son estructuras que permiten ejecutar partes
    del código de forma repetida mientras se cumpla una
    condición.

    Esta condición puede ser simple o compuesta de
    otras condiciones unidas por operadores
    lógicos.

    Sentencia WHILE

         Su sintaxis es:

    <> while (condición)
    sentencia;

    Con esta sentencia se controla la condición antes
    de entrar en el bucle. Si ésta no se cumple, el programa
    no entrará en el bucle.

    Naturalmente, si en el interior del bucle hay más
    de una sentencia, éstas deberán ir entre llaves
    para que se ejecuten como un bloque.

    /* Uso de la sentencia WHILE. */

    #include <stdio.h>

    main() /* Escribe los números del 1 al 10
    */

    {

    int numero=1;

    while(numero<=10)

    {

    printf("%dn",numero);

    numero++;

    }

    }

    Sentencia DO…WHILE

    Su sintaxis es:

    <> do{

    sentencia1;

    sentencia2;

    }while (condición);

    Con esta sentencia se controla la condición al
    final del bucle. Si ésta se cumple, el programa vuelve a
    ejecutar las sentencias del bucle.

    La única diferencia entre las sentencias while y
    do…while es que con la segunda el cuerpo del bucle se
    ejecutará por lo menos una vez.

    /* Uso de la sentencia DO…WHILE.
    */

    #include <stdio.h>

    main() /* Muestra un menú si no se pulsa 4
    */

    {

    char seleccion;

    do{

    printf("1.- Comenzarn");

    printf("2.- Abrirn");

    printf("3.- Grabarn");

    printf("4.- Salirn");

    printf("Escoge una opción:
    ");

    seleccion=getchar();

    switch(seleccion){

    case '1':printf("Opción
    1");

    break;

    case '2':printf("Opción
    2");

    break;

    case '3':printf("Opción
    3");

    }

    }while(seleccion!='4');

    }

    Sentencia FOR

    Su sintaxis es:

    <> for
    (inicialización;condición;incremento){

    sentencia1;

    sentencia2;

    }

    La inicialización indica una variable (variable
    de control) que condiciona la repetición del bucle. Si hay
    más, van separadas por comas:

    <> for (a=1,b=100;a!=b;a++,b-
    -){

    El flujo del bucle FOR transcurre de la siguiente
    forma:

    /* Uso de la sentencia FOR. */

    #include <stdio.h>

    main() /* Escribe la tabla de multiplicar
    */

    {

    int num,x,result;

    printf("Introduce un número:
    ");

    scanf("%d",&num);

    for (x=0;x<=10;x++){

    result=num*x;

    printf("n%d por %d =
    %dn",num,x,result);

    }

    }

    Sentencia BREAK

    Esta sentencia se utiliza para terminar la
    ejecución de un bucle o salir de una sentencia SWITCH.

    Sentencia CONTINUE

    Se utiliza dentro de un bucle. Cuando el programa llega
    a una sentencia CONTINUE no ejecuta las líneas de
    código que hay a continuación y salta a la
    siguiente iteración del bucle.

    Y aquí termina el capítulo dedicado a los
    bucles. Existe otra sentencia, GOTO, que permite al programa
    saltar hacia un punto identificado con una etiqueta, pero el buen
    programador debe prescindir de su utilización. Es una
    sentencia muy mal vista en la programación
    en C++.

    /* Uso de la sentencia CONTINUE. */

    #include <stdio.h>

    main() /* Escribe del 1 al 100 menos el 25
    */

    <>

    {

    int numero=1;

    while(numero<=100)

    {

    if (numero==25)

    <>

    {

    <> numero++;

    continue;

    }

    printf("%dn",numero);

    numero++;

    }

    }

    Funciones<>

    Las funciones son bloques de código utilizados
    para dividir un programa en partes más pequeñas,
    cada una de las cuáles tendrá una tarea
    determinada.

    Su sintaxis es:

    <> tipo_función
    nombre_función (tipo y nombre de argumentos)

    {

    bloque de sentencias

    }

    tipo_función: puede ser de cualquier tipo de los
    que conocemos. El valor devuelto por la función
    será de este tipo. Por defecto, es decir, si no indicamos
    el tipo, la función devolverá un valor de tipo
    entero ( int ). Si no queremos que retorne ningún
    valor deberemos indicar el tipo vacío ( void
    ).

    nombre_función: es el nombre que le daremos a la
    función.

    tipo y nombre de argumentos: son los parámetros
    que recibe la función. Los argumentos de una
    función no son más que variables locales que
    reciben un valor. Este valor se lo enviamos al hacer la llamada a
    la función. Pueden existir funciones que no reciban
    argumentos.

    bloque de sentencias: es el conjunto de sentencias que
    serán ejecutadas cuando se realice la llamada a la
    función.

    Las funciones pueden ser llamadas desde la
    función main o desde otras funciones. Nunca se debe
    llamar a la función main desde otro lugar del
    programa. Por último recalcar que los argumentos de la
    función y sus variables locales se destruirán al
    finalizar la ejecución de la misma.

    Declaración de las funciones

    Al igual que las variables, las funciones también
    han de ser declaradas. Esto es lo que se conoce como prototipo de
    una función. Para que un programa en C sea compatible
    entre distintos compiladores es imprescindible escribir los
    prototipos de las funciones.

    Los prototipos de las funciones pueden escribirse antes
    de la función main o bién en otro fichero. En este
    último caso se lo indicaremos al compilador mediante la
    directiva #include.

    En el ejemplo adjunto podremos ver la declaración
    de una función ( prototipo ). Al no recibir ni retornar
    ningún valor, está declarada como void en ambos
    lados. También vemos que existe una variable global
    llamada num. Esta variable es reconocible en todas las
    funciones del programa. Ya en la función main encontramos
    una variable local llamada num. Al ser una variable local,
    ésta tendrá preferencia sobre la global. Por tanto
    la función escribirá los números 10 y
    5.

    /* Declaración de funciones.
    */

    #include <stdio.h>

    void funcion(void); /* prototipo
    */

    int num=5; /* variable global */

    main() /* Escribe dos números
    */

    {

    int num=10; /* variable local */

    printf("%dn",num);

    funcion(); /* llamada */

    }

    void funcion(void)

    {

    printf("%dn",num);

    }

    Paso de parámetros a una
    función

    Como ya hemos visto, las funciones pueden retornar un
    valor. Esto se hace mediante la instrucción return,
    que finaliza la ejecución de la función,
    devolviendo o no un valor.
    En una misma función podemos tener más de una
    instrucción return. La forma de retornar un valor es la
    siguiente:

    <> return ( valor o expresión
    );

    El valor devuelto por la función debe asignarse a
    una variable. De lo contrario, el valor se
    perderá.

    En el ejemplo puedes ver lo que ocurre si no guardamos
    el valor en una variable. Fíjate que a la hora de mostrar
    el resultado de la suma, en el printf, también
    podemos llamar a la función.

    /* Paso de parámetros. */

    #include <stdio.h>

    int suma(int,int); /* prototipo */

    main() /* Realiza una suma */

    {

    int a=10,b=25,t;

    t=suma(a,b); /* guardamos el valor
    */

    printf("%d=%d",suma(a,b),t);

    suma(a,b); /* el valor se pierde
    */

    <>

    }

    int suma(int a,int b)

    {

    return (a+b);

    <>

    }

    Ahora veremos lo que se conoce como paso de
    parámetros.

    Existen dos formas de enviar parámetros a una
    función:

    Por valor: cualquier cambio que se
    realice dentro de la función en el argumento enviado,
    NO afectará al valor original de las variables
    utilizadas en la llamada. Es como si trabajáramos con una
    copia, no con el original. No es posible enviar por valor
    arrays,
    deberemos hacerlo por referencia.

    Por referencia: lo que hacemos es enviar a la
    función la dirección de memoria donde se encuentra la
    variable o dato. Cualquier modificación SI
    afectará a las variables utilizadas en la llamada.
    Trabajamos directamente con el original.

    /* Paso por valor. */

    #include <stdio.h>

    void intercambio(int,int);

    main() /* Intercambio de valores */

    {

    int a=1,b=2;

    printf("a=%d y b=%d",a,b);

    intercambio(a,b); /* llamada */

    printf("a=%d y b=%d",a,b);

    }

    void intercambio (int x,int
    y)

    <>

    {

    <> int aux;

    aux=x;

    x=y;

    y=aux;

    printf("a=%d y b=%d",x,y);

    }

    Para enviar un valor por referencia se utiliza el
    símbolo & (ampersand) delante de la variable
    enviada. Esto le indica al compilador que la función que
    se ejecutará tendrá que obtener la dirección
    de memoria en que se encuentra la variable.

    Vamos a fijarnos en los ejemplos. En el ejemplo anterior
    podrás comprobar que antes y después de la llamada,
    las variables mantienen su valor. Solamente se modifica en la
    función intercambio ( paso por valor ).

    En el siguiente ejemplo podrás ver como las
    variables intercambian su valor tras la llamada de la
    función ( paso por referencia ).

    Las variables con un * son conocidas como
    punteros, el
    único dato en 'C' que puede almacenar una dirección
    de memoria.

    /* Paso por referencia. */

    #include <stdio.h>

    void intercambio(int *,int *);

    main() /* Intercambio de valores */

    {

    int a=1,b=2;

    printf("a=%d y b=%d",a,b);

    intercambio(&a,&b); /* llamada
    */

    printf("a=%d y b=%d",a,b);

    }

    void intercambio (int *x,int
    *y)

    <>

    {

    <> int aux;

    aux=*x;

    *x=*y;

    *y=aux;

    printf("a=%d y b=%d",*x,*y);

    }

    Los argumentos de la función
    main

    Ya hemos visto que las funciones pueden recibir
    argumentos. Pues bién, la función main no
    podía ser menos y también puede recibir argumentos,
    en este caso desde el exterior.

    Los argumentos que puede recibir son:

    argc: es un contador. Su valor es igual al número
    de argumentos escritos en la línea de comandos,
    contando el nombre del programa que es el primer
    argumento.

    argv: es un puntero a un array de cadenas de
    carácteres que contiene los argumentos, uno por
    cadena.

    Arrays 

    Un array es un identificador que referencia un conjunto
    de datos del mismo tipo. Imagina un tipo de dato int; podremos
    crear un conjunto de datos de ese tipo y utilizar uno u otro con
    sólo cambiar el índice que lo referencia. El
    índice será un valor entero y positivo. En C los
    arrays comienzan por la posición 0.
    Vectores
    Un vector es un array unidimensional,
    es decir, sólo utiliza un índice para referenciar a
    cada uno de los elementos. Su declaración
    será:

    tipo nombre [tamaño];

    El tipo puede ser cualquiera de los ya conocidos y el
    tamaño indica el número de elementos del vector (
    se debe indicar entre corchetes [ ] ). En el ejemplo puedes
    observar que la variable i es utilizada como índice, el
    primer for sirve para rellenar el vector y el segundo para
    visualizarlo. Como ves, las posiciones van de 0 a 9 ( total 10
    elementos ).

    /* Declaración de un array.
    */

    #include <stdio.h>

    main() /* Rellenamos del 0 – 9 */

    {

    int vector[10],i;

    for (i=0;i<10;i++) vector[i]=i;

    for (i=0;i<10;i++) printf("
    %d",vector[i]);

    }

    Podemos inicializar (asignarle valores) un vector
    en el momento de declararlo. Si lo hacemos así no es
    necesario indicar el tamaño. Su sintaxis es:

    tipo nombre []={ valor 1, valor 2…}

    Ejemplos:

    int vector[]={1,2,3,4,5,6,7,8};

    char vector[]="programador";

    char
    vector[]={'p','r','o','g','r','a','m','a','d','o','r'};

    Una particularidad con los vectores de tipo
    char (cadena de carácteres), es que deberemos indicar en
    que elemento se encuentra el fin de la cadena mediante el
    carácter nulo (). Esto no lo controla el compilador, y
    tendremos que ser nosotros los que insertemos este
    carácter al final de la cadena.
    Por tanto, en un vector de 10 elementos de tipo char podremos
    rellenar un máximo de 9, es decir, hasta vector[8]. Si
    sólo rellenamos los 5 primeros, hasta vector[4], debemos
    asignar el carácter nulo a vector[5]. Es muy sencillo:
    vector[5]=''; .
    Ahora veremos un ejemplo de como se rellena un vector de tipo
    char.

    /* Vector de tipo char. */

    #include <stdio.h>

    main() /* Rellenamos un vector char */

    {

    char cadena[20];

    int i;

    for (i=0;i<19 &&
    cadena[i-1]!=13;i++)

    cadena[i]=getche( );

    if (i==19) cadena[i]='';

    else cadena[i-1]='';

    printf("n%s",cadena);

    }

    Podemos ver que en el for se encuentran dos
    condiciones:

    Que no se hayan rellenado todos los elementos
    (i<19).

    Que el usuario no haya pulsado la tecla ENTER, cuyo
    código
    ASCII es 13.

    (cadena[x-i]!=13).
    También podemos observar una nueva función llamada
    getche( ), que se encuentra en conio.h. Esta función
    permite la entrada de un carácter por teclado.
    Después se encuentra un if, que comprueba si se ha
    rellenado todo el vector. Si es cierto, coloca el carácter
    nulo en el elemento nº20 (cadena[19]). En caso contrario
    tenemos el else, que asigna el carácter nulo al elemento
    que almacenó el carácter ENTER.

    En resumen: al declarar una cadena deberemos reservar
    una posición más que la longitud que queremos que
    tenga dicha cadena.

    Llamadas a funciones con arrays

    Como ya se comentó en el tema anterior, los
    arrays únicamente pueden ser enviados a una función
    por referencia. Para ello deberemos enviar la dirección de
    memoria del primer elemento del array. Por tanto, el argumento de
    la función deberá ser un puntero.

    /* Envío de un array a una función.
    */

    #include <stdio.h>

    void visualizar(int []); /* prototipo
    */

    main() /* rellenamos y visualizamos
    */

    <>

    {

    <> int array[25],i;

    for (i=0;i<25;i++)

    {

    printf("Elemento nº %d",i+1);

    scanf("%d",&array[i]);

    }

    visualizar(&array[0]);

    <>

    }

    void visualizar(int array[]) /* desarrollo
    */

    <>

    {

    <> int i;

    for (i=0;i<25;i++)
    printf("%d",array[i]);

    <>

    }

    En el ejemplo se puede apreciar la forma de enviar un
    array por referencia. La función se podía haber
    declarado de otra manera, aunque funciona exactamente
    igual:

    <> declaración o prototipo

    void visualizar(int *);

    <> desarrollo de la función

    void visualizar(int *array)

    Matrices
    Una matriz es un
    array multidimensional. Se definen igual que los vectores
    excepto que se requiere un índice por cada
    dimensión.

    Su sintaxis es la siguiente:

    <> tipo nombre [tamaño
    1][tamaño 2]…;

    Una matriz
    bidimensional se podría representar gráficamente
    como una tabla con filas y columnas.

    La matriz tridimensional se utiliza, por ejemplo, para
    trabajos gráficos con objetos 3D.
    En el ejemplo puedes ver como se rellena y visualiza una matriz
    bidimensional. Se necesitan dos bucles para cada una de las
    operaciones. Un bucle controla las filas y otro las
    columnas.

    /* Matriz bidimensional. */

    #include <stdio.h>

    main() /* Rellenamos una matriz */

    {

    int x,i,numeros[3][4];

    /* rellenamos la matriz */

    for (x=0;x<3;x++)

    for (i=0;i<4;i++)

    scanf("%d",&numeros[x][i]);

    /* visualizamos la matriz */

    for (x=0;x<3;x++)

    for (i=0;i<4;i++)

    printf("%d",numeros[x][i]);

    }

    Si al declarar una matriz también queremos
    inicializarla, habrá que tener encuenta el orden en el que
    los valores
    son asignados a los elementos de la matriz. Veamos algunos
    ejemplos:

    <> int
    numeros[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

    Quedarían asignados de la siguiente
    manera:

    numeros[0][0]=1 numeros[0][1]=2 numeros[0][2]=3
    numeros[0][3]=4

    numeros[1][0]=5 numeros[1][1]=6 numeros[1][2]=7
    numeros[1][3]=8

    numeros[2][0]=9 numeros[2][1]=10 numeros[2][2]=11
    numeros[2][3]=12

    También se pueden inicializar cadenas de
    texto:

    char
    dias[7][10]={"lunes","martes","miércoles","jueves","viernes","sábado","domingo"};

    Para referirnos a cada palabra bastaría con el
    primer índice:

    <> printf("%s",dias[i]);

    Punteros.

    Un puntero es una variable que contiene la
    dirección de memoria de otra variable. Se utilizan para
    pasar información entre una función y sus
    puntos de llamada.

    Declaración
    Su sintaxis es la siguiente:

    <> tipo *nombre;

    Donde nombre es, naturalmente, el nombre de la variable,
    y tipo es el tipo del elemento cuya dirección almacena el
    puntero.

    Operadores
    Existen dos operadores especiales para trabajar con punteros:
    & y *.

    l primero devuelve la dirección de memoria de su
    operando. Por ejemplo, si queremos guardar en el puntero x
    la dirección de memoria de la variable num,
    deberemos hacer lo siguiente:

    <> x=&num;

         El segundo devuelve el
    valor de la variable cuya dirección es contenida por el
    puntero. Este ejemplo sitúa el contenido de la variable
    apuntada por x, es decir num, en la variable
    a:

    <> a=*x;

    Asignación
    Los punteros se asignan igual que el resto de las variables. El
    programa ejemplo mostrará las direcciones contenidas en
    p1 y p2, que será la misma en ambos
    punteros.

    /* Asignaciones de punteros. */

    #include <stdio.h>

    main() /* Asignamos direcciones */

    {

    int a;

    int *p1,*p2;

    p1=&a;

    p2=p1;

    printf("%p %p",p1,p2);

    }

    Aritmética de direcciones

    Es posible desplazar un puntero recorriendo posiciones
    de memoria. Para ello podemos usar los operadores de suma, resta,
    incremento y decremento (+, -, ++, – -). Si tenemos un puntero (
    p1 ) de tipo int ( 2 bytes ), apuntando a la
    posición 30000 y hacemos: p1=p1+5; el puntero
    almacenará la posición 30010, porque apunta 5
    enteros por encima ( 10 bytes más ).

    Estructuras

    Concepto de estructura

    Una estructura es un conjunto de una o más
    variables, de distinto tipo, agrupadas bajo un mismo nombre para
    que su manejo sea más sencillo.

    Su utilización más habitual es para la
    programación de bases de datos, ya que están
    especialmente indicadas para el trabajo con
    registros o
    fichas.

    La sintaxis de su declaración es la
    siguiente:

    <> struct tipo_estructura

    {

    tipo_variable nombre_variable1;

    tipo_variable nombre_variable2;

    tipo_variable nombre_variable3;

    };

    Donde tipo_estructura es el nombre del nuevo tipo
    de dato que hemos creado. Por último, tipo_variable
    y nombre_variable son las variables que forman parte de la
    estructura.

    Para definir variables del tipo que acabamos de crear lo podemos
    hacer de varias maneras, aunque las dos más utilizadas son
    éstas:

    Una forma de definir la estructura:

    <> struct trabajador

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    char puesto[10];

    };

    struct trabajador fijo, temporal;

    Otra forma:

    <> struct trabajador

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    char puesto[10];

    }fijo, temporal;

    En el primer caso declaramos la estructura, y en el
    momento en que necesitamos las variables, las declaramos. En el
    segundo las declaramos al mismo tiempo que la
    estructura. El problema del segundo método es
    que no podremos declarar más variables de este tipo a lo
    largo del programa. Para poder declarar una variable de tipo
    estructura, la estructura tiene que estar declarada previamente.
    Se debe declarar antes de la función
    main.

    El manejo de las estructuras es muy sencillo, así
    como el acceso a los campos ( o variables ) de estas estructuras.
    La forma de acceder a estos campos es la siguiente:

    <> variable.campo;

    Donde variable es el nombre de la variable de
    tipo estructura que hemos creado, y campo es el
    nombre de la variable que forma parte de la estructura. Lo
    veremos mejor con un ejemplo basado en la estructura del
    capítulo 13.1:

    <> temporal.edad=25;

    Lo que estamos haciendo es almacenar el valor 25 en el
    campo edad de la variable temporal de tipo
    trabajador.

    Otra carácterística interesante de las
    estructuras es que permiten pasar el contenido de una estructura
    a otra, siempre que sean del mismo tipo naturalmente:

    <> fijo=temporal;

    Al igual que con los otros tipos de datos,
    también es posible inicializar variables de tipo
    estructura en el momento de su
    declaración:

    <>     struct
    trabajador fijo={"Pedro","Hernández Suárez", 32,
    "gerente"};

    Si uno de los campos de la estructura es un array
    de números, los valores de
    la inicialización deberán ir entre
    llaves:

    <> struct notas

    {

    char nombre[30];

    int notas[5];

    <>};

    struct notas alumno={"Carlos
    Pérez",{8,7,9,6,10}};

    Estructuras y funciones

    Podemos enviar una estructura a una función de
    las dos maneras conocidas:

         1.- Por valor: su
    declaración sería:

    <> void visualizar(struct
    trabajador);

         Después
    declararíamos la variable fijo y su llamada
    sería:

    <> visualizar(fijo);

         Por último, el
    desarrollo de la función sería:

    <> void visualizar(struct trabajador
    datos)

    /* Paso de una estructura por valor. */

    #include <stdio.h>

    struct trabajador

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    char puesto[10];

    };

    void visualizar(struct trabajador);

    main() /* Rellenar y visualizar */

    {

    struct trabajador fijo;

    printf("Nombre: ");

    scanf("%s",fijo.nombre);

    printf("nApellidos: ");

    scanf("%s",fijo.apellidos);

    printf("nEdad: ");

    scanf("%d",&fijo.edad);

    printf("nPuesto: ");

    scanf("%s",fijo.puesto);

    visualizar(fijo);

    }

    void visualizar(struct trabajador datos)

    {

    printf("Nombre: %s",datos.nombre);

    printf("nApellidos: %s",datos.apellidos);

    printf("nEdad: %d",datos.edad);

    printf("nPuesto: %s",datos.puesto);

    }

    Por referencia: su
    declaración sería:

    <> void visualizar(struct trabajador
    *);

    Después declararemos la variable fijo y su
    llamada será:

    <> visualizar(&fijo);

    Por último, el desarrollo de la función
    será:

    <> void visualizar(struct trabajador
    *datos)

    Fíjate que en la función
    visualizar, el acceso a los campos de la variable
    datos se realiza mediante el operador ->, ya que
    tratamos con un puntero. En estos casos siempre utilizaremos el
    operador ->. Se consigue con el signo menos
    seguido de mayor que.

    /* Paso de una estructura por referencia.
    */

    #include <stdio.h>

    struct trabajador

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    char puesto[10];

    };

    void visualizar(struct trabajador
    *);

    main() /* Rellenar y visualizar */

    {

    struct trabajador fijo;

    printf("Nombre: ");

    scanf("%s",fijo.nombre);

    printf("nApellidos: ");

    scanf("%s",fijo.apellidos);

    printf("nEdad: ");

    scanf("%d",&fijo.edad);

    printf("nPuesto: ");

    scanf("%s",fijo.puesto);

    visualizar(&fijo);

    }

    void visualizar(struct trabajador
    *datos)

    {

    printf("Nombre:
    %s",datos->nombre);

    printf("nApellidos:
    %s",datos->apellidos);

    printf("nEdad:
    %d",datos->edad);

    printf("nPuesto:
    %s",datos->puesto);

    }

    Arrays de estructuras

    Es posible agrupar un conjunto de elementos de tipo
    estructura en un array. Esto se conoce como array de
    estructuras:

    <> struct trabajador

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    };

    struct trabajador fijo[20];

    Así podremos almacenar los datos de 20
    trabajadores. Ejemplos sobre como acceder a los campos y sus
    elementos: para ver el nombre del cuarto trabajador,
    fijo[3].nombre;. Para ver la tercera letra del nombre del
    cuarto trabajador, fijo[3].nombre[2];. Para inicializar la
    variable en el momento de declararla lo haremos de esta
    manera:

    struct trabajador fijo[20]={{"José","Herrero
    Martínez",29},{"Luis","García
    Sánchez",46}};

    Typedef
    Es posible agrupar un conjunto de elementos de tipo estructura en
    un array. Esto se conoce como array de estructuras:
         El lenguaje 'C' dispone de una
    declaración llamada typedef que permite la
    creación de nuevos tipos de datos. Ejemplos:

    typedef int entero; /* acabamos de crear un tipo de
    dato llamado entero */

    entero a, b=3; /* declaramos dos variables de este
    tipo */

    Su empleo con
    estructuras está especialmente indicado. Se puede hacer de
    varias formas:

    <> Una forma de hacerlo:

    <> struct trabajador

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    };

    typedef struct trabajador datos;

    datos fijo,temporal;

    Otra forma:

    <> typedef struct

    {

    char nombre[20];

    char apellidos[40];

    int edad;

    }datos;

    datos fijo,temporal;

    Ficheros
     

    Ahora veremos la forma de almacenar datos que podremos
    recuperar cuando deseemos. Estudiaremos los distintos modos en
    que podemos abrir un fichero, así como las funciones para
    leer y escribir en él.

    Apertura
    Antes de abrir un fichero necesitamos declarar un puntero de tipo
    FILE, con el que trabajaremos durante todo el proceso. Para
    abrir el fichero utilizaremos la función fopen(
    )
    .

         Su sintaxis es:

    <> FILE *puntero;

    puntero = fopen ( nombre del fichero, "modo de apertura"
    );

    Donde puntero es la variable de tipo FILE,
    nombre del fichero es el nombre que daremos al fichero que
    queremos crear o abrir. Este nombre debe ir encerrado entre
    comillas. También podemos especificar la ruta donde se
    encuentra o utilizar un array que contenga el nombre del archivo ( en este
    caso no se pondrán las comillas ).

    Algunos ejemplos:

    <> puntero=fopen("DATOS.DAT","r");

    puntero=fopen("C:\TXT\SALUDO.TXT","w");

    Un archivo puede ser abierto en dos modos diferentes, en
    modo texto o en modo binario. A continuación lo veremos
    con más detalle.

         Modo
    texto

    <> w<> crea un fichero
    de escritura. Si
    ya existe lo crea de nuevo.

    <> w+<> crea un
    fichero de lectura y
    escritura.
    Si ya existe lo crea de nuevo.

    <> a<> abre o crea un
    fichero para añadir datos al final del mismo.

    a+<> abre o crea un fichero
    para leer y añadir datos al final del mismo.

    r<> abre un fichero de
    lectura.

    r+<> abre un fichero de
    lectura y escritura.

         Modo
    binario

    <> wb<> crea un fichero
    de escritura. Si ya existe lo crea de nuevo.

    <> w+b<> crea un
    fichero de lectura y escritura. Si ya existe lo crea de
    nuevo.

    <> ab<> abre o crea un
    fichero para añadir datos al final del mismo.

    a+b<> abre o crea un fichero
    para leer y añadir datos al final del mismo.

    rb<> abre un fichero de
    lectura.

    r+b<> abre un fichero de
    lectura y escritura.

    La función fopen devuelve, como ya hemos visto, un
    puntero de tipo FILE. Si al intentar abrir el fichero se
    produjese un error ( por ejemplo si no existe y lo estamos
    abriendo en modo lectura ), la función fopen
    devolvería NULL. Por esta razón es mejor
    controlar las posibles causas de error a la hora de programar. Un
    ejemplo:

    <> FILE *pf;

    pf=fopen("datos.txt","r");

    if (pf == NULL) printf("Error al abrir el
    fichero");

         freopen(
    )

    Esta función cierra el fichero apuntado por el puntero y
    reasigna este puntero a un fichero que será abierto. Su
    sintaxis es:

    <> freopen(nombre del fichero,"modo de
    apertura",puntero);

    Donde nombre del fichero es el nombre del nuevo
    fichero que queremos abrir, luego el modo de apertura, y
    finalmente el puntero que va a ser reasignado.

    Cierre
    Una vez que hemos acabado nuestro trabajo con un fichero es
    recomendable cerrarlo. Los ficheros se cierran al finalizar el
    programa pero el número de estos que pueden estar abiertos
    es limitado. Para cerrar los ficheros utilizaremos la
    función fclose( );.

    Esta función cierra el fichero, cuyo puntero le
    indicamos como parámetro. Si el fichero se cierra con
    éxito
    devuelve 0.

    <> fclose(puntero);

    Un ejemplo ilustrativo aunque de poca utilidad:

    <> FILE *pf;

    pf=fopen("AGENDA.DAT","rb");

    if ( pf == NULL ) printf ("Error al abrir el
    fichero");

    else fclose(pf);

    Escritura y
    lectura

    A continuación veremos las funciones que se
    podrán utilizar dependiendo del dato que queramos escribir
    y/o leer en el fichero.

         Un
    carácter

    <> fputc( variable_carácter ,
    puntero_fichero );

         Escribimos un
    carácter en un fichero ( abierto en modo escritura ). Un
    ejemplo:

    <> FILE *pf;

    char letra='a';

    if (!(pf=fopen("datos.txt","w"))) /* otra forma de
    controlar si se produce un error */

    <>

    {

    <> printf("Error al abrir el
    fichero");

    exit(0); /* abandonamos el programa */

    }

    else fputc(letra,pf);

    fclose(pf);^b

    fgetc( puntero_fichero );

    Lee un carácter de un fichero ( abierto en modo
    lectura ). Deberemos guardarlo en una variable. Un
    ejemplo:

    <> FILE *pf;

    char letra;

    <> if (!(pf=fopen("datos.txt","r"))) /*
    controlamos si se produce un error */

    <>

    {

    <> printf("Error al abrir el
    fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    letra=fgetc(pf);

    printf("%c",letra);

    fclose(pf);

    }

         Un número
    entero

    <> putw( variable_entera, puntero_fichero
    );

    Escribe un número entero en formato binario en el
    fichero. Ejemplo:

    <> FILE *pf;

    int num=3;

    if (!(pf=fopen("datos.txt","wb"))) /* controlamos si
    se produce un error */

    <>

    {

    <> printf("Error al abrir el
    fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    fputw(num,pf); /* también podíamos haber
    hecho directamente: fputw(3,pf); */

    <> fclose(pf);

    }

    <> getw( puntero_fichero );

    Lee un número entero de un fichero, avanzando dos
    bytes después de cada lectura. Un ejemplo:

    <> FILE *pf;

    int num;

    if (!(pf=fopen("datos.txt","rb"))) /* controlamos si se
    produce un error */

    {

    printf("Error al abrir el fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    num=getw(pf);

    printf("%d",num);

    fclose(pf);

    }

        Una cadena de
    carácteres

    <> fputs( variable_array, puntero_fichero
    );

         Escribe una cadena de
    carácteres en el fichero. Ejemplo:

    <> FILE *pf;

    char cad="Me llamo Vicente";

    if (!(pf=fopen("datos.txt","w"))) /* controlamos si se
    produce un error */

    {

    printf("Error al abrir el fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    fputs(cad,pf); /* o también así: fputs("Me
    llamo Vicente",pf); */

    fclose(pf);

    }

    <> fgets( variable_array, variable_entera,
    puntero_fichero );

    Lee una cadena de caracteres del fichero y la almacena
    en variable_array. La variable_entera indica la longitud
    máxima de caracteres que puede leer. Un
    ejemplo:

    <> FILE *pf;

    char cad[80];

    if (!(pf=fopen("datos.txt","rb"))) /* controlamos si
    se produce un error */

    <>

    {

    <> printf("Error al abrir el
    fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    fgets(cad,80,pf);

    printf("%s",cad);

    fclose(pf);

    }

         Con
    formato

    <> fprintf( puntero_fichero, formato,
    argumentos);

    Funciona igual que un printf pero guarda la
    salida en un fichero. Ejemplo:

    <> FILE *pf;

    char nombre[20]="Santiago";

    int edad=34;

    if (!(pf=fopen("datos.txt","w"))) /* controlamos si se
    produce un error */

    {

    printf("Error al abrir el fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    fprintf(pf,"%20s%2dn",nombre,edad);

    fclose(pf);

    }

    <>

    <> fscanf( puntero_fichero, formato, argumentos
    );

    Lee los argumentos del fichero. Al igual que con un
    scanf, deberemos indicar la dirección de memoria de
    los argumentos con el símbolo & ( ampersand ).
    Un ejemplo:

    <> FILE *pf;

    char nombre[20];

    int edad;

    if (!(pf=fopen("datos.txt","rb"))) /* controlamos si
    se produce un error */

    <>

    {

    <> printf("Error al abrir el
    fichero");

    exit(0); /* abandonamos el programa */

    }

    else

    {

    fscanf(pf,"%20s%2d",nombre,&edad);

    printf("Nombre: %s Edad: %d",nombre,edad);

    fclose(pf);

    }

         Estructuras

    <> fwrite( *buffer, tamaño, nº
    de veces, puntero_fichero );

    Se utiliza para escribir bloques de texto o de datos,
    estructuras, en un fichero. En esta función,
    *buffer será la dirección de memoria de la
    cuál se recogerán los datos; tamaño,
    el tamaño en bytes que ocupan esos datos y nº de
    veces
    , será el número de elementos del
    tamaño indicado que se escribirán.

    <> fread( *buffer, tamaño, nº
    de veces, puntero_fichero );

    Se utiliza para leer bloques de texto o de datos de un
    fichero. En esta función, *buffer es la
    dirección de memoria en la que se almacenan los datos;
    tamaño, el tamaño en bytes que ocupan esos
    datos y nº de veces, será el número de
    elementos del tamaño indicado que se
    leerán.

    Puedes encontrar ejemplos sobre la apertura y cierre de
    ficheros, así como de la lectura y
    escritura de datos, en el archivo IMAGECAT.C. Se trata de
    un programa que crea un catálogo en formato HTML a partir de
    las imágenes
    que se encuentran en un directorio determinado.

    Otras funciones para ficheros

    <> rewind( puntero_fichero );

    Sitúa el puntero al principio del
    archivo.

    <> fseek( puntero_fichero, long posicion,
    int origen );

    Sitúa el puntero en la posicion que le
    indiquemos. Como origen podremos poner:

    <> 0 o SEEK_SET, el
    principio del fichero

    1 o SEEK_CUR, la posición
    actual

    2 o SEEK_END, el final del
    fichero

    <> rename( nombre1, nombre2 );

    Su función es exactamente la misma que la que
    conocemos en MS-DOS. Cambia el nombre del fichero
    nombre1 por un nuevo nombre, nombre2.

    <> remove( nombre );

    Como la función del DOS del, podremos
    eliminar el archivo indicado en nombre.

    Detección de final de fichero

    <> feof( puntero_fichero );

    Siempre deberemos controlar si hemos llegado al final de
    fichero cuando estemos leyendo, de lo contrario podrían
    producirse errores de lectura no deseados. Para este fin
    disponemos de la función feof( ). Esta
    función retorna 0 si no ha llegado al final, y un
    valor diferente de 0 si lo ha alcanzado.

    Pues con esto llegamos al final del tema. Espero que no
    haya sido muy pesado. No es necesario que te aprendas todas las
    funciones de memoria. Céntrate sobre todo en las funciones
    fputs( ), fgets( ), fprintf( ), fwrite(
    )
    y fread( ). Con estas cinco se pueden gestionar los
    ficheros perfectamente.

    Gestión
    Dinámica de
    Memoria
    <>

    Funciones
    Como veremos después, la gestión
    dinámica memoria se realiza mediante
    estructuras dinámicas de datos. Fíjate que se
    repite la palabra dinámica. Estas estructuras se
    diferencian de las estáticas ( arrays y estructuras
    ), en que no tienen un tamaño fijo, es decir, no tenemos
    que indicar su tamaño al declararlas, sino que podremos
    aumentarlo o disminuirlo en tiempo de ejecución,
    cuando se esté ejecutando la aplicación. Como
    puedes ver, las estructuras dinámicas son de gran utilidad. A
    continuación veremos las funciones que se encargan de
    reservar y liberar memoria durante la ejecución, que se
    encuentran en la librería alloc.h:
         malloc( tamaño
    );

    Esta función reserva en memoria una zona de
    tamaño bytes, y devuelve un puntero al inicio de
    esa zona. Si no hubiera suficiente memoria retornaría
    NULL. Más adelante veremos algunos
    ejemplos.

         free( puntero
    );

    Esta función libera de la memoria la zona que
    habíamos reservado anteriormente con la función
    malloc.

    Estructuras dinámicas de datos

    En función de la forma en que se relacionan
    existen varios tipos de estructuras de datos. Este tipo de
    estructuras son autorreferenciadas, es decir, contienen entre sus
    campos un puntero de su mismo tipo. Las más utilizadas
    son:

    <> – pilas

    – colas

    – listas

    Las pilas

    Este tipo de estructuras se carácteriza porque
    todas las operaciones se realizan en el mismo lado. Es de tipo
    LIFO ( Last In First Out ), el
    último elemento en entrar es el primero en
    salir.

    /* Ejemplo de una pila. */

    #include <stdio.h>

    #include <conio.h>

    #include <stdlib.h>

    #include <alloc.h>

    void insertar(void);

    void extraer(void);

    void visualizar(void);

    struct pila

    {

    char nombre[20];

    struct pila *ant;

    }*CAB=NULL,*AUX=NULL;

    main() /* Rellenar, extraer y visualizar
    */

    {

    char opc;

    do

    {

    clrscr(); /* borramos la pantalla
    */

    gotoxy(30,8); /* columna 30, fila 8
    */

    printf("1.- Insertar");

    gotoxy(30,10);

    printf("2.- Extraer");

    gotoxy(30,12);

    printf("3.- Visualizar la pila");

    gotoxy(30,14);

    printf("4.- Salir");

    opc=getch( );

    switch(opc)

    {

    case '1':

    insertar( );

    break;

    case '2':

    extraer( );

    break;

    case '3':

    visualizar( );

    }

    }while (opc!='4');

    <>

    }

    void insertar(void)

    {

    AUX=(struct pila *)malloc(sizeof(struct
    pila));

    clrscr();

    printf("Nombre: ");

    gets(AUX->nombre);

    if (CAB==NULL)

    {

    CAB=AUX;

    AUX->ant=NULL;

    }

    else

    {

    AUX->ant=CAB;

    CAB=AUX;

    }

    }

    void extraer(void)

    <>

    {

    <> if (CAB==NULL) return;

    AUX=CAB;

    CAB=CAB->ant;

    free(AUX);

    }

    void visualizar(void)

    {

    if (CAB==NULL) return;

    clrscr();

    AUX=CAB;

    while (AUX!=NULL)

    {

    printf("Nombre: %sn",AUX->nombre);

    AUX=AUX->ant;

    }

    getch( );

    }

    La estructura tipo que utilizaremos será
    ésta:

    <> struct pila

    {

    tipo variables;

    struct pila *ant;

    }*CAB=NULL,*AUX=NULL;

    Donde tipo variables serán las diferentes
    variables que guardaremos en la estructura, struct pila
    *ant
    es un puntero que apunta al elemento de tipo pila
    introducido anteriormente, *CAB será donde
    guardaremos el último elemento insertado en la pila y
    *AUX nos servirá para guardar elementos
    temporalmente y para recorrer la pila al visualizarla.

    Antes de insertar un elemento, deberemos comprobar si la
    pila está vacía o no. Si lo estuviera deberemos
    insertar el primer elemento:

    <> CAB=AUX;

    CAB->ant=NULL;

    Si ya hubiera algún elemento crearemos uno nuevo
    apuntado por AUX y haremos que AUX->ant apunte a
    CAB, que en este momento contiene la dirección del
    elemento insertado anteriormente. Tras esto haremos que
    CAB apunte al último elemento insertado, que
    será la nueva cabeza de la pila:

    <> AUX->ant=CAB;

    CAB=AUX;

    Para extraer un elemento de la pila deberemos hacer que
    AUX apunte a la misma dirección que CAB,
    después haremos que CAB apunte a
    CAB->ant, con lo que el elemento anterior pasará
    a ser la cabeza de la pila. Tras esto, solo queda liberar la
    memoria de la zona apuntada por AUX. No olvides controlar
    si existe algún elemento ( si CAB es igual a
    NULL la pila está vacía ):

    <> if (CAB==NULL) return;

    AUX=CAB;

    CAB=CAB->ant;

    free(AUX);

    Por último, para visualizar los elementos de la
    pila, haremos que el puntero auxiliar AUX apunte a la
    cabeza de la pila, o sea, a CAB. Tras esto iremos
    visualizando el contenido de la pila, haciendo que AUX
    tome la dirección de AUX->ant, mientras
    AUX sea distinto de NULL. También es
    importante controlar que la pila no esté
    vacía.

    <> if (CAB==NULL) return;

    AUX=CAB;

    while (AUX!=NULL)

    {

    printf("%s",AUX->nombre);

    AUX=AUX->ant;

    };

    Estructura gráfica de una pila:

    Las colas

    Este tipo de estructuras se carácteriza porque
    insertamos los elementos por un lado y los extraemos por el otro
    lado. Es de tipo FIFO ( First In
    First Out ), el primer elemento en entrar es el
    primero en salir. Para gestionar la cola utilizaremos 3
    punteros ( para la pila solo eran necesarios 2
    ).

    /* Ejemplo de una cola. */

    #include <stdio.h>

    #include <conio.h>

    #include <stdlib.h>

    #include <alloc.h>

    void insertar(void);

    void extraer(void);

    void visualizar(void);

    struct cola

    {

    char nombre[20];

    struct cola *sig;

    }*CAB=NULL,*AUX=NULL,*FIN=NULL;

    main() /* Rellenar, extraer y visualizar
    */

    <>

    {

    <> char opc;

    do

    {

    clrscr();

    gotoxy(30,8);

    printf("1.- Insertar");

    gotoxy(30,10);

    printf("2.- Extraer");

    gotoxy(30,12);

    printf("3.- Visualizar la cola");

    gotoxy(30,14);

    printf("4.- Salir");

    opc=getch( );

    switch(opc)

    {

    case '1':

    insertar( );

    break;

    case '2':

    extraer( );

    break;

    case '3':

    visualizar( );

    }

    }while (opc!='4');

    }

    void insertar(void)

    {

    AUX=(struct cola *)malloc(sizeof(struct
    cola));

    clrscr();

    printf("Nombre: ");

    gets(AUX->nombre);

    AUX->sig=NULL;

    if (FIN==NULL)

    FIN=CAB=AUX;

    else

    {

    FIN->sig=AUX;

    FIN=AUX;

    }

    }

    void extraer(void)

    <>

    {

    <> if (CAB==NULL) return;

    AUX=CAB;

    CAB=CAB->sig;

    free(AUX);

    }

     void visualizar(void)

    {

    if (CAB==NULL) return;

    clrscr();

    AUX=CAB;

    while (AUX!=NULL)

    {

    printf("Nombre: %sn",AUX->nombre);

    AUX=AUX->sig;

    }

    getch();

    }

    La estructura que utilizaremos será:

    <> struct cola

    {

    tipo variables;

    struct cola *sig;

    }*CAB=NULL,*AUX=NULL,*FIN=NULL;

    Donde tipo variables serán las diferentes
    variables que guardaremos en la estructura, struct cola
    *sig
    es un puntero que apunta al elemento de tipo cola
    introducido a continuación, *CAB será donde
    guardaremos el primer elemento insertado en la cola, *AUX
    nos servirá para guardar elementos temporalmente y para
    recorrer la cola al visualizarla y *FIN tomará la
    dirección del último elemento insertado.
    Antes de insertar un elemento, deberemos comprobar si la cola
    está vacía o no. Si lo está deberemos
    insertar el primer elemento:

    <> if (FIN==NULL)

    CAB=FIN=AUX;

    Si ya existiera algún elemento haremos que
    FIN->sig apunte al elemento de AUX y a
    continuación haremos que FIN tome la
    dirección de AUX, con lo que FIN
    apuntará al último elemento insertado.

    <> FIN->sig=AUX;

    FIN=AUX;

    Para extraer un elemento de la cola haremos que el
    puntero auxiliar AUX tome la dirección del primer
    elemento insertado, que hemos guardado en CAB.

    Tras esto haremos que CAB apunte a
    CAB->sig, es decir, que tome la dirección del
    segundo elemento insertado, que ahora pasará a ser el
    primero. Luego liberaremos la zona de memoria apuntada por
    AUX:

    AUX=CAB; /* Deberemos controlar que no esté
    vacía: if (CAB==NULL) return; */

    <> CAB=CAB->sig;

    free(AUX);

    Para visualizar la cola comprobaremos que existan
    elementos, esto es, que FIN sea distinto de NULL.
    Hecho esto asignaremos a AUX la dirección de
    CAB e iremos recorriendo la cola hasta que AUX sea
    igual a NULL.

    AUX=CAB; /* Deberemos controlar que no esté
    vacía: if (CAB==NULL) return; */

    <> while(AUX!=NULL)

    {

    printf("%s",AUX->nombre);

    AUX=AUX->sig;

    }

    Estructura gráfica de una cola:

    Las
    listas

    Este tipo de estructuras se caracteriza porque los
    elementos están enlazados entre sí, de manera que
    además de las acciones
    habituales de insertar, extraer y visualizar también
    podremos buscar un elemento. Para gestionar la lista utilizaremos
    4 punteros.

    /* Ejemplo de una lista. */

    #include <stdio.h>

    #include <conio.h>

    #include <stdlib.h>

    #include <alloc.h>

    void insertar(void);

    void extraer(void);

    void visualizar(void);

    struct lista

    {

    int num;

    struct lista *sig;

    <>}*CAB=NULL,*AUX=NULL,*F=NULL,*P=NULL;

    main() /* Rellenar, extraer y visualizar */

    {

    char opc;

    do

    {

    clrscr( );

    gotoxy(30,8);

    printf("1.- Insertar");

    gotoxy(30,10);

    printf("2.- Extraer");

    gotoxy(30,12);

    printf("3.- Visualizar la lista");

    gotoxy(30,14);

    printf("4.- Salir");

    opc=getch( );

    switch(opc)

    {

    case '1':

    insertar( );

    break;

    case '2':

    extraer( );

    break;

    case '3':

    visualizar( );

    }

    }while (opc!='4');

    <>

    }

    /* A continuación insertaremos el elemento
    quevamos a crear en la posición que le
    corresponda,teniendo en cuenta que la lista deberá
    quedarordenada de menor a mayor. El puntero P compruebasi el
    campo num de un elemento es menor que elcampo num del elemento
    introducido. El punteroF se quedará apuntando al
    elemento de la posición

    anterior al elemento que hemos insertado */

    void insertar(void)

    {

    AUX=(struct lista *)malloc(sizeof(struct
    lista));

    clrscr( );

    printf("Introduce un número: ");

    scanf("%d",&AUX->num);

    AUX->sig=NULL;

    if (CAB==NULL)

    CAB=AUX;

    else if (CAB->num > AUX->num)

    <>{

    <> AUX->sig=CAB;

    CAB=AUX;

    }

    else

    {

    P=F=CAB;

    while (P->num < AUX->num &&
    P!=NULL)

    <>{

    <> if (P==CAB) P=P->sig;

    else

    {

    P=P->sig;

    F=F->sig;

    <>}

    <>

    }

    <> AUX->sig=F->sig;

    F->sig=AUX;

    <>}

    <>

    }

    void extraer(void)

    {

    int var;

    if (CAB==NULL) return;

    clrscr( );

    printf("Introduce el número a extraer:
    ");

    scanf("%d",&var);

    if (CAB->num==var)

    {

    P=CAB;

    CAB=CAB->sig;

    free(P);

    }

    else

    {

    P=F=CAB;

    while (P->num != var && P!=NULL)

    {

    if (P==CAB) P=P->sig;

    else

    {

    P=P->sig;

    F=F->sig;

    }

    }

    if (P==NULL) return;

    F->sig=P->sig;

    free(P);

    }

    }

    void visualizar(void)

    <>

    {

    <> if (CAB==NULL) return;

    clrscr( );

    AUX=CAB;

    while (AUX!=NULL)

    <>{

    <> printf("Número:
    %dn",AUX->num);

    AUX=AUX->sig;

    }

    getch( );

    }

    La estructura que utilizaremos será:

    <> struct lista

    {

    tipo variables;

    struct lista *sig;

    }*CAB=NULL,*AUX=NULL,*F=NULL,*P=NULL;

    Donde tipo variables serán las variables
    que guardaremos en la estructura, struct lista *sig es un
    puntero que apunta al elemento de tipo lista introducido a
    continuación, *CAB será donde guardaremos el
    primer elemento de la lista, *AUX nos servirá para
    guardar elementos temporalmente y para recorrer la lista al
    visualizarla, *P para comparar los valores introducidos y
    ordenarlos, y *F, que apuntará al elemento anterior
    al último introducido.

    Antes de insertar un elemento, deberemos comprobar si la
    lista está vacía o no. Si lo está deberemos
    insertar el primer elemento:

    <> if (CAB==NULL) CAB=AUX;

    Si ya existiera algún elemento haremos que
    P y F apunten al primero de la lista. Si el
    elemento introducido fuera menor que el primero de la lista,
    haríamos que el nuevo elemento pasara a ser el primero, y
    el que hasta ahora era el primero, pasaría a ser el
    segundo.

    <> if (AUX->num <
    CAB->num){

    AUX->sig=CAB;

    CAB=AUX;

    }

    Para extraer un elemento de la lista solicitaremos un
    número, si el número introducido se corresponde con
    el campo num de uno de los elementos, éste será
    extraído de la lista. Deberemos controlar que la lista no
    esté vacía y que el elemento con el número
    solicitado exista.

    Fíjate en el ejemplo, en la función
    extraer. Si CAB es igual a NULL, será que la
    lista está vacía, y si P es igual a
    NULL al salir del while significará que no
    se ha encontrado ningún elemento que contenga el
    número introducido.

    Para visualizar la lista comprobaremos que existan
    elementos, es decir, que CAB sea distinto de NULL.
    Hecho esto asignaremos a AUX la dirección de
    CAB e iremos recorriendo la lista mientras AUX sea
    distinto de NULL.

    <> if (CAB==NULL) return;

    AUX=CAB;

    while(AUX!=NULL)

    {

    printf("%d",AUX->num);

    AUX=AUX->sig;

    }

    Estructura gráfica de una lista:

    Aquí finaliza el tema de la gestión
    dinámica de memoria. Es un tema algo complejo hasta que se
    asimila el concepto y
    funcionamiento de las diferentes estructuras, pero tras
    conseguirlo ya no tiene ningún secreto. Si alguna vez no
    recuerdas su funcionamiento siempre es una buena solución
    coger papel y
    lápiz, dibujar una pila, cola o lista gráficamente
    y simular la introducción de elementos, escribiendo la
    situación de los punteros en cada momento.

    Existen otras estructuras, como las listas doblemente
    enlazadas
    . La única diferencia con la lista que
    conocemos es que en las primeras cada elemento guarda la
    dirección del anterior y del posterior. Sería una
    estructura como esta:

    <> struct lista_doble

    {

    char nombre[20];

    struct lista_doble *ant;

    struct lista_doble *sig;

    };

    Su funcionamiento es muy similar al de una lista normal.
    Puedes intentar hacerla tu mismo.
    Otras estructuras, como los árboles son más
    complejas y menos utilizadas.

    Programación Gráfica

    Conceptos básicos

    El estándar de C++ no define ninguna
    función gráfica debido a las grandes diferencias
    entre las interfaces de los distintos tipos de hardware. Nosotros veremos
    el conjunto de funciones que utiliza Turbo C. La
    resolución más habitual del modo gráfico en
    Turbo C es de 640x480x16.

    Inicialización del modo
    gráfico

    Para poder trabajar en modo gráfico primero
    deberemos inicializarlo. Las funciones a utilizar son
    estas.

    <> detectgraph (int *tarjeta , int
    *modo);

    Detecta el tipo de tarjeta que tenemos instalado. Si en
    el primer argumento retorna -2 indica que no tenemos
    ninguna tarjeta gráfica instalada (cosa bastante
    improbable).

    <> initgraph (int *tarjeta , int *modo ,
    "path");

    Inicializa el modo gráfico ( primero hay que usar
    detectgraph ). En path deberemos indicar el
    directorio donde se encuentra el archivo
    EGAVGA.BGI.

    <> int graphresult( );

    Retorna el estado del
    modo gráfico. Si no se produce ningún error
    devuelve 0, de lo contrario devuelve un valor entre
    -1 y -16.

    <> char grapherrormsg(int
    error);

    Retorna un puntero al mensaje de error indicado por
    graphresult.

    Finalización del modo gráfico

    <> closegraph( );

    Cierra el modo gráfico y nos devuelve al modo
    texto.

    <> restorecrtmode( );

    Reestablece el modo de video original (
    anterior a initgraph ).

    /* Inicialización del modo gráfico.
    */

    #include <graphics.h>

    main() /* Inicializa y finaliza el modo
    gráfico. */

    {

    int tarjeta, modo, error;

    detectgraph(&tarjeta,&modo);

    initgraph(&tarjeta,&modo,"C:\TC\BGI");

    error=graphresult( );

    if (error)

    {

    printf("%s",grapherrormsg(error));

    }

    else

    {

    getch( );

    closegraph( );

    }

    }

    Funciones

    <> int getmaxx( );

    Retorna la coordenada máxima horizontal,
    probablemente 639. Ej: hm=getmaxx( );

    <> int getmaxy( );

    Retorna la coordenada máxima vertical,
    probablemente 479. Ej: vm=getmaxy( );

    <> int getx( );

    Retorna la coordenada actual horizontal. Ej:
    hact=getx( );

    <> int gety( );

    Retorna la coordenada actual vertical. Ej: vact=gety(
    );

    <> moveto(int x , int y);

    Se mueve a las coordenadas indicadas. Ej:
    moveto(320,240);

    <> setcolor(color);

    Selecciona el color de dibujo y texto
    indicado. Ej: setcolor(1); o
    setcolor(BLUE);

    <> setbkcolor(color);

    Selecciona el color de fondo indicado. Ej:
    setbkcolor(4); o setbkcolor(RED);

    <> int getcolor( );

    Retorna el color de dibujo y texto
    actual. Ej: coloract=getcolor( );

    <> int getbkcolor( );

    Retorna el color de fondo actual. Ej:
    fondoact=getbkcolor( );

    <> int getpixel(int x , int y);

    Retorna el color del pixel en x,y. Ej:
    colorp=getpixel(120,375);

    <> cleardevice( );

    Borra la pantalla. Ej: cleardevice( );

    Funciones de dibujo

    <> putpixel(int x , int y ,
    color);

    Pinta un pixel en las coordenadas y color indicados. Ej:
    putpixel(100,50,9);

    <> line(int x1 , int y1 , int x2 , int
    y2);

    Dibuja una linea desde x1,y1 a x2,y2. Ej:
    line(20,10,150,100);

    <> circle(int x , int y , int radio);

    Dibuja un círculo del radio indicado y con centro
    en x,y. Ej: circle(320,200,20);

    <> rectangle(int x1 , int y1 , int x2 , int
    y2);

    Dibuja un rectángulo con la esquina superior
    izquierda en x1,y1 y la inferior derecha en x2,y2. Ej:
    rectangle(280,210,360,270);

    <> arc(int x , int y, int angulo1 , int
    angulo2 , int radio);

    Dibuja un arco cuyo centro está en x,y, de radio
    r, y que va desde angulo1 a angulo2. Ej:
    arc(200,200,90,180,40);

    <> setlinestyle(int estilo, 1 ,
    grosor);

    Selecciona el estilo de linea a utilizar. El estilo
    puede tomar un valor de 0 a 4. El grosor puede
    tomar dos valores: 1 = normal y 3 = ancho. Ej:
    setlinestyle(2,1,3);

    Funciones de relleno

    <> floodfill(int x , int y , int
    frontera);

    Rellena el area delimitada por el color indicado en
    frontera comenzando desde x,y. Ej:
    floodfill(100,30,12);

    <> setfillstyle(int pattern , int
    color);

    Selecciona el patrón y el color de relleno. El
    patrón puede tomar un valor de 0 a 12 Ej:
    setfillstyle(1,9);

    <> bar(int x1 , int y1, int x2 , int
    y2);

    Dibuja una barra ( rectángulo ) y si es posible
    la rellena. Ej: bar(200,200,400,300);

    <> bar3d(int x1 , int y1, int x2 , int y2 ,
    int profundidad , int tapa);

    Dibuja una barra en 3d, son los mismos valores que bar
    además de la profundidad y la tapa: 0 si la
    queremos sin tapa y 1 si la queremos con tapa. Ej:
    bar3d(100,100,400,150,40,1);

    <> pieslice(int x , int y , int angulo1 ,
    int angulo2 , int radio);

    Dibuja un sector. Hace lo mismo que arc, pero
    además lo cierra y lo rellena. Ej:
    pieslice(250,140,270,320,50);

    Funciones de escritura de texto

    <> outtextxy(int x , int y , char
    *);

    Muestra el texto indicado ( puede ser un array o puede
    escribirse al llamar a la función ) en las coordenadas
    x,y. Ej: outtextxy(50,50,"Esto es texto en modo
    gráfico");

    <> settextstyle(int fuente , int
    dirección , int tamaño);

    Selecciona el estilo del texto. Las fuentes
    más comunes son las que van de 0 a 4. La
    dirección puede ser: 0 = horizontal y 1 =
    vertical. El tamaño puede tomar un valor de 1 a
    10. Ej: settextstyle(2,0,5);

    <> setviewport(int x1 , int y1 , int x2 ,
    int y2 , int tipo);

    Define una porción de pantalla para trabajar con
    ella. La esquina superior izquierda está determinada por
    x1,y1 y la inferior derecha por x2,y2. Para tipo podemos indicar
    1, en cuyo caso no mostrará la parte de un dibujo
    que sobrepase los límites
    del viewport, o distinto de 1, que sí
    mostrará todo el dibujo aunque sobrepase los límites.
    Al activar un viewport, la esquina superior izquierda
    pasará a tener las coordenadas (0,0). Para volver a
    trabajar con la pantalla completa, deberemos escribir:
    viewport(0,0,639,479,1);.

    <> clearviewport( );

    Borra el contenido del viewport.

    Aquí concluye el tema del modo gráfico.
    Hay algunas funciones más, aunque su complejidad es mayor.
    Generalmente no se suelen utilizar más que las aquí
    descritas, pero puedes investigar en la ayuda de Turbo C para
    conocer alguna otra.

    • Investigar todo lo referente a Librerías o
      Bibliotecas

    Una librería es un conjunto de recursos
    (algoritmos) prefabricados que puede utilizar el programador para
    realizar determinadas operaciones.  Las declaraciones de las
    funciones utilizadas en estas librerías junto con algunas
    macros y
    constantes predefinidas que facilitan su utilización, se
    agrupan en ficheros de nombres conocidos que suelen encontrarse
    en sitios predefinidos. 

    Por ejemplo, en los sistemas UNIX, en
    /usr/include.  Estos ficheros se suelen llamar "de
    cabecera
    " porque es tradición utilizar las primeras
    líneas del programa para poner las directivas
    #include que los incluirá en el código
    fuente durante la fase de preprocesado.

    Librerías son trozos de código que
    contienen alguna funcionalidad pre-construida que puede ser
    utilizada por un ejecutable.  Por supuesto, las
    librerías contienen en su interior variables y
    funciones;  si como suponemos, son librerías C++, lo
    más probable es que estas variables y funciones
    estén encapsuladas en forma de clases.

    De forma general, el término
    librería se utiliza para referirse a un conjunto de
    módulos objeto .obj (resultados de
    compilación) agrupados en un solo fichero que suele tener
    las extensiones .LIB, .OBJ, .BPI
    [6]
    y .DLL.  Estos ficheros permiten tratar las
    colecciones de módulos como una sola unidad, y representan
    una forma muy conveniente para el manejo y desarrollo de
    aplicaciones grandes, además de ser un concepto muy
    fértil para la industria del
    software, ya que
    permiten la existencia de las librerías de los propios
    compiladores y de un mercado de
    utilidades y componentes adicionales.  Son las denominadas
    librerías 3pp (de terceras partes), en referencia a que no
    son incluidas de forma estándar con los compiladores, ni
    creadas por el programador de la aplicación.

    En este sentido el software se parece a
    cualquier otro mercado de
    componentes.  Además de las librerías
    más o menos extensas que acompañan a los
    compiladores, pueden adquirirse otras, que permiten añadir
    a nuestros programas las
    funcionalidades más diversas sin necesidad de ser un
    experto en cada área de la programación y sin
    necesidad de que tengamos que estar reinventando la rueda
    constantemente.

    Tipos

    En lo que respecta al lenguaje C++, existen tres tipos
    fundamentales de librerías que son :

    Librería Estándar

    La librería estándar ANSI C++ define la
    denominada que debe acompañar a cada implementación
    del compilador que se adhiera al estándar.  Es decir:
    el Estándar determina cuales son, como se llaman y como se
    utiliza este conjunto de algoritmos que deben acompañar
    (como mínimo) a cada implementación del compilador
    que quiera llamarse "Estándar".

    De otro lado, C++ incluye todas las funciones de la
    primitiva librería estándar de C mas otras
    nuevas.  Las primeras se han mantenido por razón de
    compatibilidad, aunque el diseño
    e importancia de las nuevas cambia drásticamente la
    filosofía del propio lenguaje. 

    Los ficheros de cabecera del C++ Estándar
    previstos para compatibilidad con el antiguo C, utilizan
    los mismos nombres .h para los ficheros de cabecera que
    este.  Son los siguientes:

    <assert.h>, <ctype.h>,
    <errno.h>, <float.h>,
    <limits.h>, <locale.h>,
    <math.h>, <setjmp.h>,
    <signal.h>, <stdarg.h>,
    <stddef.h>, <stdio.h>,
    <stdlib.h>, <string.h>,
    <time.h>

    Componentes 

    A grandes rasgos, podemos decir que la Librería
    Estándar C++ comprende los siguientes
    elementos:

    La denominada Librería Estándar de
    Plantillas abreviadamente STL.

    • Una utilidad de entrada/salida de flujos.
    • Una utilidad local (locale)
    • Una clase string para manejo estandarizado de cadenas
      de caracteres.
    • Una clase complex para manejo y representación
      estandarizada de números complejos.
    • Una clase valarray optimizada para la
      manipulación de matrices
      numéricas.
    • Un esquema para describir de modo uniforme el entorno
      de ejecución mediante la utilización de una clase
      estándar denominada numeric_limits y
      especialización para cada uno de los tipos de datos
      fundamentales.
    • Utilidades para manejo de memoria.
    • Soporte para utilización de juegos de
      caracteres y signos de diversos idiomas.
    • Utilidades para manejo de excepciones.
    • Funcionalidad
    • Si atendemos a su funcionalidad,  pueden
      agruparse en:
    • Clasificación: Clasifican caracteres ASCII, como
      letras, caracteres de control (no imprimibles),
      Mayúsculas/minúsculas etc.  Se definen en la
      cabecera <ctype.h>.
    • Entradas/Salidas de Consola:  Estas son las
      denominadas entrada/salida estándar.  Se refieren
      al teclado y a la pantalla (no pueden utilizarse directamente
      en las aplicaciones de interfaz gráfica).

    Conversión: Convierten caracteres y cadenas de
    caracteres desde formato alfabético a numérico de
    diversos tipos (float, int, long). También realizan la
    conversión inversa, de formatos numéricos a
    representaciones alfabéticas y de mayúsculas a
    minúsculas y viceversa.

    Diagnóstico:  Son rutinas destinadas a
    comprobaciones, a descubrir y corregir posibles
    errores.

    Directorio:  Rutinas para manejo de directorios y
    sus direcciones (path names).

    En linea (Inline):  Rutinas para versiones inline
    de funciones. El compilador genera el código
    correspondiente para las versiones inline cuando se utiliza
    #pragma intrinsic o si se solicita optimización al
    compilador (optimización de tiempo de
    ejecución).

    Entrada/Salida. Son rutinas que proporcionan manejo de
    flujos y operaciones de Entrada/Salida a bajo nivel (de Sistema
    Operativo).

    Manipulación. Manejo de cadenas y bloques de
    memoria: copiar, comparar, convertir y buscar.

    Matemáticas:  Para realizar cálculos
    matemáticos.

    De Memoria:  Proporcionan asignación
    dinámica de memoria.

    Miscelánea.  Se agrupan aquí rutinas
    varias, como las que posibilitan saltos (goto) no locales y las
    que manejan diferencias de tipo cultural o de lenguaje.  Por
    ejemplo representación de números, de moneda,
    formatos de fecha y hora, clasificación de tipo
    alfabético, etc.

    Control de proceso. 
    Rutinas que permiten invocar y terminar nuevos procesos desde
    otra rutina.

    Fecha y hora. Incluyen rutinaspara conversión y
    manipulación de variables de medida del tiempo(fecha y
    hora).

    Argumentos variables.  Rutinas utilizadas cuando se
    usan listas variables de argumentos, como en los casos de
    printf(), vscanf(), etc.

    Utilización

    Para utilizar una función de librería hay
    que incluirla en nuestro programa.  Para hacerlo se
    necesitan tres cosas (en realidad las exigencias son las mismas
    que con cualquier otra función, la diferencia estriba en
    la forma en que se realizan los pasos b y c):

    a:  Incluir en el código fuente las
    invocaciones a las funciones que estamos utilizando. 
    Ejemplo:

    printf("Esto es una llamada a la función
    "printf" de librerían");

    b:  Incluir en el código fuente los
    prototipos de dichas funciones.

    Puesto que los prototipos ya están incluidos en
    los ficheros estándar de cabecera, hay que indicar al
    compilador que los incluya.  Esto se realiza poniendo en
    nuestro fuente (normalmente al principio) una directiva de
    preprocesado #include que señala el fichero de
    cabecera que se debe añadir. Por ejemplo, si el manual indica que
    la función printf está definida en el
    fichero de cabecera stdio.h ponemos en nuestro
    código:

    #include <stdio.h>

    c:  Incluir en el fuente las
    definiciones de las funciones utilizadas.  Como
    alternativa se puede indicar al compilador que tales definiciones
    están en ficheros compilados previamente.

    En este último caso se dice que las definiciones
    de las funciones están en librerías de las
    que existen dos tipos: estáticas (.LIB, .OBJ y
    .BPI) y dinámicas (.DLL).  Toda la
    información que necesita el compilador está
    contenida en los ficheros de cabecera, por lo que las operaciones
    correspondientes son realizadas de forma automática; con
    la sola condición de que los ficheros y librerías
    correspondientes sean accesibles al compilador.

    No se debe olvidar que todas las cosas en la
    Librería Estándar C++ (que no están
    en ficheros de cabecera .h), se han definido en un espacio
    de nombres denominado std, por lo que es preciso referirse
    a él específicamente cuando se quieran utilizar
    estos recursos.

    Funciones y macros

    Hay que señalar que algunas funciones pueden
    venir implementadas de dos formas: como macro y como
    función; por ejemplo, la función
    isalnum, contenida en <ctype.h>. Esto
    significa que además de estar implementada como una
    función en la correspondiente librería (que se
    utiliza con los argumentos señalados en el manual),
    está definida como una macro de preprocesado en
    <ctype.h>, de forma que salvo indicación
    contraria, al realizar la compilación, el preprocesador
    transforma la llamada del programador en otra serie de sentencias
    equivalentes que utilizan los mismos argumentos.  El
    resultado es que en el código resultante, que luego pasa
    al compilador y al enlazador, no existe nada parecido a una
    llamada a una función isalnum (técnicamente
    el proceso es una sustitución inline de la
    función de librería.

    Para evitar que esto ocurra y por consiguiente que la
    llamada a islanum nunca llegue a producirse, basta con
    indefinir la correspondiente directiva; lo que se hace incluyendo
    al principio del código y debajo de la línea
    #include <ctype.h>, una linea de preprocesado adecuada, en
    este caso: #undef

    isalnum, con lo que el #define del preprocesador
    quedará sin efecto, con el resultado de que todas las
    invocaciones a isalnum de nuestro código
    serán respetadas por el preprocesador; más tarde,
    el enlazador cargará el código de isalnum
    (que extrae de la librería) con el resto de nuestro
    programa, y colocará en cada punto de nuestro
    código donde aparezca una invocación a dicha
    función, un salto a la dirección
    adecuada.

    En estos casos, el resultado es el mismo en ambas
    modalidades: como macro (por defecto) o como función de
    librería. La elección de una u otra es
    cuestión de optimización; para tomar una
    decisión es necesario comprobar y valorar dos
    aspectos:

    El tamaño del ejecutable que resulta en uno y
    otro caso: posiblemente mayor si se utiliza la función
    muchas veces y se adopta la macro.

    La velocidad de
    ejecución. Posiblemente mayor si se utiliza la
    función muchas veces (en bucles muy largos) y se utiliza
    la macro.

    Librería
    clásica

    Se pude decir que esta Librería es parte de la
    Librería Estándar correspondiente al C
    clásico.

    La calidad de un
    compilador C++ viene determinada en gran medida por la calidad y
    cantidad de su RTL; por su grado de adherencia al
    Estándar (debe incluir todos sus elementos) y por el grado
    de soporte que proporciona para la plataforma concreta a que se
    destina.

    Librería estáticas

    Denominadas también librerías-objeto, son
    colecciones de ficheros objeto .obj (compilados) agrupados
    en un solo fichero de extensión .LIB y
    .OBJ.

    Los prototipos de las funciones utilizadas en estas
    librerías, junto con algunas macros y
    constantes predefinidas que facilitan su uso, se agrupan en
    ficheros denominados "de cabecera", porque es
    tradición utilizar las primeras líneas del programa
    para poner las directivas #include que los
    incluirán en el fuente durante la fase de
    preprocesado.

    Así pues, las librerías estáticas
    se componen de uno o varios ficheros .lib, .obj o
    .bpi junto con uno o varios ficheros de cabecera
    (generalmente .h).

    Durante la fase de compilación, el enlazador
    incluye en el ejecutable los módulos correspondientes a
    las funciones de librería que hayan sido utilizadas en el
    programa, de forma que entran a formar parte del ejecutable, de
    ahí su nombre:  Librerías enlazadas
    estáticamente
    .

    Dejando aparte consideraciones de comodidad y rapidez,
    el  resultado de utilizar una de tales librerías no
    se diferencia en nada al que puede obtenerse programando las
    funciones o clases correspondientes y compilándolas como
    un módulo más de nuestra
    aplicación.

    El compilador Borland C++ dispone de una herramienta
    específica para la creación y manejo de
    librerías estáticas; el ejecutable
    TLIB.EXE.

    Librería dinámicas

    Otra forma de añadir funcionalidad a un
    ejecutable son las denominadas librerías de enlazado
    dinámico,
    generalmente conocidas como DLLs,
    acrónimo de su nombre en inglés
    ("Dynamic Linked Library").  Estas librerías se
    utilizan mucho en la programación para el SO
    Windows.  Este Sistema contiene
    un gran número de tales librerías de
    terminación .DLL, aunque en realidad pueden tener
    cualquier otra terminación .EXE, .FON, .BPI, .DRV
    etc.  Cualquiera que sea su terminación, de forma
    genérica nos referiremos a ellas como DLLs, nombre
    por el que son más conocidas.

    La programación tradicional de aplicaciones
    Windows utilizando la API del Sistema es en realidad una
    sucesión de llamadas a este tipo de librerías
    externas.  De hecho, este Sistema Operativo es en realidad
    un conjunto de tales DLLs.  La mayoría de los
    ficheros de disco asociados con el sistema son de este tipo, y se
    ha llegado a afirmar que escribir una DLL es escribir una
    extensión del propio Windows.

    Como utilizar
    Librerías

    Desde la óptica
    del programador C++, la utilización de Librerías
    comprende dos aspectos totalmente diferenciados:  Su
    utilización y quizás la
    construcción de alguna de ellas si nuestras
    aplicaciones son medianamente grandes.

    En cuanto al primer punto, es seguro que como
    mínimo utilice algunas de la "Librería
    Estándar".  En cuanto a su construcción, si se dedica a esto de
    programar en C++, antes o después pondrá manos a la
    obra.  Por cierto:  Hay empresas de
    software cuya principal actividad es precisamente fabricar y
    vender librerías.

    Cualquiera que sea el caso, tanto la utilización
    como la construcción, son diferentes según se trate
    de librerías estáticas o
    dinámicas.  

    Bibliografía:

    Lenguaje C++

    http://www.ciens.ula.ve/~amoret/c_plus.html


    http://www.cvc.uab.es/shared/teach/a21292/docs/cpp_arg.ppt

    http://www.lcc.uma.es/~pastrana/LP/tema2.pdf

    http://www.geocities.com/studioxl/hc.htm

    http://www.mundovb.net/mundoc/capitulo1-1.htm

    www.monografias.com/trabajos/introc/introc

    www.zator.com/Cpp/E1_2.htm


    http://w3.mor.itesm.mx/~jfrausto/Algoritmos/estructuras/notas/C++_intro.html

    Librerías

    http://www.zator.com/Cpp/E1_4_4b.htm

    http://www.zator.com/Cpp/E5.htm

    http://www.hispan.com/eltaller/Taller4.htm

    Nombre:

    Cristhian Patricio Castillo
    Martínez

    Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

    Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

    Categorias
    Newsletter