Módulo 5 - Fundamentos de Programación en C, C++.pdf

39
MP 11 Fundamentos Programación UF 02 Diseño Modular MP 11 UF 02 Módulo 5 Fundamentos Programación. Página 1 MÓDULO 5 FUNDAMENTOS PROGRAMACIÓN EN C, C++. OBJETIVOS. En este módulo comenzaremos a ver uno de los aspectos más característicos de los lenguajes C/C++: los punteros. Como que los punteros y los vectores o variables indexadas, están muy relacionadas, veremos también con más profundidad estos últimos y muchos aspectos relacionados con ellos. Concretamente, los aspectos que tratará este módulo son: Punteros: ¿qué son?; Declaración de un puntero; Los operadores & y *; Asignaciones de punteros; Aritmética de punteros; Inicialización de punteros; Paso de argumentos por valor y por referencia; Punteros del tipo void*; Vectores o variables indexadas (unidimensionales y multidimensionales); Inicialización de vectores; Relación entre vectores y punteros; Paso de vectores como argumentos de una función.

Transcript of Módulo 5 - Fundamentos de Programación en C, C++.pdf

  • MP 11 Fundamentos Programacin UF 02 Diseo Modular

    MP 11 UF 02 Mdulo 5 Fundamentos Programacin. Pgina 1

    MDULO 5 FUNDAMENTOS PROGRAMACIN EN C, C++.

    OBJETIVOS.

    En este mdulo comenzaremos a ver uno de los aspectos ms caractersticos de los lenguajes C/C++: los punteros.

    Como que los punteros y los vectores o variables indexadas, estn muy relacionadas, veremos tambin con ms profundidad estos ltimos y muchos aspectos relacionados con ellos.

    Concretamente, los aspectos que tratar este mdulo son:

    Punteros: qu son?;

    Declaracin de un puntero;

    Los operadores & y *;

    Asignaciones de punteros;

    Aritmtica de punteros;

    Inicializacin de punteros;

    Paso de argumentos por valor y por referencia;

    Punteros del tipo void*;

    Vectores o variables indexadas (unidimensionales y multidimensionales);

    Inicializacin de vectores;

    Relacin entre vectores y punteros;

    Paso de vectores como argumentos de una funcin.

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 2

    1. RESUMEN TERICO.

    1.1. INTRODUCCIN A LOS PUNTEROS.

    Cuando se declara una variable, se reserva espacio en la memoria para contener el valor de esta variable. El nombre de la variable queda asociado a la direccin de memoria donde comienza este espacio reservado. La cantidad de espacio reservado depende del tipo de variable; por ejemplo, en la siguiente declaracin: char carac, carac2;

    int contador;

    float x;

    int i:

    Entonces se obtendr el siguiente esquema en la memoria del ordenador (las posiciones concretas de memoria son orientativas):

    Un puntero es una variable que contiene la direccin de otra variable. Se dice que la variable puntero o el puntero apunta a esta segunda variable; es decir, en realidad nos indica o apunta una posicin o direccin de memoria.

    Los punteros proporcionan una gran potencia a los lenguajes C y C++ y marcan la diferencia entre estos y otros lenguajes de programacin. Los punteros nos permiten aproximarnos al tipo de trabajo que hace el ordenador. Los programas que utilizan punteros son normalmente ms eficientes, aunque los punteros son un elemento peligroso en el sentido que un puntero sin valor inicial o incontrolado puede provocar un mal funcionamiento del sistema y provocar errores de difcil localizacin.

    La importancia de los punteros est principalmente es estos tres puntos:

    1 - Proporcionan los medios por los cuales las funciones pueden modificar sus argumentos de llamada.

    2 - Permiten la asignacin dinmica de memoria. Esto quiere decir que con la ayuda de los punteros se puede reservar la memoria en tiempo de ejecucin en lugar de en tiempo de compilacin, lo que significa que el espacio reservado por los datos puede ser determinado por el usuario en lugar de por el programador.

    3 - Pueden sustituir a los vectores o variables indexadas para incrementar la eficacia del programa.

    El hecho de trabajar en sistemas de 32bits hace que los punteros puedan directamente apuntar a cualquier lugar de la memoria. No es necesario el uso de los segmentos y desplazamientos como necesitaban los sistemas de 16bits, no obstante esto, los sistemas operativos Windows (NT, 95, 98 y 2000) no permiten que los punteros apunten fuera de la memoria reservada para la ejecucin del programa.

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 3

    1.1.1. DECLARACIN DE UN PUNTERO.

    Las variables puntero se deben declarar como cualquier otra variable en C/C++. El formato general de la declaracin de un puntero es:

    tipo_bsico *nombre_de_la_variable

    donde tipo_bsico es cualquiera de los tipos bsicos de datos y define el tipo de datos que encontraremos en el lugar donde apunta el puntero. El asterisco se puede leer de momento como "puntero a tipo_bsico".

    El nombre de la variable puntero es un identificador de variable normal y, como tal, es correcto cualquier identificador.

    Por ejemplo: char carac, *ptrcarac;

    Esta sentencia declara dos variables, una variable tipo char denominada carac, y otra de tipo char* (puntero a char) denominada ptrcarac.

    Si tenemos las siguientes asignaciones: carac = 'A' ptrcarac = &carac;

    tendremos el siguiente esquema en la memoria:

    Los nmeros de la columna de la izquierda representan, en formato hexadecimal, la direccin de cada posicin de memoria (estas direcciones son orientativas). Dentro de los cuadros se representa el contenido de la memoria.

    La variable carac est asignada a la posicin 006515A1 y su contenido es 'A', o bien el nmero 65. Esta variable ocupa un nico octeto.

    La variable ptrcarac est asignada a la posicin 006515A2 y su contenido es la posicin de la variable carac; es decir, la posicin 006515A1. En Visual C, las variables punteros ocupan 4 octetos, independientemente del tipo de variable a la cual apuntan.

    El almacenado de la variable ptrcarac que va desde la posicin 006515A2 a la 006515A5, se hara de forma que su contenido (006515A1) quedara de la siguiente forma: en la posicin 006515A2 00

    006515A3 65 006515A4 15 006515A5 A1

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 4

    1.1.2. LOS OPERADORES DE MANIPULACIN DE PUNTEROS: & Y *.

    El operador & (operador direccin): es un operador unario que retorna la direccin de memoria de su operando, el cual puede ser cualquier tipo de variable, incluyendo las variables punteros.

    En el ejemplo anterior, la asignacin: ptrcarac = &carac; hace que en la variable ptrcarac se almacene la direccin de la variable carac. En este momento, la variable ptrcarac apuntar a la variable carac.

    El operador * (operador de indireccin) es otro operador unario que retorna el valor de la variable donde se est apuntando el operando (que ser un puntero). Por ejemplo, la sentencia: val = *ptrcarac; asignar a la variable val (declarada previamente como char) el valor 65.

    El operador & acta sobre cualquier variable. El operador * acta sobre variables punteros.

    No se debe confundir el operario unario * con el operador binario * que representa el producto de dos nmeros. En expresiones complicadas en las cuales pueda haber confusiones, se puede poner parntesis para evitarlas.

    1.1.3. ASIGNACIN A PUNTEROS.

    Como cualquier variable, se puede utilizar un puntero en la parte derecha de una sentencia para asignar el valor del puntero a otro puntero. Por ejemplo:

    int a, *px, *py; a=100;

    px=&a;

    py=px;

    printf("direccin de py: %p\n apunta al valor: %d", py, *py);

    El puntero py apuntar a la variable a, por tanto, *py ser igual a 100. El cdigo de formato para mostrar direcciones de memoria en hexagesimal con la funcin printf() es %p.

    1.1.4. ARITMTICA DE PUNTEROS.

    En C se pueden utilizar los operadores ++, --, + y - sobre punteros. Una expresin como: p++; sobre un puntero p hace que apunte a la siguiente posicin de memoria, entendiendo como siguiente posicin la que se obtiene de sumar el nmero de octetos que ocupa el tipo base del puntero.

    Por ejemplo, si la variable puntero p, declarada como un puntero entero (int *p), contiene la direccin 0065A510, la sentencia p++ hace que este puntero contenga ahora la direccin 0065A514, ya que, una variable entera ocupa 4 octetos.

    Los lenguajes C/C++ no se limitan slo a los incrementos y decrementos, tambin se puede sumar y restar a los punteros. Por ejemplo, si a la variable p definida en el prrafo anterior, sumamos 5 con la sentencia: p=p+5; el valor actual ser 0065A514+5*(medida de un entero)= 0065A528 (Si no se ha entendido esta suma, hay que recordar que las direcciones se expresan normalmente en hexagesimales, de hecho, se han sumado 20 posiciones de memoria).

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 5

    1.1.5. INICIALIZACIN DE PUNTEROS.

    Si una variable local no se inicializa, su valor es indeterminado. Si este hecho puede ser peligroso en el caso de una variable normal, es especialmente peligroso en el caso de los punteros. Siempre es necesario inicializar los punteros antes de utilizarlos.

    Para trabajar con punteros vacios (que temporalmente no apuntan a ningn lugar), se pueden inicializar a un valor especial denominado NULL (puntero nulo). NULL es una constante simblica que est definida en algunos archivos de cabecera estndar como stdio.h y ioscrean.h y de hecho es un valor 0, el valor falso en las condiciones.

    Si un puntero siempre apunta a una misma variable es una buena prctica inicializarla en la declaracin, por ejemplo: int main(){

    int a=6;

    int *pa=&a;

    1.1.6. PASO DE ARGUMENTOS POR VALOR Y POR REFERENCIA.

    En C/C++, cuando llamamos a una funcin con un argumento (una variable), se pasa una copia del contenido de esta variable. Se dice que el argumento se ha pasado por valor. La funcin no puede modificar el contenido de la variable original. La principal restriccin del mtodo de llamada por valor es que la funcin slo puede retornar un nico valor.

    Otra posibilidad es pasar argumentos por referencia; es decir, pasar la direccin de la variable en lugar de su valor. Esto hace que la funcin no tiene la necesidad de crear una copia de esta variable y, adems, las modificaciones que realice la funcin afectarn al valor de la variable una vez acabada la funcin. De esta forma una funcin puede modificar ms de un valor.

    En C/C++ se puede crear una llamada por referencia utilizando un puntero como argumento. En la primera prctica se podr entender la diferencia este estos dos tipos de paso de argumentos.

    1.1.7. PUNTEROS DEL TIPO VOID*.

    En C/C++, se incorpora la posibilidad de declarar un puntero como void*, esto permite que el puntero apunte a cualquier tipo de datos. Esto puede ser til en muchos casos. Podemos pensar, por ejemplo, en la funcin estndar de entrada C: scanf(), que admite como argumentos punteros a cualquier tipo de datos.

    Cuando se quiere manipular una variable puntero void*, primero se debe hacer una conversin explcita a cualquier tipo de dato vlido C/C++. En la prctica 3 se trata un ejemplo de esta caracterstica.

    1.2. VECTORES O VARIABLES INDEXADAS.

    Los vectores (tambin conocidos como variables indexadas, array, arreglos, formaciones, matrices, etc.), son un conjunto de variables del mismo tipo y con el mismo nombre. Para referirnos a un elemento concreto de un vector se utiliza uno o ms ndices cerrados entre corchetes, el nmero de los cuales representar la dimensin del vector. En el caso que la dimensin sea superior a 1 se suele denominar matriz.

    Para declarar un vector o matriz de una o diversas dimensiones, se debe escribir el tipo y el nombre seguido de unos corchetes con un nmero de elementos para cada dimensin.

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 6

    Por ejemplo: int x(10); //Define un vector de 10 variables int. float a [2][3] //Define una matriz de 6 variables float.

    Para referirnos a una de las 10 variables int del vector x se utiliza un ndice que puede ser cualquier expresin que retorne un entero 0 y n-1, siendo n el nmero que se ha utilizado en la definicin.

    A las matrices de dos dimensiones, los elementos se van almacenando por variacin de los ndices de ms a la derecha hacia los ndices de ms a la izquierda, por ejemplo: int m [3][4]; se almacenar en la memoria en el siguiente orden: m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3].

    Una cosa muy importante a tener en cuenta es que C/C++ no utiliza comprobacin de lmites, esto quiere decir que si se declara un vector de dimensin n, puede pasar que se utilice un ndice con un valor ms grande que n. Esta circunstancia no es controlada por el compilador y puede provocar la cada del sistema.

    1.2.1. INICIALIZACIN DE VECTORES.

    Como toda variable, un vector puede tomar valores iniciales despus de su declaracin. El formato general es:

    tipo identificador_variable [tamao] = {lista_de_valores}

    La lista de valores es una lista separada por comas " , ", de constantes que son del mismo tipo que el de la base del vector.

    Ejemplo: int num [5] = {0, 1, 2, 3, 4};

    Donde la primera constante de valor 0 almacenar en la primera posicin del vector, la segunda constante de valor 1 en la segunda posicin del vector, y as sucesivamente hasta completar las cinco constantes. El compilador las situar en posiciones contiguas de memoria.

    No es necesario poner valor inicial a todo el vector, en este caso el compilador pondr ceros a todos aquellos elementos a los que no le hayamos asignado ningn valor. Por ejemplo: int num [5] = {0, 1, 2}; . Aqu el compilador asignar ceros a los dos ltimos elementos del vector.

    Tambin es posible al poner los valores iniciales al vector, no declarar su tamao. El compilador la determinar calculando el nmero de valores numerados. As, la asignacin: int num [] = {0, 1, 2, 3, 4}; , hace que la dimensin de la variable num sea 5.

    Para poner valores iniciales a los vectores multidimensionales lo haremos de una forma parecida a la hecha por los vectores unidimensionales.

    Por ejemplo, para una matriz de enteros de dos filas por cinco columnas poniendo valores iniciales las siguientes declaraciones de asignacin:

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

    equivalente a: int tab [2] [5] = {0, 1, 2, 3, 4,5, 6, 7, 8, 9};

    y tambin equivalente a: int tab [2] [5] = { {0, 1, 2, 3, 4},

    {5, 6, 7, 8, 9}

    };

    As, como en los vectores unidimensionales, el poner valor inicial lo podamos hacer en forma parcial, ahora tambin es posible, a condicin de comenzar por el principio de cada ndice del vector.

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 7

    No obstante es necesario ir con cuidado porque en las declaraciones incompletas las confusiones son fciles como muestra el siguiente ejemplo:

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

    /* Valores iniciales completos, corresponde a:

    1 2 3 4

    5 6 7 8

    */

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

    /* Valores iniciales incompletos, corresponde a:

    1 2 3 0

    0 0 0 0

    */

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

    /* Valores iniciales incompletos, corresponde a:

    1 0 0 0

    2 3 0 0

    */

    /* Valores iniciales a un vector sin dimensiones. La dimensin

    indeterminada ser siempre la primera */

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

    /* Valores iniciales que corresponde a:

    1 2

    3 4

    5 6

    */

    1.2.2. RELACIN ENTRE VECTORES Y PUNTEROS.

    Existe una estrecha relacin entre vectores y punteros. De hecho, el nombre de un vector es un puntero a la direccin de memoria que contiene el primer elemento del vector; es decir, si definimos el vector: int vec[5]el identificador vect es equivalente a &vect[0].

    En general, vect+i ser un puntero que apuntar a vect[i].

    De hecho, a los punteros se les pueden poner ndices y, si se ha definido un puntero como: int *p; es equivalente p+i que p[i].

    En el caso de los vectores multidimensionales o matrices, la relacin entre estos y los punteros es algo ms complicado. En el caso de una matriz bidimensional, el nombre de la matriz es un puntero al primer elemento de un vector de punteros; por ejemplo, si definimos: int tab[2][3]; donde mat es un puntero al primer elemento del vector de punteros mat[].

    Por tanto, mat es equivalente a &mat[0] i mat[0] es equivalente a &mat[0][0], de la misma manera que mat[1] es equivalente a &mat[1][0].

  • MP 11 UF 01 Mdulo 5 Fundamentos Programacin. Pgina 8

    1.2.3. PASO DE VECTORES COMO ARGUMENTOS DE UNA FUNCIN.

    Para considerar el paso de vectores como argumentos de una funcin, es necesario entender la relacin entre estas y los punteros.

    Si pasamos a una funcin un elemento de un vector, estamos pasando el valor de este elemento. En este caso, el argumento de la funcin se ha de declarar del tipo de dato que se pasa. Por ejemplo: int funcion(int);

    int main(){

    int vect[10] , a;

    ......

    a = funcion(vect[1]);

    ......

    }

    int funcion(int a){

    .......

    Podemos pasar directamente todo el vector. En este caso la llamada se har con el nombre del vector que, como ya se sabe, es un puntero. Se puede hacer de dos formas:

    void funcion(int v[]);

    int main(){

    int vect[10];

    ......

    funcion(vect);

    ......

    }

    int funcion(int v[]){

    .......

    void funcion(int*);

    int main(){

    int vect[10];

    ......

    funcion(vect);

    ......

    }

    int funcion(int *v){

    .......

    En el caso de matrices multidimensionales, es necesario dar las dimensiones de la matriz que se pasa como argumento excepto la primera. Por ejemplo:

    int funcin(int v[][10]);

    void main(){

    int vect[10][10];

    ......

    funcion(vect);

    ......

    }

    int funcion(int v[][10]){

    .......

    int funcin(int (*v)[][10];

    void main(){

    int vect[10][10];

    ......

    funcion(vect);

    ......

    }

    int funcion(int (*v)[][10]{

    .......

    En la segunda versin, la de la derecha, el parntesis de int (*v)[10] es necesario debido a la mayor prioridad del operador [] sobre el operador *.

    1.2.4. PUNTEROS EN FUNCIONES.

    Las funciones, al igual que las variables, tienen su propia direccin de memoria. Una caracterstica muy interesante, al mismo tiempo que confusa, es la de puntero en funcin. Este puntero corresponder a la direccin inicial del cdigo de la funcin.

    Los punteros en funciones permiten referenciar de forma indirecta una funcin, y tambin permiten que una funcin pueda ser pasada como argumento a otra funcin.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 9

    Como pasa con los vectores, el nombre de una funcin sin sus parntesis se interpreta como un puntero en la funcin.

    Para declarar un puntero en una funcin se hace normalmente de dos formas: la primera forma es declarar directamente una variable puntero en funcin de la siguiente forma: tipo (*nombre_puntero_funcin)(tipo, tipo,...);

    Es necesario poner parntesis alrededor del nombre de la funcin (*nombre_puntero_funcin) debido a que el operador * tiene menor prioridad que el parntesis que le rodea.

    La segunda forma es declarar un puntero tipo void, que posteriormente ser asignado a una funcin. Esta asignacin se puede hacer poniendo el nombre de una funcin, sin parntesis, al lado derecho de una sentencia de asignacin: void puntero;

    puntero=funcin;

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 10

    2. PRCTICA 1: PRIMER CONTACTO CON LOS PUNTEROS.

    En esta prctica aprenderemos a declarar un puntero, asignndole la direccin de una variable y entender los operadores & y *.

    2.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo C++ denominado m5p01.cc y se escribir el siguiente cdigo:

    //m5p01.cc - PRIMER CONTACTO CON LOS PUNTEROS -

    #include

    #include

    using namespace std;

    int main(){

    int i,j, *ptr_entero; //Declaracin de variables.

    //Es el modificador del nombre de la variable; es decir, declara que la

    variable que viene a continuacin es un puntero.

    system("clear");

    cout

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 11

    2.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    2.3. EXPLICACIN DEL PROGRAMA.

    Si ejecutamos el programa, la salida ser parecida a la siguiente (el valor de las direcciones puede cambiar de una ejecucin a otra, sea en el mismo ordenador o en otro):

    La direccin de la variable entera 'i' es: 0x0065FDF4 La direccin de la variable entera 'j' es: 0x0065FDF0 La direccin del puntero ptr_entero es: 0x0065FDEC

    La direccin de 'i' es 0x0065FDF4 y su contenido es: 10 La direccin del puntero es 0x0065FDEC y su contenido es: 0x0065FDF4 El puntero apunta a la variable 'i' de valor 10

    La direccin de la variable 'j' es 0x0065FDF0 y su valor es 10

    Lo primero que debemos observar en el programa anterior es la lnea: using namespace std; que es necesaria, ya que las declaraciones que permiten el

    acceso a cout y cin estn en una librera externa.

    En la declaracin: int i,j, *ptr_entero; //Declaracin de variables. se declaran simultneamente tres variables, dos variables enteras i, y j y una variable puntero en entero denominada ptr_entero.

    En las siguientes lneas se ordena que salga por pantalla las direcciones de las tres variables:

    cout

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 12

    Mientras que i muestra el valor de la variable, &i muestra la direccin donde est almacenada la variable i: La direccin de 'i' es 0x0065FDF4 y su contenido es: 10

    La siguiente lnea es una asignacin de un valor a la variable puntero. Evidentemente, este valor es una direccin de memoria, la direccin de la variable i:

    ptr_entero =&i; //Le ponemos la direccin de 'i' al puntero ptr_entero.

    Las siguientes sentencias muestran la diferencia entre el valor del puntero y su direccin:

    cout

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 13

    3. PRCTICA 2: DISEO DE UNA FUNCIN QUE INTERCAMBIA EL

    CONTENIDO DE DOS VARIABLES.

    En esta prctica aprenderemos la diferencia entre el paso de argumentos por valor y por referencia.

    3.1. DESARROLLO DE LA PRCTICA.

    Como hemos visto anteriormente, al pasar parmetros a una funcin se pasa una copia del contenido de la variable. Esto implica que la funcin no puede modificar las variables externas a ella (a excepcin de las globales). Podemos modificar el contenido de esta copia pero no afectar pero no afectar al contenido de la variable original.

    Crearemos un nuevo archivo C++ denominado m5p021.cc con el siguiente cdigo:

    //m5p021.cc - FUNCIN PERMUTA (I) PASO POR VALOR -

    #include

    #include

    using namespace std;

    void Permuta (int A, int B);

    int main(){

    int X=10, Z=20;

    system("clear");

    cout

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 14

    3.3. EXPLICACIN DEL PROGRAMA.

    Este programa no cambia el valor de las variables. Por qu? Porque la comunicacin entre una funcin y aquella que hace la llamada es para el traspaso de valores y no de variables. En realidad, este programa intercambia los valores de sus parmetros A y B pero no los argumentos de la llamada; es decir, el valor inicial es A=10 y B=20, y despus A=20 y B=10, pero X=10 y Z=20 tanto antes como despus de la llamada a la funcin Permuta.

    En general podemos enviar a las funciones dos tipos de informacin sobre las variables. En primer lugar, si usamos la sintaxis: funcion1 (x);, le transferimos el valor de la variable X. En segundo lugar, si usamos las sintaxis: : funcion2 (&x);, le transferimos la direccin de memoria de la variable X.

    El primer formato requiere que la definicin de la funcin incluya un argumento formal del mismo tipo que la variable X: funcion1 (int num){

    . . . . . . . . . .

    }

    Y el segundo formato, necesita que la definicin de la funcin incluya un argumento formal que sea un puntero al tipo de variable correspondiente: funcion2 (int *ptr){

    . . . . . . . . . .

    }

    Se utiliza el primer formato cuando la funcin necesita el valor para hacer un clculo o ejecutar alguna accin sobre el valor de la variable. Usaremos el segundo formato cuando la funcin necesite modificar las variables del programa de la llamada. Es ste, evidentemente, el caso de la funcin que queremos hacer, por tanto, modificaremos el cdigo, creando un nuevo archivo C++ denominado m5p022.cc quedando de la siguiente forma:

    //m5p022.cc - FUNCIN PERMUTA (II) PASO POR REFERENCIA -

    #include

    #include

    using namespace std;

    void Permuta (int *A, int *B);

    int main(){

    int X=10, Z=20;

    system("clear");

    cout

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 15

    3.4. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    La funcin Permuta intercambia punteros, de tal manera que A apunta a X y B apunta a Z, tanto antes como despus de la llamada a la funcin. Como que la funcin ha intercambiado los valores que son apuntados por las variables A y B, de hecho, intercambia los valores de las variables X y Z.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 16

    4. PRCTICA 3: PUNTEROS EN CUALQUIER TIPO DE DATOS.

    Recordemos que un puntero es una variable que contiene la direccin de otra variable. Es posible asignar el contenido de un puntero a otro puntero si los dos son del mismo tipo, si no es as, debemos utilizar un operador de conversin.

    Es posible, no obstante, utilizar unos punteros en cualquier tipo de datos, son los denominados punteros void. Veremos en esta prctica el uso de este tipo de punteros.

    4.1. DESARROLLO DE LA PRCTICA.

    Los punteros del tipo void se declaran como: void *

    Todos los tipos de punteros pueden ser asignados a un puntero del tipo void. En cambio un puntero del tipo void no puede ser directamente asignado a un puntero de otro tipo sin una conversin explcita.

    Por ejemplo, el compilador sabe que un puntero a un int hace referencia a 4 octetos de memoria en una mquina de 32bytes. Los punteros en void simplemente hacen referencia a una posicin de memoria y el compilador no sabe el tamao del objeto al cual hace referencia. El compilador necesita conocer el tipo de datos para saber el nmero de octetos a desreferenciar.

    En esta prctica veremos una sencilla aplicacin de los punteros void. Consiste en una funcin que puede admitir un argumento de tipo indeterminado. Este tipo de funcin nos recuerda las funciones de entrada y salida printf() y scanf() que tienen esta caracterstica.

    Crearemos un nuevo archivo del tipo C denominado m5p03.c con el siguiente cdigo:

    //m5p03.c - USO DE LOS PUNTEROS TIPO VOID -

    #include

    #include

    using namespace std;

    void funcion_ejemplo( void *prtvoid, char tipo);

    int main(){

    //Declaramos las variables y al mismo tiempo les asignamos valores.

    int a=10,*prta=&a;

    float b=5.5, *prtb=&b;

    char c='a', *prtc=&c;

    system("clear");

    //Llamamos a la funcin y le pasamos como segundo argumento el tipo de

    dato al que apunta el puntero.

    //Una referencia a 'int'.

    funcion_ejemplo(prta, 'i');

    //Una referencia a 'float'.

    funcion_ejemplo(prtb, 'f');

    //Una referencia a 'char'.

    funcion_ejemplo(prtc, 'c');

    return 0;

    }

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 17

    void funcion_ejemplo( void *prtvoid, char tipus){

    switch(tipo){

    case 'i':

    cout

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 18

    5. PRCTICA 4: PARMETROS ESTADSTICOS.

    En esta prctica definiremos las funciones Media() y Varianza() para calcular la media, la varianza y la desviacin tpica de una coleccin de datos de cualquier medida. Para almacenar los datos se utilizar un vector de nmeros reales.

    5.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo C denominado m5p04.c con el siguiente cdigo:

    //m5p04.c - PARMETROS ESTADSTICOS -

    #define MAX_NUM_DATOS 100

    #include

    #include

    #include

    double Media(double*, int);

    double Varianza(double* ,int );

    int main(){

    double Dato[MAX_NUM_DATOS],Var;

    int n,i;

    system("clear");

    //Introduccin a los datos.

    printf("Numero de datos a introducir:...");

    scanf("%d", &n);

    for(i=0;i

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 19

    5.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    5.3. EXPLICACIN DEL PROGRAMA.

    Los datos se almacenan en la variable indexada Dato[]. Esta variable se declara de forma que pueda almacenarse un mximo de 100 datos (MAX_NUM_DATOS).

    Los datos de introducen por teclado y son ledos por el siguiente cdigo:

    for(i=0;i

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 20

    6. PRCTICA 5: USO DE LOS PUNTEROS EN LOS VECTORES

    MULTIDIMENSIONALES.

    En esta prctica se tratar de entender bien cmo se almacenan los datos en un vector multidimensional. Tambin veremos la relacin entre punteros y vectores multidimensionales.

    6.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo denominado m5p05.c del tipo C y con el siguiente cdigo:

    // m5p05.c - USO DE PUNTEROS EN MATRICES BIDIMENSIONALES -

    #include

    #include

    int main(){

    int Tabla [3][5];

    //El nombre Tabla representa la direccin del primer elemento del vector,

    es a decir &Tabla[0][0].

    int *P;

    system("clear");

    printf("\n Valor de Tabla = %u",Tabla);

    //La variable '%u' hace referencia a un entero sin signo.

    printf("\n Valor de Tabla[0] = %u",Tabla[0]);

    printf("\n Direccion de Tabla [0][0] = %u",&Tabla[0][0]);

    printf("\n Direccion de Tabla [0][1] = %u",&Tabla[0][1]);

    printf("\n Direccion de Tabla [0][2] = %u",&Tabla[0][2]);

    printf("\n Direccion de Tabla [0][3] = %u",&Tablaa[0][3]);

    printf("\n Direccion de Tabla [0][4] = %u\n",&Tabla[0][4]);

    printf("\n Valor de Tabla [1] = %u",Tabla[1]);

    printf("\n Valor de Tabla [2] = %u",Tabla[2]);

    printf("\n Valor de Tabla [3] = %u",Tabla[3]);

    printf("\n Tabla + 1 = %u ",Tabla+1);

    printf("\n Tabla [0] + 1 = %u",Tabla[0]+1);

    Tabla[2][3]=5;

    P=Tabla[0];

    printf("\n Tabla [2][3] = %d",Tabla[2][3]);

    printf("\n *(*(Tabla + 2) + 3) = %d",*(*(Tabla+2)+3));

    printf("\n *(P+2*5+3) = %d\n", *(P+2*5+3));

    return 0;

    }

    Hablamos indistintamente de vector o de tabla para hacer referencia a la misma estructura de datos. As como en los vectores unidimensionales, en los vectores multidimensionales el nombre del vector tambin seala la direccin de memoria del primer elemento.

    Si tenemos la declaracin: int Tabla[3][4];, el nombre Tabla representa la direccin del primer elemento del vector; es decir: &Tabla[0][0].

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 21

    Un vector bidimensional se puede considerar como un vector de vectores, por lo que puede pensarse que Tabla[0] representa al subvector: Tabla[0][0], Tabla[0][1], Tabla[0][2], Tabla[0][3], Tabla[0][4]; y que Tabla[1] representa al subvector: Tabla[1][0], Tabla[1][1], Tabla[1][2], Tabla[1][3], Tabla[1][4].

    Resumiendo, Tabla apunta a Tabla[0] que es un vector de enteros, y Tabla[0] apunta a Tabla[0][0], que es un entero. Por tanto, Tabla es un puntero que apunta a otro puntero.

    Qu diferencia existe entre un puntero en un vector y un puntero en un entero? Aunque los dos almacenen posiciones de memoria, la diferencia est en el tamao del objeto al cual apuntan. En el ejemplo anterior, el puntero Tabla[0] apunta a un entero, por tanto apunta a un objeto de 4 octetos mientras que la Tabla apunta a un vector de 5 enteros y, por tanto, a un objeto de 20 octetos.

    Es por esta razn que si tenemos: Tabla+1, se obtendr una direccin 20 octetos mayor;

    Tabla[0]+1, se obtendr una direccin 4 octetos mayor.

    6.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    6.3. EXPLICACIN DEL PROGRAMA.

    Para explicar este programa, debemos fijarnos en la salida, que puede ser como esta (las direcciones concretas pueden variar de una ejecucin a otra):

    Segn los datos de la salida del programa, las direcciones de las 15 posiciones de memoria de la matriz Tabla[][] son:

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 22

    Tanto Tabla como Tabla[0] son punteros que apuntan a la primera posicin de memoria, es decir, 6684092.

    El puntero Tabla [1] apunta al primer elemento de la segunda fila (del segundo subvector) y Tabla [2] apunta al primer elemento de la tercera fila.

    Aunque parezca que Tabla es lo mismo que Tabla[0], ambos punteros apunta o objetos diferentes, lo cual se pone de manifiesto en la aritmtica de punteros:

    Tabla+1 = 6684112 (una posicin de memoria 20 octetos ms alta).

    Tabla[0] + 1 = 6684096 (una posicin de memoria 4 octetos ms alta).

    Por ltimo, el programa muestra tres formas de referirnos a un elemento concreto de la matriz, en este caso, el elemento [2][3]:

    Tabla [2][3];

    *(*(Tabla + 2) + 3);

    *(P+2*5+3)); (Donde 'P' es un puntero entero en la primera posicin del vector P=Tabla[0]).

    En general, para referirnos al elemento [i][j] se escribir:

    Tabla [i][j];

    *(*(Tabla + i) + j);

    *(P+i*5+j));

    Si en el caso de un vector unidimensional, Tabla[2] era equivalente a *(Tabla+2) y proporciona el tercer elemento del vector, en un vector bidimensional, *(Tabla+2) es el nombre de un vector.

    Cmo representaremos Tabla [2][3] (tercera fila, cuarta columna)? Para llegar a la tercera fila del vector escribiremos *(Tabla+2), para llegar a la columna 4 aadiendo 3, es decir, *(Tabla+2)+3 y el elemento debera ser *(*(Tabla+2)+3).

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 23

    7. PRCTICA 6: PRODUCTO DE MATRICES.

    En esta prctica calcularemos el producto de dos matrices entradas por el teclado, utilizaremos las variables indexadas multidimensionales (matrices).

    7.1. DESARROLLO DE LA PRCTICA.

    Este programa calcular el producto de dos matrices.

    Si tenemos dos matrices A y B, la primera de N filas y M columnas, y la segunda de M filas y P columnas (debemos fijarnos que el nmero de columnas de la primera matriz coincida con el nmero de filas de la segunda matriz), el producto de estas dos matrices se define como una matriz R de N filas y P columnas (tantas filas como la primera matriz y tantas columnas como en la segunda), donde cada elemento se calcula con la siguiente expresin:

    Rij = Ai0B0j + Ai1B1j + Ai2B2j + + A(i(m-1)B(m-1)j

    El producto de matrices es una operacin bsica y muy importante que tiene una gran cantidad de aplicaciones.

    Crearemos un nuevo archivo en C++ denominado m5p06.cc con el siguiente cdigo:

    // m5p06.cc - CLCULO DEL PRODUCTO DE DOS MATRICES -

    #include

    #define MAX_FILAS 10

    #define MAX_COLUMNAS 10

    int main(){

    double A[MAX_FILAS][MAX_COLUMNAS];

    double B[MAX_FILAS][MAX_COLUMNAS];

    double R[MAX_FILAS][MAX_COLUMNAS]={0};

    int FA, CA; //Filas y Columnas de A.

    int FB, CB; //Filas y Columnas de B.

    int FR, CR; //Filas y Columnas de R.

    int I,J,K;

    printf("\n Introduzca el numero de filas de la matriz A:");

    scanf("%d", &FA);

    printf("\n Introduzca el numero de columnes de A:");

    scanf("%d", &CA);

    FB=CA; //El nmero de Filas de B = Columnas de A.

    printf("\n La matriz B tendra %d filas\n",CA);

    printf("\n Introduzca el numero de columnas de B:");

    scanf("%d", &CB);

    //Introduccin de los elementos de A.

    for (I=0;I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 24

    //Introduccin de los elementos de B.

    for (I=0;I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 25

    7.3. EXPLICACIN DEL PROGRAMA.

    Lo primero que podemos observar en este programa es la definicin de las macros MAX_FILAS y MAX_COLUMNAS, ambas con el valor de 10. Es una buena prctica definir este tipo de macros para poder modificar rpidamente el cdigo en caso que necesitemos aumentar o disminuir la medida de las matrices.

    Se definen tres matrices de dos dimensiones denominadas A, B y R. Las dos primeras contendrn las matrices que queremos multiplicar y la ltima el resultado del producto. Es interesante observar que la tercera matriz se inicializa a 0 de esta forma:

    double R[MAX_FILAS][MAX_COLUMNAS]={0};

    No es necesario escribir ms que un 0.

    A continuacin se solicita al usuario el nmero de filas y columnas de la primera matriz, as como el nmero de columnas de la segunda matriz. El nmero de filas de la segunda matriz no se solicita, ya que coincide con el nmero de columnas de la primera matriz.

    Despus hay dos dobles bucles que sirven para rellenar los valores de los elementos de las dos matrices.

    El clculo del producto se hace con el siguiente triple bucle:

    //Clculo del producto A*B.

    FR=FA;CR=CB; //Clculo de las dimensiones de 'R'.

    for(I=0;I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 26

    8. PRCTICA 7: CLCULO DE LA MATRIZ TRANSPUESTA DE UNA

    MATRIZ CUADRADA.

    En esta prctica aprenderemos como se pasan vectores multidimensionales en una funcin, construyendo una funcin denominada transpuesta que har la transposicin de una matriz pasada como argumento.

    8.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo del tipo C++ denominado m5p07.cc con el siguiente cdigo:

    //m5p07.cc - TRANSPOSICIN DE UNA MATRIZ CUADRADA -

    #include

    #define MAX_FILAS 10

    void Tranposicion(double [][MAX_FILAS],int);

    int main(){

    double A[MAX_FILAS][MAX_FILAS];

    int N,I,J; //Numero de filas y de columnas.

    printf("\n Introduzca el numero de filas de la matriz A:");

    scanf("%d", &N);

    //Introduccin de los elementos de A.

    for (I=0;I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 27

    Si tenemos una matriz A de N filas y M columnas, se denomina transpuesta de A, y se anota AT, c.omo la matriz de M filas y N columnas que resulta de cambiar el elemento Aij por el elemento Aji. De momento, y para simplificar esta prctica, supondremos matrices cuadradas, esto quiere decir del mismo nmero de filas que de columnas.

    Esquemticamente, si tenemos la matriz A:

    La matriz transpuesta es:

    8.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    8.3. EXPLICACIN DEL PROGRAMA.

    El programa solicita los elemento de la matriz A, una vez introducidos todos, muestra l matriz, la transpone y la vuelve a mostrar para ver como se ha producido la transposicin.

    La transposicin se hace a travs de la funcin Transpuesta(). Fijmonos que el protocolo de esta funci se pone double[][MAX_FILAS] como primer argumento. Es obligatorio indicar todas las dimensiones menos la primera.

    La llamada se hace con el nombre de la matriz. En los vectores multidimensionales el nombre es un puntero al primer elemento de un vector de punteros. En este caso, A=&A[0] y A[0]=&A[0][0].

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 28

    9. PRCTICA 8: LA LEY DE HONDT. CLCULO DE LOS ESCAOS DE

    CADA PARTIDO EN UNAS ELECCIONES.

    En esta prctica veremos un ejemplo prctico e interesante donde hay definida una funcin que recibe como argumentos dos vectores.

    9.1. DESARROLLO DE LA PRCTICA.

    En nuestro pas los candidatos a diputado se presentan a las elecciones agrupados en las denominadas candidaturas o listas, que pueden ser presentadas por partidos polticos o por coaliciones de partidos. Cada elector vota una de las listas. A partir del nmero de votos obtenidos, cada lista recibe una cierta cantidad de escaos.

    Para determinar el nmero de escaos que recibe cada lista se utiliza el sistema que se conoce con el nombre de Ley de Hondt. Esta ley se implementa en el siguiente programa.

    Crearemos un nuevo archivo de tipo C denominado m5p08.c con el siguiente cdigo:

    //m5p08.c - MTODO DE HONDT -

    #include

    #include

    #define N_ESC 2 //Nmero de escaos.

    #define N_PAR 3 //Nmero de partidos.

    int Nuevo_escao(int *, int *);

    int main(void){

    int ct;

    int Escaos[N_PAR]={0}; //Escaos{[N_PAR]= Nmero escaos por partido.

    int Votos[N_PAR]; //Votos[N_PAR] = Nmero votos por partido.

    system("clear");

    printf("Introduce el numero de votos de cada partido.\n");

    for (ct=0; ct

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 29

    9.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    9.3. EXPLICACIN DEL PROGRAMA.

    Llamaremos Escao[0], Escao[1], Escao[2], ... respectivamente al nmero de escaos que sern asignados a cada partido. Al comienzo estas tres variables sern 0 y a medida que se vayan asignando escaos cambiarn su valor.

    Llamaremos Votos[0], Votos[1], Votos[2], ... respectivamente al nmero de votos que ha obtenido cada partido.

    El primer escao se asigna al partido ms votado. Los otros escaos se asignan con el siguiente criterio:

    El siguiente escao se asigna al partido que maximice la expresin Votos[]/(Escao[]+1). Esta asignacin se har mediante la funcin Nuevo_escao(), que tiene como argumentos dos punteros a los dos vectores Votos[] y Escaos[]; es decir, las direcciones de memoria (o el nombre de los vectores) y retorna un nmero entero que corresponde al partido que recibe un nuevo escao.

    Para explicar cmo funciona esta ley veremos un ejemplo:

    Imaginemos que se presentan 3 partidos: A, B y C, que han recibido 120, 50 y 40 votos respectivamente y se deben repartir un total de 7 escaos.

    Por lo tanto, Votos[A]=120, Votos[B]=50, Votos[C]=40 e inicialmente: Escao[A]=0, Escao[B]=0 y Escao[C]=0.

    El primer escao es para el partido A que tiene el nmero de votos ms grande, por tanto: Escao[A]=1, Escao[B]=0 y Escao[C]=0.

    El clculo de Votos[]/(Escao[]+1) da como resultado: 60, 50 y 40; por tanto, el segundo escao tambin es para el partido A: Escao[A]=2, Escao[B]=0 y Escao[C]=0.

    Calculando otra vez Votos[]/(Escao[]+1) da como resultado: 30, 50 y 40; por tanto, el segundo escao es para el partido B: Escao[A]=2, Escao[B]=1 y Escao[C]=0.

    El nuevo clculo de Votos[]/(Escao[]+1) da como resultado: 30, 25 y 40; por tanto, el segundo escao es para el partido C: Escao[A]=2, Escao[B]=1 y Escao[C]=1.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 30

    Calculando nuevamente Votos[]/(Escao[]+1) da como resultado: 30, 25 y 20; por tanto, el segundo escao es para el partido A: Escao[A]=3, Escao[B]=1 y Escao[C]=1.

    El nuevo clculo de Votos[]/(Escao[]+1) da como resultado: 15, 25 y 20; por tanto, el segundo escao es para el partido B: Escao[A]=3, Escao[B]=2 y Escao[C]=1.

    Finalmente, el ltimo clculo de Votos[]/(Escao[]+1) da como resultado: 15, 12,5 y 20; por tanto, el segundo escao es para el partido C: Escao[A]=3, Escao[B]=2 y Escao[C]=2.

    Como ya se han repartido los 7 escaos previstos, ya no se puede seguir con los clculos.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 31

    10. PRCTICA 9: REPETICIN DE CARACTERES ALFABTICOS CON

    MAYSCULAS.

    Queremos generar 30.000 nmeros aleatorios entre el nmero 65 (carcter A) y el 90 (carcter Z), siendo un total de 26 letras y almacenar este resultado de tal forma que el programa listar todos los caracteres alfabticos entre la A y la Z con el nmero de veces que ha salido.

    10.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo de tipo C++ denominado m5p09.c con el siguiente cdigo:

    //m5p09.cc - REPETICIN DE LOS CARACTERES ALFABTICOS CON MAYSCULAS.

    #include

    #include

    #include

    int main(){

    int I=1,Inicio=65, Tope=90,Dato;

    int Valores[26]={0};

    time_T T; //Para generar la semilla.

    //Inicializar la generacin de nmeros aleatorios.

    srand((unsigned) time(&T));

    printf(" Generacion de numeros aleatorios \n\n" );

    for( I=1; I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 32

    10.3. EXPLICACIN DEL PROGRAMA.

    Con el siguiente fragmento de cdigo generaremos nmeros aleatorios entre 0 y 25 ambos incluidos: for( I=1; I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 33

    11. PRCTICA AMPLIACIN 1: USO DE VECTORES DE PUNTEROS EN

    FUNCIONES.

    En esta prctica veremos un ejemplo de punteros en funciones.

    11.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo del tipo C++ denominado m5pa01.cc con el siguiente cdigo:

    //m5pa1.cc - VECTORES DE PUNTEROS EN FUNCIONES -

    #include

    #include

    using namespace std;

    void (*Afuncion[4])(int,int);

    void Suma(int A,int B);

    void Resta(int A,int B);

    void Multiplicacion(int A,int B);

    void Division(int A,int B);

    int main(){

    int I,C=20,D=10;

    system("clear");

    Afuncion[0]=Suma;

    Afuncion[1]=Resta;

    Afuncion[2]=Multiplicacion;

    Afuncion[3]=Division;

    for(I=0;I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 34

    11.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    11.3. EXPLICACIN DEL PROGRAMA.

    La caracterstica principal de este programa es que puede se puede llamar a cuatro funciones diferentes con una sola sentencia de llamada. La lnea de cdigo clave es la siguiente:

    for(I=0;I

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 35

    12. PRCTICA AMPLIACIN 2: TABLA VALORES DIVERSAS FUNCIONES.

    PASAR UNA FUNCIN COMO ARGUMENTO DE OTRA FUNCIN.

    En esta prctica aprenderemos a declarar, definir y llamar funciones que tienen como argumentos punteros a otras funciones.

    12.1. DESARROLLO DE LA PRCTICA.

    Crearemos un nuevo archivo del tipo C denominado m5pa02.c con el siguiente cdigo:

    //m5pa2.cc - LISTA DE VALORES DE DIVERSAS FUNCIONES -

    #include

    #include

    #include

    void Proceso(double(*F)(double),double VI, double INC, int NP);

    int main(){

    double VI=0;

    double INC=1;

    int NP=5;

    double (*PF)(double);

    system("clear");

    printf("Lista de valores de la funcion sin\n");

    PF = sin; Proceso(PF,VI,INC,NP);

    printf("Lista de valores de la funcion cos\n");

    PF = cos; Proceso(PF,VI,INC,NP);

    printf("Lista de valores de la funcion tan\n");

    PF = tan; Proceso(PF,VI,INC,NP);

    return 0;

    }

    void Proceso(double(*F)(double),double VI, double INC, int NP){

    int CT;

    double Valor;

    for (CT=0,Valor=VI;CT

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 36

    12.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

    12.3. EXPLICACIN DEL PROGRAMA.

    Otro uso de los punteros en funciones es la posibilidad de poder pasar una funcin como argumento de otra funcin. En este programa, la funcin que tiene como argumento una funcin es la funcin Proceso() que tiene el siguiente protocolo:

    void Proceso(double(*F)(double), double VI, double INC, int NP);

    Esta funcin, que no retorna ningn valor, tiene cuatro argumentos, el primero del cual es un puntero a otra funcin que tiene un argumento del tipo double y retorna un valor del tipo double. Los otros tres argumentos son de variables numricas normales.

    Esta funcin servir para imprimir una lista de NP valores de la funcin apuntada por el puntero F donde los argumentos de esta funcin comienzan como VI y se incrementan de INC en INC.

    Por ejemplo, cuando el puntero PF apunta a la funcin sin, como que el valor de las variables son VI=0, INC=1, NP=5, la funcin Proceso(PF, VI, INC, NP) hace que se imprima el valor y el valor seno de los nmeros desde o hasta el 4; es decir:

    Lista de valores de la funcin sin.

    0: 0.00 0.00

    1: 1.00 0.84

    2: 2.00 0.91

    3: 3.00 0.14

    4: 4.00 -0.76

    Para que el puntero PF declarado previamente como un puntero en una funcin que retorna un valor double y admite un argumento double apunte a la funcin de la librera estndar sin() basta con asignarle el nombre de la funcin sin los parntesis: PF = sin;

    Esto mismo se podra hacer con cualquier funcin, ya sea de la librera estndar de C/C++ o no. Slo es necesario que la funcin tenga el protocolo compatible con la definicin del puntero PF.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 37

    13. EJERCICIOS.

    1) Rotar tres variables.

    Escribiremos un programa en el cual se utilice la funcin: void Rota(int *A, int *B, int *C)

    Esta funcin debe rotar los valores de las tres variables enteras A, B y C; es decir, el contenido de A pasar a B, el contenido de B pasar a C y el contenido de C pasar a A. Por ejemplo, si los valores antes de la llamada a la funcin son: A=2, B=3 y C=10, despus de la llamada a la funcin, debern ser: A=10, B=2 y C=3. Evidentemente, como queremos que la funcin modifique sus argumentos, estos deben ser punteros.

    Denominaremos al programa m5e1.c dentro de la carpeta Mdulo_5.

    2) La Coladera de Eratstenes.

    Un nmero entero primo es aquel que slo puede dividirse entre 1 y s mismo. La Coladera de Eratstenes es un mtodo para encontrar nmeros primos y siguiendo los pasos:

    Declaramos un vector de enteros y ponemos un 1 en todas sus celdas. Para dar este valor inicial hay que hacer un bucle que ponga todas las celdas a 1. Al finalizar el mtodo aquellos elementos del vector que tengan subndices primos permanecern con el contenido inicial. El resto de celdas en algn momento tendrn un 0.

    Se comienza por el subndice 2, ya que el subndice 1 es primo, y cada vez que se encuentre una celda que contenga un 1 hay que hacer: Guardar en una variable, por ejemplo Sindex, su subndice.

    Se repasa el resto del vector y se ponen a 0 todas aquellas celdas que su subndice sea mltiple de Sindex. Para el subndice 2, pondremos a 0 el contenido de los subndices 4, 6, 8, 10, y as hasta el final del vector.

    En el caso del subndice 3, pondremos a 0 las celdas 6, 9, 12, 15, y as hasta el final del vector.

    Una vez acabado todo el proceso se hace una pasada por todas las posiciones del vector y aquellas posiciones que tienen como contenido 1 su subndice es un nmero primo.

    Escribiremos un programa que sobre un vector de 1000 posiciones muestre por la pantalla los nmeros primos que hay entre 1 y 999, ignorando la posicin 0 del vector.

    Denominaremos al programa m5e2.c dentro de la carpeta Mdulo_5.

    3) Buscar el Punto_Suma de un vector de dimensin M por N.

    Denominamos Punto_Suma de un vector bidimensional al elemento que coincide con la suma del resto de elementos del vector.

    Por ejemplo: dada la matriz de enteros A de 3 por 4 (int A[3][4]), en la posicin [1][1], que contiene el entero 197, tenemos el Punto_Suma que es el que coincide con la suma del resto de celdas ( 5 + 2 + 6 + 7 + 0 + 1 + 8 + 1 + 7 + 10 + 150 = 197).

    Escribiremos un programa que permita recoger enteros para almacenarlos dentro de la matriz A de M por N, denominndolo m5e3.c dentro de la carpeta Mdulo_5.

    El programa trabajar utilizando las directivas #define para dar el tamao del vector en tiempo de diseo: #define M 3 y #define N 4. Ms adelante veremos, con la asignacin dinmica de memoria, como dar el tamao del vector en tiempo de ejecucin.

    Escribiremos una funcin con el siguiente prototipo int Punto_Suma (int B[][N]; que recoger el vector y retornar, si existe, el Punto_Suma.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 38

    4) Transpuesta de una matriz NxM.

    Uno de los problemas que se puede plantear despus de la prctica 7 es qu sucede con la matriz que no es cuadrada. Esto supone un problema por el hecho que no se puede convertir una matriz de dimensin NxM en una matriz de dimensin MxN.

    Una forma de resolver este problema es utilizar una nica dimensin; es decir, declarar la matriz como: double A[MAX_FILAS*MAX_FILAS];

    Ahora, si denominamos N al nmero de filas y M al nmero de columnas, todo el cdigo es parecido al de la prctica cambiando: A[I][J] por A[I*N+J], y cambiando N por M en la comprobacin del segundo bucle. Por ejemplo, la parte del cdigo que solicita los elementos de la matriz sera: //Introduccin de los elementos de A.

    for (I=0;I(U[0]+U[1])/2 US[N-1]=(U[N-2]+U[N-1])/2

    Por ejemplo, el vector U de la primera columna de esta tabla debe convertirse en el vector US de la segunda columna

    Para entender bien el significado de esta "suavizacin" veremos dos diagramas de barras correspondientes a los vectores U y US donde se puede observar como en el segundo vector las diferencias entre elementos contiguos son ms pequeos.

    Denominaremos al programa m5e5.c dentro de la carpeta Mdulo_5.

  • MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 39

    6) La Ley de Hondt.

    Modificaremos el programa de la prctica 8 para que el nmero de escaos y de partidos se pueda introducir por teclado.

    En el programa de la prctica 8 hay un caso que no se ha tenido en cuenta, y es que cuando se evala la funcin Nuevo_escao para asignar uno nuevo, en el caso que dos partidos tengan el mismo valor de Votos[]/(Escao[]+1), el escao debera asignarse al partido ms votado.

    Realizaremos las modificaciones necesarias para que se considere esta circunstancia. Probaremos con tres partidos y cuatro escaos, y que los votos de los tres partidos sean 40, 50 y 120.

    Denominaremos al programa m5e6.c dentro de la carpeta Mdulo_5.

    7) Valor mximo de un vector.

    Haremos un programa en el cual se utilice la funcin:

    double mximo(double *vector, int grande)

    Esta funcin ha de retornar el mximo del vector de nmeros reales vector que tiene grande elementos del tipo double.

    Denominaremos al programa m5e7.c dentro de la carpeta Mdulo_5.