Monografias.com > Sin categoría
Descargar Imprimir Comentar Ver trabajos relacionados


PARTE II:

 

    MEMORIA DIN�MICA

    Cap�tulo VII: Memoria Principal y Aritm�tica
    de Punteros

    Al iniciar �sta segunda parte, vamos a comentar algunos
    aspectos que son de suma importancia y que el lector debe conocer y manejar,
    como lo es el uso y funcionamiento de la memoria, dentro de la computadora.

    Debemos iniciar diciendo que, La Memoria Principal; se
    compone de un conjunto de celdas b�sicas dotadas de una determinada
    organizaci�n.

    Ya que, la Memoria, es el lugar donde se guardan datos
    y programas.

    Tipos de Memoria

    La Memoria RAM

    Es aquella memoria que �se volatiliza� al apagar el equipo.
    A mayor cantidad de RAM, m�s ventanas se pueden abrir, m�s programas
    funcionando simult�neamente y menos bloqueos de la PC. Existen
    varios tipos de RAM, seg�n su forma de encapsulado.

    M�DULOS DIP (Dual Inline Package): eran chips
    de memoria de forma rectangular y chata. Presentaban dos l�neas
    de pines
    en sus laterales. Una muesca o punto sobre el chip indicaban
    cu�l es la pata n� 1 para evitar colocar el chip al rev�s en
    el z�calo de la mother. Hoy no se utilizan memorias RAM en formato
    DIP, pero s� todav�a como cach� en motherboards
    u otras tarjetas.

    M�DULOS SIP (Single Inline Package): se trataba
    de m�dulos de memoria RAM cuyos chips de memoria se encontraban soldados
    sobre una peque�a placa de circuito impreso que hac�a contacto
    con la motherboard con una sola hilera de pines soldados en uno de
    sus bordes. Los pines calzaban en un z�calo colocado en la mother.

    M�DULOS SIMM (Single Inline Memory Module):
    son m�dulos de memoria que tambi�n tienen una sola hilera de
    pines. Una peque�a placa de circuito tiene soldada en una o ambas caras
    varios chips de memoria. Estos m�dulos de memoria se presentan en dos
    versiones. Existen:

    -SIMM de 30 pines: organizan la cantidad total de
    memoria en renglones de a 8 bits. (Mother 486)

    -SIMM de 72 pines: organizan la cantidad total de
    memoria en renglones de a 32 bits. (Mother 486 o Pentium)

    M�DULOS DIMM (Double Inline Memory Module):
    similares a los SIMM, aunque poseen 168 pines y organizan la memoria
    en renglones de a 64 bits. Hay m�dulos DIMM de 168 pines para
    16, 32, 64, 128, 256 y hasta 512 MBytes. (Mother Pentium o Pentium II en adelante).

    M�DULOS DDR (Double Data Rate Synchronous DRAM):
    esta tecnolog�a transmite al doble de la velocidad del bus del sistema. Estas
    memorias se presentan en forma de m�dulos de 184 contactos o pines.

    Z�calos y Bancos

    Un banco es un conjunto de z�calos para insertar
    chips individuales (como los DIP, o SIP), o m�dulos de memoria RAM
    (SIMM de 30, SIMM de 72 o DIMM de 128 pines).

    Una motherboard posee m�s de un banco de memoria
    para agregar m�s memoria a la m�quina sin tener que retirar
    la que estaba instalada. Cada banco de memoria puede poseer 1, 2 �
    4 z�calos.

    Un banco organiza la cantidad total de memoria en
    renglones sucesivos seg�n el ancho del bus de datos del microprocesador.
    Por ejemplo, en un Intel 486 (bus de datos de 32 bits), para colocar memorias
    en los bancos deben respetarse las siguientes reglas:

    1.- Un banco de memoria debe tener en todos sus z�calos la misma cantidad
    de m�dulos.

    2.- Debe llenarse primero el banco 0, luego el banco 1, y
    as� sucesivamente (excepto si la motherboard posee autobanking).

    3.- Un banco debe tener m�dulos de la misma velocidad.
    No se puede colocar una memoria SIMM de 60 nanosegundos junto con otra de
    distinta velocidad.

    Memoria Cach�

    Estas memorias son de tipo est�ticas. Son muy
    veloces (10 ns) y tambi�n caras, ya que su proceso de fabricaci�n
    es mucho m�s complejo. Con una memoria cach� el micro
    lee una direcci�n de memoria y mientras procesa la informaci�n
    el cach� lee las restantes posiciones de memoria principal consecutivas.
    Cuando el micro necesite leer la pr�xima direcci�n de memoria,
    su contenido se encontrar� en cach�. De esta manera, se acelera
    mucho la velocidad de procesamiento.

    Una declaraci�n de variable como:        

    int var;

    produce una asociaci�n entre el nombre 'var' y un espacio
    de almacenamiento en memoria. Por lo tanto hay dos elementos relacionados
    con el nombre 'var': un valor que se puede almacenar alli y una direcci�n
    de memoria para la variable, algunos autores se refieren a estos dos aspectos
    como el "rvalue" y "lvalue" de la variable.
    Adem�s del identificador "var", tenemos la palabra "int" que nos indica
    el TIPO (type) de la variable. El tipo nos indica:
    1-CUANTAS CELDAS DE MEMORIA (bytes) se asocian a ese nombre de variable.
    2-DE QUE MODO SERAN INTERPRETADOS  los datos que se encuentren en tal
    localidad de memoria,
    1-Un byte es la menor unidad de informaci�n que pueden direccional
    la mayor�a de las computadoras. En la mayor�a de las arquitecturas
    el tipo char ocupa un solo byte, por lo tanto es la unidad m�nima.
    Un bool admite solo dos valores diferentes, pero es almacenado como
    un byte. El tipo integer ocupa generalmente 2 bytes, un long
    4, double 8, y asi con el resto de los tipos.
    2-El otro punto es la relaci�n entre LO QUE HAY en una celda de memoria
    y COMO ES INTERPRETADO. Lo que hay en un celda cuya extensi�n es un
    byte es simplemente un conjunto de ocho estados posibles (8 bits) que a nivel
    hardware admiten dos estados diferenciales, estados que pueden ser interpretados
    como 'verdadero / falso', 0/1, o cualquier otro par de valores. Una celda
    de memoria del sector de datos, podr�a contener algo como lo siguiente:

    Que es esto? Depende en gran parte del TIPO (type) que hayamos asociado a
    esa celda (y suponiendo que exista tal asociaci�n). Ese valor
    interpretado como un Hexadecimal es 0x61, en decimal es 97, y si fue asociada
    al tipo char representara la letra 'a', cuyo ASCII es igual a 97. En
    ninguna localidad de memoria hay algo como la letra 'a', lo que encontramos
    son valores binarios que en caso de estar asociados a char y en caso
    de que lo saquemos en pantalla como char hara que veamos encendidos
    ciertos pixeles de pantalla, en los cuales reconoceremos una representaci�n
    de la letra 'a'.
    La representaci�n binaria de datos ocupa demasiado espacio, por ese
    motivo es preferible utilizar el sistema Hexadecimal, ademas de ser muy f�cil
    de traducir a binario es mas econ�mico que este o el decimal. Observar
    los bytes de un sector de memoria de un programa facilita la comprensi�n
    sobre el modo en que cada tipo (type) se asocia a direcciones de memoria.
    Supongamos un programa que declara, define e inicializa las siguientes variables:

    Algunos Conceptos Importantes

    BIT: Acr�nimo
    del ingl�s "Binary Digit", o "D�gito Binario" es decir, cada
    uno de los 0 (ceros) o 1 (unos) que utiliza el sistema de numeraci�n
    en base 2. Esta es la forma en la que ordenador procesa toda la informaci�n.

    Byte: Tambi�n llamado "octeto", es el conjunto
    de 8 bit (ceros y unos) que se necesitan para codificar un car�cter,
    al ser un valor muy peque�o, se utilizan sus m�ltiplos: kilobyte,
    megabyte, gigabyte…

    Palabra: Unidad direccionable formadas por bits. Desde
    8 bits (1 byte) hasta 64 bits (8 bytes).

    ASCII: Siglas de "American Standard Code for Informati�n
    Interchange", o c�digo est�ndar americano para el intercambio
    de informaci�n. El conjunto b�sico de caracteres ASCII comprende
    s�lo las letras (del alfabeto ingl�s) y carece de acentos, de
    letras no inglesas (como la �) y de formatos (negrita, cursiva…),
    pero existen conjuntos de caracteres m�s amplios.

    Unicode: Han Ampliado a 16 bits, que se usan. Se puede
    representar todos los s�mbolos de los lenguajes de programaci�n.

    BCD: (Binary Code Decimal) se utilizan s�lo
    4 bits para representar las letras, los d�gitos y otros s�mbolos.
    Estos grupos de 4 bits se llaman nibble.

    Ejemplo:

    0=0000

    2=0010

    9=1001

    Apuntadores

    Una de las cosas m�s dif�ciles que encuentran
    los principiantes en C es entender el concepto de

    apuntadores. Me he encontrado a menudo que la principal raz�n
    por la que los principiantes tienen problemas con los apuntadores es que tienen
    una muy pobre o m�nima concepci�n de las variables, (del modo
    en que C hace uso de ellas). As� que comencemos con una discusi�n
    sobre las variables de C en general. Una variable en un programa es algo con
    un nombre, que contiene un valor que puede variar. El modo en que el compilador
    y el enlazador (linker) manejan esto es que asignan un bloque espec�fico
    de la memoria dentro de la computadora para guardar el valor de una variable.
    El tama�o de este bloque depende del rango en que a

    esta variable le es permitido variar. Por ejemplo, en PC�s
    de 32 bits, el tama�o de una variable de tipo entero (int) es de 4
    bytes, en una m�quina antigua de 16 bits los enteros tienen un tama�o
    de 2 bytes. En C el tama�o de un tipo de variable como una de tipo
    entero no tiene porqu� ser el mismo en todos los tipos de m�quinas.
    Es m�s en C disponemos de diferentes tipos de variables enteras, est�n
    los enteros largos (long int) y los enteros cortos (short int) sobre los que
    puedes averiguar en cualquier texto b�sico sobre C. El presente documento
    asume que se est� usando un sistema de 32 bits con enteros de 4 bytes.

    Recordemos, el tama�o de los tipo de datos usados
    en el lenguaje C:


    TABLA CON LOS TIPOS DE DATOS PREDEFINIDOS EN C


    >ENTEROS: numeros completos y sus negativos


    Palabra reservada:


    Ejemplo


    Tama�o (byte)


    Rango de valores


    Int


    -850


    2


    -32767 a 32767


    VARIANTES DE ENTEROS


    short int


    -10


    1


    -128 a 127


    unsigned int


    45689


    2


    0 a 65535


    long int


    588458


    4


    -2147483648 a 2147483647


    unsigned long


    20000


    4


    0 a 4294967295


    >REALES: n�meros con decimales o punto flotante


    Palabra reservada:


    Ejemplo


    Tama�o (byte)


    Rango de valores


    Float


    85


    4


    3.4×10-38 a 3.4×1038


    VARIANTES DE LOS REALES


    Double


    0.0058


    8


    1.7×10-308 a 1.7×10308


    long double


    1.00E-07


    10


    3.4×10-4932 a 1.1×104932


    >CAR�CTER: letras, digitos, s�mbolos,
    signos de puntuaci�n.


    Palabra reservada:


    Ejemplo


    Tama�o (byte)


    Rango de valores


    Char


    'O'


    1


    0 ……255

    Como ya se ha dicho, cuando hacemos una declaratoria, como
    int a;

    Le estamos indicando a la computadora la cantidad de almacenamiento
    (tama�o, que para el caso es de 2 bytes), adem�s indica c�mo
    se va a interpretar los datos guardados en ese lugar de la memoria (en nuestro
    caso, enteros).

    Y es a qui donde radica la importancia, de lo punteros, por
    que como ya se dijo, los Punteros o Apuntadores, son variables que
    contienen la direcci�n de otra variable.

    En forma gr�fica, la podemos representarlo, como se
    muestra en la figura de arriba. P, es apuntador hacia el entero identificado
    como "a", en el cual, se reservan dos bytes, para guardar el entero.
    3B, es la direcci�n de la variable. (NOTA: "3B", es s�lo
    por decir un dato, para que el lector tenga la idea de una direcci�n
    de memoria).

    Cabe mencionar que, un puntero, es una variable q termina
    con la direcci�n con la que comienza la variable a la que apunta:

    Los usos principales, que tienen, los punteros, son los siguientes:

    ->Nos ayuda, para que una funci�n devuelva m�s
    de un valor. Por ejemplo, una funci�n que devuelva un vector de enteros,
    en dicha funci�n mandamos la direcci�n del primer elemento a
    la funci�n principal, y a partir de ella, imprimimos todos los valores
    contenidos en el vector.

    ->Mejor uso de la memoria din�mica. Esto es lo
    que m�s nos tiene cuenta, el lector debe tener presente que, el uso
    de punteros, ayuda a ahorrar memoria y por consiguiente, hace m�s efectivo
    el uso y administraci�n de la misma.

    La forma de declarar un apuntador, es la siguiente:

    Int *p;

    Int->indica que, es un puntero hacia un entero.

    *->indica al compilador que esa variable, es un puntero

    p-> Es el identificador del puntero.

    Otros ejemplos:

    float *q; /*apuntador hacia un flotante*/

    char *z; /*puntero que contiene la direcci�n de una
    variable que guarda un car�cter */

    Para referirnos a un valor a trav�s de un apuntador,
    lo hacemos mediante un proceso llamado indirecci�n.

    Por ejemplo, para mandar a impresi�n el valor entero,
    hacia el cual a punta "p", ser�a as�:

    printf("%d", *p);

    Los punteros, pueden ser inicializados a 0, NULL �
    alguna direcci�n v�lida:

    float *p1;

    p1=0;

    p1=NULL;

    Ahora bien, para guardar la direcci�n de alguna variable,
    en un puntero, debemos conocer un nuevo amigo:

    &->Operador de Direcci�n.

    P1=&a;

    Con esa simple declaraci�n, estamos indic�ndole
    al compilador que p1, contendr� le direcci�n de memoria de a.

    Veamos algunos ejemplos:

    Ejemplo 7.1

    Dise�e un programa que muestre el uso de operadores
    b�sicos en la declaraci�n de punteros empleando el direccionamiento
    y el operador indirecci�n.

    #include <stdio.h>

    #include <conio.h>

    main()

    {

    int a;

    /*Declaraci�n de un puntero a un entero */

    int *p;

    clrscr();

    printf("Ingrese un valor ENTERO para la variable:n");

    scanf("%d", &a);

    while(a<0)

    {

    printf("ERROR, el valor debe ser mayor que cero:n");

    scanf("%d", &a);

    }

    clrscr();

    /*Limpiamos la pantalla */

    printf("a=%dn", a); /*Imprimo el valor de a*/

    printf("La direcci�n de a es %pn", &a);

    printf("*p=%pn", p); /*Imprimo la direcci�n que guarda
    p*/

    /*imprimo el valor guardado en la direccion a la que apunta
    p*/

    printf("a=%dn", *p);

    printf("El tama�o de *p es %dn", sizeof(p));

    getch();

    return 0;

    }

    Explicaci�n:

    Como ya se ha explicado, la forma de declaraci�n de
    un puntero consiste en colocar al tipo de dato al cual apunta, el operador
    asterisco (*), seguido del identificador del mismo. Debo hacer notar que,
    para mandar a impresi�n una direcci�n de memoria, debo hacerlo
    usando la expresi�n "%p", para lo cual es indistinto si mando
    directamente la direcci�n de memoria, haciendo uso del operador &
    (ejemplo: &a), o si le mando, a impresi�n el contenido de la variable
    apuntador. (ejemplo: "*p=%pn", p).

    La funci�n sizeof como su nombre lo indica,
    se utiliza para determinar el tama�o (en bytes) de alguna variable
    en espec�fico.

    Ejemplo 7.2

    Dise�e un programa, que sume dos variables de tipo
    entero, por medio de apuntadores.

    #include <stdio.h>

    #include <conio.h>

    main()

    {

    int a, b, c;

    int *p1, *p2, *p3; /*declaracion de los punteros */

    printf("Ingrese el valor de a:n");

    scanf("%d", &a);

    printf("Ahora el valor de b:n");

    scanf("%d", &b);

    c=a+b;

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

    /*asiganamos las direcciones a los punteros correspondientes/

    p1=&a;

    p2=&b;

    /*ahora desreferenciamos el valor de los punteros para sumarlos
    */

    printf("*p1 + *p2=%dn", *p1+*p2);

    p3=&c;

    printf(" Direcci�n de a es %pn Direccion de b es %pn Y
    la de c es %pnn", p1, p2, p3);

    getch();

    return 0;

    }

    con esta instrucci�n: *p1+*p2, estamos invocando
    el valor guardado en la direcci�n a la que apunta p1 y p2, por tanto
    se obtiene el mismo resultado, que si sum�ramos directamente las dos
    variable (a+b).

    Ejemplo 7.3

    Programa que, asigna valores a punteros y juega un poco con
    las direcciones y las desrefenciaciones.

    #include <stdio.h>

    #include <conio.h>

    main()

    {

    int a, b,c, *p1, *p2;

    void* p; /*puntero que apunta a void*/

    p1=&a;/*guarda la direcci�n de a*/

    *p1=1; /* a donde apunta p1, guarda el valor de uno */

    p2=&b;

    *p2=2;

    p1=p2; /*En p1, guarda la direccion a la que apunta p2*/

    *p1=0;

    p2=&c;

    *p2=3;/*a donde apunta p2, le asigno 3*/

    printf("a =%dn b =%dn c =%dnn", a,b,c);

    p=&p1; /*p contiene la direccion de p1*/

    p=p2;

    *p1=1;/*es como asignarle a C, el valor de 1*/

    /*con los cambios realizados imprimimos el nuevo

    valor de las variables */

    printf("a =%dn b =%dn c =%dnn", a,b,c);

    getch();

    return 0;

    }

    La salida que presenta este c�digo, es la siguiente:

    Punteros y Arreglos

    Si mat es un arreglo unidimensional, la direcci�n
    del primer elemento puede ser expresada tanto como &mat[0] o simplemente
    como mat.

    La direcci�n del elemento (i+1) se puede expresar
    como (mat+i), donde mat, representa la rireci�n del arreglo e "i",
    la posici�n espec�fica a la cual nos referimos.

    Si &mat[i] y (mat +i) representan la direcci�n
    del i-�simo elemento de mat, mat[i] y *(mat+i), representa el contenido
    de esa direcci�n.

    Por ejemplo, supongamos que tenemos el siguiente arreglo:

    Int mat[]={2, 16, -4, 29, 234, 12, 0, 3}

    Tenemos un arreglo de 8 posiciones, de las cuales ya hemos
    aprendido que, para referirnos a cada uno de esos valores, lo podemos hacer
    usando sub�ndices. As�:

    Mat[0]=2;

    Mat[1]=16;

    pero podemos acceder a ellos de un modo alternativo, usando
    punteros de la siguiente manera:

    int *ptr;

    ptr=&mat[0];

    y de esa manera, podemos imprimir los valores de nuestro
    arreglo, ya sea usando la notaci�n de arreglos o desreferenciando nuestro
    puntero.

    Ejemplo 7.4

    Utilice un puntero para imprimir los valores de un puntero
    de 6 posiciones.

    #include <stdio.h>

    #include <conio.h>

    main()

    {

    int mat[]={2,3,5,9,10,4};/*declaracion del arreglo*/

    int i;

    int *ptr;

    ptr=&mat[0];/*al puntero ptr, le asignamos la direccion
    del primer

    elemento del arreglo*/

    clrscr();

    printf("tttElementos del arreglo:nnn");

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

    {

    printf("mat[%d]=%dn", i, mat[i]); /*notacion de arreglos*/

    printf("ptr+%d=%dn", i, *(ptr+i));/*notacion de punteros*/

    }

    getch();

    return 0;

    }

    ahora, supongamos que, lo que tenemos es un arreglo multidimensional,
    entonces, podemos acceder a el mediante la siguiente sintaxis:

    multi[renglon][columna]

    *(*(multi + renglon) + columna)

    Para entender mejor lo que sucede, reemplacemos *(multi +
    renglon) con una X, tal que la expresi�n nos quede como *(X
    + columna) Ahora vemos que esta X es como un apuntador ya que la expresi�n
    se encuentra desreferenciada y sabemos que col es un entero. Aqu� la
    aritm�tica a utilizar es de un tipo especial llamada "aritm�tica
    de punteros". Eso

    significa que, ya que hablamos de un arreglo de enteros,
    la direcci�n a ser apuntada por (el valor de) X + columna + 1 debe
    ser mayor que la direcci�n de X + columna por una cantidad que
    es igual a sizeof(int) (el

    tama�o del tipo de dato entero). Ya que sabemos la
    estructura de memoria para arreglos bidimensionales, podemos determinar que
    en la

    expresi�n multi + renglon como se hizo arriba,
    multi + renglon + 1 hace que esto se incremente por un valor igual
    al necesario para "apuntar a" el siguiente rengl�n, lo cual
    ser�a entonces COLUMNAS * sizeof (int).

    Esto nos dice que si la expresi�n *(*(multi + renglones)
    + columnas)
    va a ser evaluada correctamente en tiempo de ejecuci�n,
    el compilador debe generar c�digo que tome en consideraci�n
    el valor de COLUMNAS, es decir, la segunda dimensi�n. Debido
    a la equivalencia entre las dos formas de expresi�n, esto se hace cierto
    ya sea que usemos la sintaxis de punteros o la de arreglos multi[renglon][columna].

    As� que para evaluar cualquiera de estas dos expresiones,
    se deben conocer 5 valores:

    1. La direcci�n del primer elemento del arreglo, la
    cual es conocida por la expresi�n multi, es decir, el

    nombre del arreglo.

    2. El tama�o y el tipo de los elementos que conforman
    el arreglo, en este caso sizeof(int).

    3. La segunda dimensi�n del arreglo.

    4. El valor espec�fico del �ndice para la primera
    dimensi�n, renglon en este caso.

    5. El valor espec�fico del �ndice para la segunda
    dimensi�n, columna en este caso.

    Una vez que conocemos esto, consideremos el problema de dise�ar
    una funci�n que manipula los elementos de un arreglo previamente declarado.
    Por ejemplo, uno que establecer�a un valor de 1 todos los elementos
    del

    arreglo multi.

    void set_value(int m_arreglo[][COLUMNAS])

    {

    int renglon, columna;

    for (renglon = 0; renglon < RENGLONES; renglon++)

    {

    for (columna = 0; columna < COLUMNAS; columna++)

    {

    m_arreglo[renglon][columna] = 1;

    }

    }

    }

    Y para llamar a esta funci�n usar�amos entonces:

    set_value(multi);

    Dentro de esta funci�n, hemos usado los valores establecidos
    por #define en RENGLONES y COLUMNAS, los

    cuales establecen los l�mites para los ciclos. Pero
    dentro de lo que le concierne al compilador, estas son

    simples constantes, es decir, no hay nada que les relacione
    directamente con el tama�o del arreglo dentro de la

    funci�n. renglon y columna son variables
    locales, por supuesto. La definici�n formal del par�metro le
    permite

    al compilador determinar las caracter�sticas del valor
    del puntero que ser� pasado en tiempo de ejecuci�n.

    Realmente no necesitamos la primera dimensi�n y, como
    veremos m�s adelante, habr� ocasiones en las que

    preferiremos no declararla en la definici�n de los
    par�metros de una funci�n, no quiere decir que eso se vuelva
    un h�bito o algo con lo que haya que ser consistente. Pero la segunda
    dimensi�n debe ser usada como se ha mostrado en la expresi�n
    del par�metro. La raz�n por la que la necesitamos es por la
    forma de la evaluaci�n de m_arreglo[renglon][columna]. Mientras
    que el par�metro define el tipo de datos (int en este caso) y las variables
    autom�ticas para rengl�n y

    columna son definidas en los ciclos for, s�lo un valor
    puede ser pasado usando un �nico par�metro. En este caso, es
    el valor de multi, como lo pasamos en la llamada a la funci�n,
    es decir, la direcci�n de su primer

    elemento, m�s bien referido como un apuntador al arreglo.
    As� que la �nica manera que tenemos de informar al compilador
    de la segunda dimensi�n es incluirlo expl�citamente en la definici�n
    del par�metro de la funci�n. De hecho y por lo general todas
    las dimensiones de orden mayor que uno, necesitan de arreglos multidimensionales.
    Esto significa que si hablamos de arreglos de 3 dimensiones, la segunda y
    tercera dimensiones deben estar especificadas en la definici�n del
    par�metro.

    Ejemplo 7.5

    /*Programa que lee un arreglo y una matriz usando

    aritm�tica de punteros */

    #include <stdio.h>

    #include <conio.h>

    #define M 3

    #define N 3

    main()

    {

    int x[3][3], y[3];

    int f=0,c=0;

    clrscr();

    for(f=0; f< M; f++)

    {

    for(c=0; c<N; c++)

    {

    printf("*(x+ %d)+%d)=", f,c);

    scanf("%d", *(x+f)+c);

    }

    printf("Elemento %d del vector:n", f);

    scanf("%d", &y[f]);

    }

    printf("IMPRESIONES:n");

    printf("*** MATRIZ ***n");

    for(f=0; f<M; f++)

    for(c=0; c<N; c++)

    printf("%d", *(*(x+f)+c));

    printf("n*** VECTOR ***n");

    for(f=0; f<M; f++)

    printf("%d", *(y+f));

    getch();

    return 0;

    }

    Ejemplo 7.6

    Uso de funciones

    #include <stdio.h>

    #include <conio.h>

    void generacion(int a[3][3], int b[3][3]);

    main()

    {

    int a[3][3]={1,2,3,4,5,6,7,8,9}; /*generamos dos matrices de igual tama�o*/

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

    int f,c;

    printf("LAS MATRICES GENERADAS SON:nn");

    printf("Matriz a:n");

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

    {

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

    printf("%d", a[f][c]);

    printf("n");

    }

    printf("Matriz b:n");

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

    {

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

    printf("%d", b[f][c]);

    printf("n");

    }

    generacion(a,b); /*la funci�n recibe como par�metros, las
    dos matrices*/

    getch();

    return 0;

    }

    void generacion (int a[3][3], int b[3][3])

    {

    int d[3][3],f,c;

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

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

    d[f][c]=a[f][c]*b[f][c];

     

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

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

    printf("Valor de la Fila %d y columna %d = %d n", f,c,*(*(d+f)+c));

    }

    Ejemplo 7.7

    Programa que dado un vector de enteros, aumenta en una unidad el valor de
    los miembros del arreglo y env�a la direcci�n del primer elemento
    como retorno a la funci�n principal. (Note, como hacer para devolver
    m�s de un valor)

    #include <stdio.h>

    #include <conio.h>

    /*funcion que devuelve una direcion de memoria*/

    int *valores (int a[]);

    main()

    {

    int a[]={2, 5, 9, 7, 10};

    int *p, i;

    clrscr();

    printf("Los valores del puntero, aumentado en uno, son:n");

    p=valores(a);

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

    printf("* %d *", *(p+i));

    getch();

    return 0;

    }

    int *valores (int a[])

    {

    int i, *p;

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

    a[i]=a[i]+1;

    p=&a[0];

    return (p);

    }

    Cuestionario

    1. �Cu�l es la diferencia entre memoria principal y memoria cach�?___________________________________________________________________________________________________________________________________________________________________________________________________________________
    2. 8 bytes es equivalente a:________ bits
    3. �Qu�s es un registro?:_____________________________________________________________________________________________________________________________
    4. �Para que nos sirven los puneteros?:___________________________________________________________________________________________________________________________
    5. �cu�l es la diferencia entre desreferenciaci�n e indirecci�n?__________________________________________________________________________________________________________________________

    Ejercicios:

    1. Dise�e un programa en C, que lea un arreglo de 20, lea los valores,
      luego los imprime y muestre la suma de sus elementos, usando notaci�n
      de punteros
    2. Dise�e un programa, que imprima, las direcciones de memoria de
      los elementos de una arreglo de 5X5, elementos
    3. Se desea conocer el n�mero de elementos de una cadena de caracteres,
      ingresada por el usuario. (NOTA: el final de una cadena es representada
      por un elemento nulo ��. Utilice aritm�tica de punteros para determinar
      este valor)
    4. Escriba un programa en C, que le permita al usuario, ingresar una cadena
      de caracteres (no mayor a 100 elementos) y luego, la imprima, en forma inversa,
      usando para ello, notaci�n de punteros.
    5. Un programa en C, contiene la siguiente declaraci�n:

    Char *mat[5]={"Yo", "Tu", "El", "Nosotros",
    "Ellos"};

    a)�Cu�l es el significado de mat?_________________________________

    b)�Qu� significa (mat+2)?_________________________________________

    c)�Qu� significa *(mat+2)?_________________________________________

     

    Cap�tulo VIII: Recursi�n

    La recursi�n, o recursividad, es una propiedad que
    tienen algunas funciones de llamarse a s� mismas. Lo cual es una alternativa,
    ante la iteraci�n.

    El uso de funciones recursivas, ayudan a que �l programador
    ahorre (en la mayor�a de los casos) muchas l�neas de c�digo.

    Todos los ejemplos que se han presentado hasta ahora, est�n
    bajo la l�nea de programaci�n estructurada, por tanto son soluciones
    correctas. Sin embargo, como programadores, en muchas ocasiones nos
    podemos enfrentar a la necesidad de utilizar funciones que se llamen a s�
    mismas. En muchos libros, cursos o seminarios de programaci�n, se hace
    mucho �nfasis a �ste t�pico, y por supuesto, no dejar�amos
    pasar la oportunidad de hablar de ello y darle el lugar que se merece.

    En forma gr�fica, una funci�n recursiva, ser�a
    m�s o menos as�:

    Funcion1(…)

    {

    funcion1(…);

    }

    en �ste cap�tulo, trataremos de darle mayor
    prioridad a los ejemplos, es por ello, que, iniciaremos con el ejemplo m�s
    emblem�tico de una funci�n recursiva, como es el caso del factorial.

    Ejemplo 8.1

    Realice una funci�n recursiva que muestre el factorial
    de un n�mero ingresado por el usuario.

    Un n�mero factorial, se define como:

    n!=nx(n-1)X(n-2)x….x1

    lo cual puede representarse as�:

    0!=1

    1!=1

    2!=2X1

    3!=3x2x1

    y la forma recursiva para ello ser�a:

    2!=2×1!

    3!=3×2!

    n!=nx(n-1)!

    #include <stdio.h>

    #include <conio.h>

    int factorial (int n); /*declaraci�n de la funci�n*/

    main()

    {

    int n, r;

    printf("Ingrese el Valor del factorial que desea Calcular:n");

    scanf("%d", &n);

    while(n<0)

    {

    printf("Ingrese el Valor del factorial que desea Calcular:n");

    scanf("%d", &n);

    }

    r=factorial(n); /*llamado de la funci�n*/

    printf("El valor de %d!= %dn", n, r);

    getch();

    return 0;

    }

    int factorial (int n)

    {

    int r;

    if(n==0)/*CASO BASE: al resultar cierta se sale de la recursi�n*/

    r=1;

    else

    r=n*factorial(n-1); /*llamado recursivo de la funci�n
    */

    return r;

    }

    Explicaci�n:

    El programa, lo que hace, es mandarle el par�metro
    a la funci�n factorial (supongamos que n=2). Entonces pregunta si n=0,
    al evaluar, resulta falsa, por tanto nos vamos por el lado del else, y asigna
    a r el valor de 3, por la llamada recursiva de n-1, (es decir 2. r=2*factorial(1)).
    Y vuelve a evaluar la condici�n, resulta falsa y vuelve a llamar la
    funci�n (r=1*factorial(0)). Por tanto, al evaluar la condici�n
    esta vez, resultar� cierta, y le asigna el valor de 1, el cual lo retorna
    a la llamada anterio (r=1*1), este resultado, lo devuelve a la llamada que
    se hizo antes de �sta (r=2*1). Y este resultado, se devuelve a la llamada
    anterior. �sta es la que se hizo en la funci�n original, y luego
    se imprime ese valor

    Antes de continuar, debemos hacer hincapi� en algo
    muy importante, como lo es: la forma en la cual, dejar�amos de ejecutar
    las llamadas iterativas, ya que debe existir alguna condici�n que,
    al resultar cierta, ya no haga m�s llamadas recursivas y por el contrario,
    empiece a retornar los valores de la funci�n. A esto se le llama Caso
    Base.

    Un Caso Base, son los casos del problema que se resuelven
    sin recursi�n, para nuestro primer ejemplo es 0, por que el factorial
    de cero, est� definido como 1 (uno).

    Si el problema es lo suficientemente complejo, debemos hacer
    uso de Los casos generales, que son definidos como la soluci�n
    de uno o m�s problemas o un conjunto de pasos adicionales. Sin embargo,
    debemos tener en cuenta que, los casos generales, deben avanzar hacia un caso
    base, de lo contrario tendremos una recursi�n infinita.

    Ejemplo 8.2

    Realice una funci�n recursiva que calcule la suma
    de dos enteros.

    Soluci�n:

    Si tenemos por ejemplo a+b, la suma ser�a "a",
    siempre y cuando "b" sea cero, de lo contrario, recursivamente,
    ser�a: 1+suma(a, b-1).

    #include <stdio.h>

    #include <conio.h>

    int suma (int a, int b);

    main()

    {

    int a, b, r;

    clrscr();

    printf("Ingrese el primer sumando:n");

    scanf("%d", &a);

    printf("Ingrese el segundo sumando:n");

    scanf("%d", &b);

    r=suma(a,b);

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

    getch();

    return 0;

    }

    int suma (int a, int b)

    {

    int r;

    if(b==0)/*caso base*/

    r=a;

    else

    r=1+suma(a, b-1);/*llamada recursiva, disminuimos b, para
    que en un

    return r;} momento dado, sea igual a cero*/

    Ejemplo 8.3

    Dise�e un programa que multiplique, dos valores enteros, recursivamente.

    Sabemos muy bien que, a*b, es igual a sumar a+a+a+a+a+……b veces.

    Pero si b=1, entonces, el producto es igual a "a".

    #include <stdio.h>

    #include <conio.h>

    int multi (int a, int b);

    main()

    {

    int a, b, r;

    clrscr();

    printf("Ingrese el valor del multiplicando:n");

    scanf("%d", &a);

    printf("Ahora el multiplicador:n");

    scanf("%d", &b);

    r=multi(a, b);

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

    getch();

    return 0;

    }

    int multi (int a, int b)

    {

    int r;

    if(b==1)/*elemento neutro de la multiplicaci�n, que es nuestro caso
    base*/

    r=a;

    else

    r=a+multi(a, b-1);/*llamada recursiva de la funci�n, disminuimos
    b, para que llegue un momento en el que sea igual a 1, y le sumamos a, por
    que as� est� definida la multiplicaci�n, como la suma
    de "a", b veces*/

    return r;

    }

    Ejemplo 8.4

    Calcule, recursivamente la expresi�n: Xn

    #include <stdio.h>

    #include <conio.h>

    int exp (int base, int p);

    main()

    {

    int base, p, r;

    clrscr();

    printf("Ingrese la Base:n");

    scanf("%d", &base);

    printf("Exponente es:n");

    scanf("%d", &p);

    r=exp(base, p);

    printf("%d^%d=%dnn", base, p, r);

    getch();

    return 0;

    }

    int exp (int base, int p)

    {

    int r;

    if(p==0)

    r=1;

    else

    r=base*exp(base, p-1);

    return r;

    }

    Ejemplo 8.5

    Obtenga, recursivamente el M�ximo Com�n Divisor,
    mcd(m,n), de dos n�meros, sabiendo que:

    -es n si n<m y n divide a m

      • es mcd(n,m) si m<n
      • es mcd(n, residuo de m/n), en caso contrario

    #include <stdio.h>

    #include <conio.h>

    int mcd (int m, int n);

    main()

    {

    int r, m, n;

    clrscr();

    printf("PROGRAMA QUE CALCULA EL M.C.D.n");

    printf("Ingrese un N�mero:n");

    scanf("%d", &m);

    printf("El otro es:n");

    scanf("%d", &n);

    r=mcd(m,n);

    printf("el mcd de %d y %d es %dn", m,n, r);

    getch();

    return 0;

    }

    int mcd (int m, int n)

    {

    int r;

    if(n<=m && m%n==0)

    r=n;

    else

    if(m<n)

    r=mcd(m,n);

    else

    r=mcd(n, m%n);

    return r;

    }

    Ejemplo 8.6:

    Programa que calcula la secuencia de Fubonacci, recursivamente:

    #include <stdio.h>

    #include <conio.h>

    int fubonacci (int n);

    main()

    {

    int n, r;

    printf("PROGRAMA QUE IMPRIME LA SECUENCIA DE FOBONACCIn");

    printf("Ingrese el valor de n:n");

    scanf("%d", &n);

    printf("** %d **", r);

    getch();

    return 0;

    }

    int fobonacci (int n)

    {

    int r;

    if(n==0 || n==1)

    r=n;

    else

    r=fobonacci(n-1)+fobonacci(n-2);

    return r;

    }

    Ejemplo 8.7:

    /*Programa que calcula la suma de los primeros

    n numeros enteros, positivos */

    #include <stdio.h>

    #include <conio.h>

    int func (int n);

    main()

    {

    int n, r;

    clrscr();

    printf("A partir de cero… �Hasta que n�emro desea sumar?n");

    scanf("%d", &n);

    r=func(n);

    printf("La suma de los primeros %n numeros eneteros es:
    %dn", n, r);

    getch();

    return 0;

    }

    int func (int n)

    {

    int r;

    if(n==0)

    r=0;

    else

    r=n+func(n-1);

    return r;

    }

    Este programa, lo que hace es sumar desde cero, hasta el
    n, n�mero entero.

    Ejemplo 8.8:

    Programa que calcula, la suma de los primeros n elementos
    de un vector:

    #include <stdio.h>

    #include <conio.h>

    int sumav(int v[], int n);

    main()

    {

    int n, r, v[]={1,2,3,4,5,6,7,8,9};

    clrscr();

    printf("Ingrese el valor hasta el cual dsea sumar:n");

    scanf("%d", &n);

    while(n<0 || n>9)

    {

    printf("Error, numero no v lido vuelva a intertarlo:n");

    scanf("%d", &n);

    }

    r=sumav(v, n);

    printf("El valor de la suma es %dn", r);

    getch();

    return 0;

    }

    int sumav(int v[], int n)

    {

    int r;

    if(n==0)

    r=v[0];

    else

    r=v[n]+sumav(v, n-1);

    return r;

    }

    Ejemplo 8. 9:

    #include <stdio.h>

    #include <conio.h>

    /*programa que lee e imprime un arreglo de enteros

    y despues hace una busqueda lineal recursiva de ciertos

    valores digitados por el usuario */

    int busquedalineal(int *V, int n, int b);

    void main()

    {

    int arreglo[12];

    int pos, i, num, bus, buscar=1;

    pos=0;

    printf("Digite 12 valores para guardarlos en el arreglo:n");

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

    {

    printf("Digite el elemento de la posici�n %d del vector:n",
    i+1);

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

    }

    printf("Los elementos del vector son:n");

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

    {

    printf("%d", arreglo[i]);

    }

    printf("n");

    while(buscar)

    {

    printf("Digite un n�mero a buscar:");

    scanf("%d", &num);

    pos=busquedalineal(arreglo, 11, num);

    if(pos)

    printf("El numero %d se encuentra en el arreglon", num);

    else

    printf("El numero %d NO se encuentra en el arreglon",
    num);

    printf("�Desea Buscar otro numero? (S/N)n");

    bus=getch();

    if(bus=='s' || bus=='S')

    buscar=1;

    else

    buscar=0;

    }//fin del while

    getch();

    }//fin del main

    /*Funci�n REcursiva de Busqueda Lineal */

    int busquedalineal(int *V, int n, int b)

    {

    if(n==0)

    return (V[0]==b);

    else

    if(V[n]==b)

    return 1;

    else

    return busquedalineal (V, n-1, b);

    }

    Ejemplo 8.10:

    /* Pograma que dado un vector de enteros

    calcule:

    1. el elemento maximo del arreglo

    2. el elemento minimo del arreglo

    3. la suma de los elementos del arreglo

    4. el producto de los elementos del arreglo

    5. el promedio de los elementos del arreglo */

    #include <stdio.h>

    #include <conio.h>

    #define N 10

    int max (int a[], int n);

    int min (int a[], int n);

    int sum (int a[], int n);

    int multi (int a[], int n);

    int prom (int a[], int n);

    main()

    {

    int a[N], i=0, r, op, n=10, ban=1;

    clrscr();

    printf("ttBIENVENIDO (A)nn");

    printf("Ingrese los valores del vector:n");

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

    {

    printf("Ingrese el elemento %d del arreglo:n", i);

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

    }

    clrscr();

    printf("Los valores del arreglo son:n");

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

    printf("** %d **", a[i]);

    getch();

    while(ban==1)

    {

    clrscr();

    printf("*****************************************n");

    printf("** �Que desea hacer? **n");

    printf("** 1. El maximo elemento **n");

    printf("** 2. El minimo elemento **n");

    printf("** 3. La suma de sus elementos **n");

    printf("** 4. Su producto **n");

    printf("** 5. Su promedio **n");

    printf("** 6. Sair **n");

    printf("*****************************************n");

    scanf("%d", &op);

    switch(op)

    {

    case 1: clrscr();

    r= max(a, n);

    printf("el maximo elemto del vector es %dn", r);

    break;

    case 2: clrscr();

    r=min(a, n);

    printf("El elemnto minimo es %dn", r);

    break;

    case 3: clrscr();

    r= sum(a, n);

    printf("La suma de los elementos del vector es: %d n",
    r);

    break;

    case 4: clrscr();

    r=multi (a, n);

    printf("Al multiplicar todos los elementos del vector
    resulta %d n", r);

    break;

    case 5: clrscr();

    r=prom(a, n);

    printf("El promedio de los valores son: %d n", r);

    break;

    case 6: return 0;

    default:

    printf("ERROR, comando no valido!!n");

    }

    printf("�Desea Seguir? (1/2)n");

    scanf("%d", &ban);

    }

    getch();

    return 0;

    }

    int max (int a[], int n)

    {

    int r, aux;

    if(n==0)

    r=a[0];

    else

    {

    aux=max(a, n-1);

    if(a[n]>aux)

    r=a[n];

    else

    r=aux;

    }

    return r;

    }

    int min (int a[], int n)

    {

    int r, aux;

    if(n==0)

    r=a[0];

    else

    {

    aux=min(a, n-1);

    if(a[n]<aux)

    r=a[n];

    else

    r=aux;

    }

    return r;

    }

    int sum (int a[], int n)

    {

    int r;

    if(n==0)

    r=0;

    else

    r=a[n-1]+sum(a, n-1);

    return r;

    }

    int multi (int a[], int n)

    {

    int r;

    if(n==0)

    r=1;

    else

    r=a[n-1] * multi(a, n-1);

    return r;

    }

    int prom (int a[], int n)

    {

    int r;

    r=sum(a, n)/N;

    return r;

    }

    Hasta el momento, hemos visto algunos ejemplo del uso de
    la recursi�n, pero hay que tener en cuenta, algunos aspectos importantes,
    para decidir entre recursi�n o iteraci�n:

    1. la relaci�n, tiempo-espacio de la memoria, para una llamada recursiva
      es mayor que para una iterativa, por eso, se debe hacer uso de la recursi�n
      s�lo cuando, una soluci�n iterativa no sea posible.
    2. si son posibles las dos soluciones (iterativa y recursiva), entonces es
      mejor hacer uso de la soluci�n iterativa, puesto que una llamada
      recursiva consume mayor tiempo y espacio en memoria.
    3. hay por el contrario, muchos problemas que se resuelven exclusivamente
      con recursi�n, ya que son demasiado extensos y complejos, por tanto
      una soluci�n recursiva, presentar� una imagen m�s fiable,
      comprensible y elegante.

    Recursi�n Infinita

    Cuando habl�bamos de los ciclos (bucles), dec�amos
    que, dentro del ciclo debe existir algo que modifique la condici�n,
    para que, en un momento dado, se pueda salir del ciclo. Lo mismo pasa con
    la iteraci�n.

    Una Recursi�n Infita, implica que cada llamada
    recursiva produce otra, y �sta a su vez produce otra llamada, y �ta
    tambi�n produce otra llamada, y as� sucesivamente para SIEMPRE,
    o al menos hasta que se termine la memoria de la computadora, para evitar
    esto, hay que tener en cuenta, y muy bien definidos, los casos baes y los
    casos generales del problema.

    Algoritmos: Div�delos y Vencer�s

    Una e las t�cnicas de programaci�n m�s
    importante, es la denominada "Divide y vencer�s", que, como
    ya hemos explicado en cap�tulos anteriores, consiste en subdividir
    un programa grande y complejo, en peque�os programas m�s simples
    y sencillos.

    En recursi�n, normalmente este proceso da lugar a
    casos base, es decir, problemas cuya soluci�n es inmediata, sin recursi�n.

    Un algoritmo divide y vencer�s, puede ser llamado
    recursivamente, a partir de un subconjunto (m�s peque�o) de
    datos. La condici�n que deja de hacer las llamadas, es lo que hemos
    denominado como caso base.

    Torres de Hanoi

    Quiz� el siguiente ejemplo, sea uno de los m�s
    complejos de la recursi�n, por que consite en tres varillas, torres
    o postes, paralelos; del cual el primero, posee tres donas, discos… en orden
    de la m�s grande a la m�s peque�a, y se desean mover
    de la varilla 1 a la varilla 3, pero bajo ciertas condiciones:

    1. los movimientos deben ser de uno en uno (es decir, no se pueden mover
      dos o tres donas al mismo tiempo)
    2. en una varilla, no puede quedar una dona peque�a, bajo una grande.
    3. La siguiente imagen, representa, la forma m�s adecuada,
      para realizar los movimientos:

      Parece bastante complejo verdad?, en lo personal, me tom�
      un poco de tiempo, entender y buscar la forma de mover las donas (debo confesar
      que no soy muy bueno para ese tipo de jueguitos).

      El ejemplo anterior constaba, unicamente de tres discos
      (donas), pero puede generalizarse para n discos y tres varilas.

      El algoritmo ser�a el siguiente:

      If(n==1)

      -Mover e disco 1 de la varilla inicial(1) a la varilla
      final(3)

      Else

      -Mover n-1 discos desde varilla inicial(1) hasta varilla
      la varilla temporal(2), utilizando la varilla 3, como auxiliar.

      -mover el disco n desde varilla inicial a varilla final

      -mover n-1 discos desde la varilla auxiliar central a varilla
      final (3) utilizando como auxiliar a la varilla n�mero uno.

      Ejemplo 8.11:

      #include <stdio.h>

      #include <conio.h>

      void hanoi (int n, int inic, int temp, int fin);

      main()

      {

      int n; /*numero de discos a mover*/

      clrscr();

      printf("Numero de discos:n");

      scanf("%d", &n);

      /*mover n discos desde 1 a 3, usando a 2 como auxiliar*/

      hanoi(n, 1, 2, 3);

      getch();

      return 0;

      }

      void hanoi (int n, int inic, int temp, int final)

      {

      if(n>0)

      {

      /*mover n-1 discos de inic a temp*/

      hanoi(n-1, inic, final, temp);

      /*mover el que quede en inic a final*/

      printf("Del poste %d al %dn", inic, final);

      /*mover n-1 discos de temp a final*/

      /*el temporal es inic*/

      hanoi(n-1, temp, inic, final);

      }

      }

      Cuestionario

      1. �Qu� es recursi�n?:________________________________________________________________________________________________________________________________________

    4. �Qu� aspectos, son los que debo tomar en cuenta, cuando tengo que
      decidir entre iteraci�n o recursi�n?_________________________________________________________________________________________________________________________________________________________________________________________________________________
    5. �Cu�ndo se produce una recursi�n infinita?_______________________________________________________________________________________________________________________________
    6. �Para que sirven los casos base?�y los casos generales?______________________________________________________________________________________________________________________________________________________________________________________________
    7. �En que consiste la t�cnica "divide y vencer�s"?______________________________________________________________________________________________________________________________________________________________________________________________

    Descubre el error:

    El siguiente c�digo, presenta algunos errores de l�gica,
    de sintaxis y de ejecuci�n, �Puedes descubrirlos y corregirlos?

    /* Programa que calcula la suma de dos vectores */

    #include <stdio.h>

    int suma (int a[], int b[], int n);

    void main()

    {

    int a[5]={1,2,3,4,5};

    int b[5]={1,2,3,4,5};

    int n=5, r;

    clrscr();

    printf("el valor de la suma es:n");

    r=suma(a,b, n);

    printf("%d", r);

    getch();

    }

    int suma (int a[], int b[], int n)

    {

    if(n!=0)

    r=0;

    else

    {

    r=a[n-1]+b[n-1]+suma(a, b, n-1);

    }

    return r;

    }

    /*Funci�n que suma a+b, usando una suceci�n*/

    #include <stdio.h>

    #include <conio.h>

    int suma (int x, int b);

    main()

    {

    int a,b,x=0, sum;

    clrscr();

    printf("PROGRAMA QUE USA LA FUNCION SUCC PARA SUMAR A+Bn");

    printf("Ingrese el valor de a:");

    scanf("%d", &a);

    printf("b=");

    scanf("%d", b);

    sum=a+suma(x,b);

    printf("%d + %d = %dnn", a,b,sum);

    getch();

    return 0;

    }

    int suma (int a, int b)

    {

    int r;

    if(x==b)

    r=x;

    else

    {

    x++;

    r=suma(a,b);

    }

    }

    Ejercicios:

    1. Dise�e un programa que sume los primeros n m�ltiplos de
      tres, en forma recursiva
    2. Dise�e un funci�n (o programa completo) que, dado un vector,
      determine el producto de todos sus elementos en forma recursiva.
    3. el valor de e (una expresi�n matem�tica, puede representarse
      de la siguiente manera: e=1/1!+1/2!+…+1/n!. Dise�e una funci�n
      (o programa) que muestre el resultado recursivo de �sta sucesi�n.
    4. Dado un vector, escriba un programa que busque un elemento ingresado por
      el usuario, en el vector y con un mensaje en pantalla, indique si ese valor
      se encuentra o no.
    5. Escribir un programa, que comntenga una funci�n recursiva, para
      calcular la funci�n de Ackermann, definida de la siguiente forma:
    6. ->A(m,n)=n+1, si m=0

      ->A(m,n)=A(m-1, 1) si n=0

      ->A(m,n)=A(m-1, A(m, n-1)) si m>0 y n>0

    7. El combinatorio de dos n�meros, est� definido, por la expresi�n
      siguiente: C(m, n)=m!/(n!x(m-n)!), escribir un programa en C, que calcule
      el combinatorio, donde n! Es el factorial de n.
    8. Dados dos vectores de enteros e igual tama�o, calcular la suma
      de los productos de sus elementos: C=S (AiXBi).
    9. Escriba un programa que transforme cualquier n�emro base 10, a
      otra base b, que puede ser de 8 a 16, utilizar para ello recursividad.
    10. Dise�e un programa que muetre cual es el valor mayor contenido
      en un vector unidimensional.
    11. Se tiene un conjunto de pesos p1, p2, p3…pn. y se desea estudiar, como
      objetivo si existe una selecci�n de dichos objetos que totalicen
      exactamente un peso v, dado. Por ejemplo, si el objetivo es V=12y los pesos
      son: 4, 3, 6, 2, 1; se pueden elegir el primero, el tercero y el cuarto,
      ya que: 4+6+2=12. El algotimo para solucionar este problema tiene como tarea
      b�sica a�adir un nuevo peso , probar si con ese peso se logra
      el objetivo o se avanza en el sentido de alcanzar la soluci�n.

    Cap�tulo IX: Estructuras
    y Uniones

    En este cap�tulo, vamos a aprender a usar una de las
    caracter�sticas m�s singulares, peculiares y sobre todo, portentes
    de C, como lo es, el uso de estructuras, uniones y TIPOS DE DATOS creados
    por el programador, lo cual nos facilita muchas cosas ya que, no nos restringimos
    a los tipos de datos que nos ofrece el lenguaje C.

    Estructuras

    Los arrays, son un ejemplo de estructuras (de tipo homog�neo),
    sin embargo, �ste tipo de estructuras posee una gran limitante,
    puesto que, s�lo admite datos del mismo tipo (entero, flotante, car�cter);
    las estructuras que vamos a estudiar, estan compuestas por un grupo de variables,
    no necesariamente del mismo tipo, en las cuales, podemos almacenar diferente
    informaci�n (en cuanto a tipo), pero referente a un mismo t�pico.

    Por ejemplo, en nuestro carn�t de identidad, del colegio,
    de la universidad, aparecen muchos datops acerca de nosotros.

    Nombres, apellidos, edad, direcci�n, fecha de nacimiento,
    grado, secci�n, ciclo…

    Estos datos, son de diferente tipo, pero, en C, podemos almacenarlos
    utilizando un tipo de dato registro al que llamamos Estructura.

    Por tanto, una estructura es una calecci�n de una
    o m�s tipos de elementos denominados miembros, cada uno de los
    cuales puede ser de un tipo de dato diferente.

    La figura anterior, muestra, los datos (y el tipo) para cierto
    registro, pero supongamos que dichos datos, son para alumnos de alguna universidad,
    la cual cuenta con 500 alumnos… la cantidad de variables, ser�a impresionante,
    por ejemplo tendr�amos que declarar 500 variables para los nombres,
    500 para los apellidos, 500 para las edades, y as� sucesivamente.

    Es ello que radica la importncia de las estructuras, por
    que nos ahora tiempo adem�s que las estructuras son una herramienta
    importante para la creaci�n de programas portentes y bases de datos.

    Declaraci�n de una Estructura

    Como toda variable, en C, debemos declarar una estructura
    para poder hacer uso de ella, y la forma de hacerlo es la siguiente:

    strcuct <nombre de la estructura>

    {

    <tipo de dato del miembro1> <nombre del miembro
    1>;

    <tipo de dato del miembro 2> <nombre de miembro
    2>:

    <tipo de dato del miembro n> <nombre del miembro
    n>;

    }

    Por ejemplo, para los datos anteriores, la forma de declararla
    ser�a la siguiente:

    struct datos

    {

    char nombre[30];

    char apellido[20];

    int edad;

    char direcci�n[100];

    char fecha_nac[8];

    };

    Definici�n de variables del tipo estructura

    Al igual que las funciones, las estructuras son declaradas
    y definidas; en la declaraci�n es que, le estamos indicando al compilador
    que las variables de tipo datos estar�n compuestas por los elemetos,
    tales como nombre, apellido etc; pero adem�s, debemos defininir variables
    que, ser�n de ese tipo. As� como en alguna parte de C, est�n
    declarados los tipos de datos char, int, float; as� tambi�n
    nosotros debemos definir las estructuras. Y cuando en el main, definimos las
    variables que ser�n del tipo int, del tipo float o del tipo char, de
    igual manera, debemos definir que variables ser�n del tipo de la estructura
    que hemos creado. Para ello existen dos procedimientos:

    1. listar las variables inmediantamente despu�s de cerrar la llave
      de la estructura
    2. Listar las variables que serp�n del tipo estructura creadas, inmeditamente
      despu�s del identificador de la estructura; en la zona de declaraciones
      del programa.

    Ejemplo:

    1. struct datos

    {

    char nombre[30];

    char apellido[20];

    int edad;

    char direcci�n[100];

    char fecha_nac[8];

    } alumno1, alumno2, alumno3;

    2. struct datos alumno1, alumno2, alumno3;

    Si por alg�n caso, los datos de las tres variables,
    fuesen los mismos, podemos asignar los valores de �sta forma:

    Alumno1=alumno2;

    Alumno3=alumno2;

    O tambi�n:

    Alumno1=alumno3=alumno2;

    Ya que, al contener los mismos miembros, es como si se tratacen
    de datos tipo int, float o char, por consiguiente podemos hacer las asignaciones
    anteriores.

    Una esructuram la podemos inicializar as�:

    struct datos

    {

    char nombre[30];

    char apellido[20];

    int edad;

    char direcci�n[100];

    char fecha_nac[8];

    }alumno1 = {"Manuel",

    "Ortez",

    20,

    "San Salvador, El Salvador",

    "27/04/86",

    };

    o tambi�n as�:

    struct datos alumno2={"Carolina",

    "Pelayo",

    20,

    "San Salvador, El Salvador",

    "14/05/86",

    };

    El tama�o de una estructura es determinado de forma
    muy simple, consiste en sumar, el tama�o de todos los miembros, para
    nuestro caso particular, el tama�o (en bytes) de la estructura datos
    ser�a:

    Ciertamente que, este proceso, lo podemos simplificar utilizando
    la sentencia:

    Sizeof(datos);

    Cuyo resultado ser�: 160.

    Acceso a una estructura.

    Para acceder a una estructura, o bi�n a la informaci�n
    guardada en ella, podemos hacer uso de dos nuevos amigos:

    1. El operador punto (.)
    2. El operador puntero �flecha- (->)

    Por ejemplo:

    Alumno1.nombre="Manuel";

    Strcpy(alumno1.apellido, "Ortez");

    Para utilizar el operador flecha, debemos hacer uso de punteros
    (y cre�ste que ya nos hab�amos olvidado de los punteros verdad?).

    Por ejemplo, si tenemos un puntero a una estructura:

    .struct datos *ptr;

    ptr=&alumno1;

    ptr->edad=20;

    Ejemplo 9.1

    Dise�e un programa que guarde los datos de dos cd.

    #include <stdio.h>

    #include <conio.h>

    /*declracion de la estructura*/

    struct datos_cd

    {

    char titulo[20];

    float precio;

    char fecha[8];

    };

    main()

    {

    /*definicion de las variables estructuras*/

    struct datos_cd cd1, cd2;

    struct datos_cd *ptr;

    int tam;

    ptr=&cd2; /*asignacion de la direccion de cd2 al puntero*/

    clrscr();

    /*leemos los datos, usando el operador punto*/

    printf("Introduzca el t�tulo del primer cd:n");

    scanf("%s", &cd1.titulo);

    printf("Intriduzca el precio del cd1:n");

    scanf("%f", &cd1.precio);

    printf("Ahora, la fecha de edicion (dd/mm/aa/):n");

    scanf("%s", &cd1.fecha);

    printf("Introduzca el t�tulo del segundo cd:n");

    scanf("%s", &cd2.titulo);

    printf("Intriduzca el precio del cd2:n");

    scanf("%f", &cd2.precio);

    printf("Ahora, la fecha de edicion (dd/mm/aa/):n");

    scanf("%s", &cd2.fecha);

    clrscr();

    printf("tttAhora vamos a imprimir los valores guardados:nn");

    printf("********************Datos del CD1*************************n");

    printf("Titulo %s n", cd1.titulo);

    printf("Precio %.2fn", cd1.precio);

    printf("Fecha %sn", cd1.fecha);

    printf("**********************************************************nn");

    printf("********************Datos del CD2*************************n");

    printf("Titulo %sn", ptr->titulo);

    printf("Precio %.2fn", ptr->precio);

    printf("Fecha %sn", ptr->fecha);

    printf("**********************************************************nn");

    printf("El tama�o de la estructura es %d bytesnn", sizeof(datos_cd));

    getch();

    return 0;

    }

    Estructuras Anidadas

    Al igual que los ciclos, las decisiones, las expreciones,
    etc, las estructuras tambi�n pueden estar dentro de otras, a esto es
    que se le llama estructuras anidadas.

    Supongamos que tenemos dos estructuras siguientes:

    stuct empleado

    {

    char nom[30];

    char puesto[10];

    int edad;

    float sueldo;

    char municipio[20];

    char ciudad[10];

    char direcci�n[50];

    };

    struct cliente

    {

    char nom[30];

    char fecha_deuda[8];

    float saldo;

    char municipio[20];

    char ciudad[10];

    char direcci�n[50];

    };

    observamos que, en ambas estructuras, hay fatos que se repiten,
    los cuales los podr�amos ubicar en otra structura, as�:

    struct direc

    {

    char municipio[20];

    char ciudad[10];

    char direcci�n[50];

    };

    por tanto, las estructuras de empleado y cliente, ser�a
    de la siguiente forma:

    stuct empleado

    {

    char nom[30];

    char puesto[10];

    int edad;

    float sueldo;

    struct direc direc_empleado;

    };

    struct cliente

    {

    char nom[30];

    char fecha_deuda[8];

    float saldo;

    struct direc direc_cliente;

    };

    en C, podemos definir una estructura dentro de otra estructura,
    claro siempre y cuando la declaraci�n de �sta, haya sido previo.

     

 P�gina anterior Volver al principio del trabajoP�gina siguiente 

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