You are on page 1of 39

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 <iostream>
#include <stdlib.h>

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<<"La direccin de la variable entera 'i' es: "<<&i<<endl;
cout<<"La direccin de la variable entera 'j' es: "<<&j<<endl;
cout<<"La direccin del puntero ptr_entero es: "<<&ptr_entero<<endl;
//ptr_entero nos retorna la posicin o direccin de la memoria.

i = 10;

cout<<"La direccin de 'i' es: "<<&i<<" y su contenido es: "<<i<<endl;

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

cout<<"La direccin del puntero es: "<<ptr_entero<<" y su contenido
es: "<<ptr_entero<<endl;
cout<<"El puntero apunta a la variable 'i' de valor:
"<<*ptr_entero<<endl;

j=*ptr_entero; //Le damos el valor de la variable a la que apunta el
puntero ptr_entero.

cout<<"La direccin de la variable 'j' es: <<&j<<" y su valor es:
"<<j<<endl;

return 0;

}

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<<"La direccin de la variable entera 'i' "<<"es: "<<&i<<endl;
cout<<"La direccin de la variable entera 'j' "<<"es: "<<&j<<endl;
cout<<"La direccin del puntero ptr_entero "<<"es: "<<&ptr_entero<<endl;
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
Por defecto, las direcciones salen en forma hexagesimal.
Debemos fijarnos que el orden para almacenar estas variables es el orden inverso de
escritura en la lnea y que las tres ocupan 4 octetos de memoria (de hecho, slo se puede
comprobar esta circunstancia con las variables *ptr_entero y j).
A continuacin se asigna el valor 10 a la variable i: i = 10;
Con la siguiente sentencia se salida se puede comprender la diferencia entre &i y i:
cout<<"La direccin de 'i' es: "<<&i<<" y su contenido es: "<<i<<endl;

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<<"La direccin del puntero es: "<<ptr_entero<<" y su contenido
es: "<<ptr_entero<<endl;
cout<<"El puntero apunta a la variable 'i' de valor:
"<<*ptr_entero<<endl;
La direccin del puntero es 0x0065FDEC y su contenido es: 0x0065FDF4
El puntero apunta a la variable 'i' de valor 10
Ambas cosas son direcciones. Se puede comprobar que el contenido de la variable
ptr_entero coincide con la direccin de la variable i mostrada anteriormente. Tambin se puede
comprobar el significado del operador de indireccin * que muestra el valor 10; es decir, el valor
de la variable apuntada por el puntero.
Por ltimo, hay una sentencia donde asigna el valor de la variable apuntada por el puntero
(10) en la variable j. La sentencia de salida siguiente permite comprobar que la direccin de la
variable j no ha cambiado y s su valor que ahora vale 10:
j=*ptr_entero; //Le damos el valor de la variable a la que apunta el
puntero ptr_entero.

cout<<"La direccin de la variable 'j' es: <<&j<<" y su valor es:
"<<j<<endl;
La direccin de la variable 'j' es 0x0065FDF0 y su valor es 10


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 <iostream>
#include <stdlib.h>

using namespace std;

void Permuta (int A, int B);

int main(){

int X=10, Z=20;
system("clear");
cout<<" Antes de la llamada a la funcin X= "<<X<<" y Z= "<<Z<<endl;
Permuta (&X, &Z);
cout<<" Despues de la llamada a la funcin X= "<<X<<" y Z= "<<Z<<endl;
return 0;
}

//Las variables 'A' y 'B' son locales en la funcin y recogen una copia
de los valores de 'X' y 'Z'.
void Permuta (int A, int B){
int Cambia;

Cambia=A;
A=B;
B=Cambia;
}
3.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.


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 <iostream>
#include <stdlib.h>

using namespace std;

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

int main(){

int X=10, Z=20;

system("clear");
cout<<" Antes de la llamada a la funcin X= "<<X<<" y Z= "<<Z<<endl;
Permuta (&X, &Z);
cout<<" Despues de la llamada a la funcin X= "<<X<<" y Z= "<<Z<<endl;
}

void Permuta int *A, int *B){
int Cambia;

Cambia=A;
*A=*B;
*B=Cambia;

}


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 <stdio.h>
#include <stdlib.h>

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<<"Valor recibido por la funcion ... "<< *((int *)
prtvoid)<<endl;
break;

case 'f':
cout<<"Valor recibido por la funcion ... "<< *((float *)
prtvoid)<<endl;
break;

case 'c':
cout<<"Valor recibido por la funcion ... "<< *((char *)
prtvoid)<<endl;
break;

default:
cout<<"Tipo no valido .."<<endl;
}
}

4.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.

4.3. EXPLICACIN DEL PROGRAMA.
Fijmonos que la funcin funcin_ejemplo tiene dos argumentos. El segundo es
necesariamente un carcter, pero el primer argumento puede ser cualquier tipo de puntero. En la
declaracin de la funcin, el primer argumento es un puntero del tipo void*.
Cuando se tiene un puntero del tipo void*, es necesario hacer una conversin explcita para
tener un puntero de un tipo especfico para poderlo utilizar. Esto se hace con los operadores:
(int*), (float*) y (char*) que convierten el puntero void* en punteros del tipo int, float y char
respectivamente.



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 <stdio.h>
#include <math.h>
#include <stdlib.h>

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<n;i++){
printf("Dato %d:..",i);
scanf("%lf",&Dato[i]);
}

//Clculo de los parmetros:
printf("\n Numero de datos...%d",n);
printf("\n Media ...%lf",Media(dato,n));
Var=Varianza(Dato,n);
printf("\n Varianza ...%lf", Var);
printf("\n Desviacion tipica...%lf\n", sqrt(Var));
return 0;
}

double Media(double *Dato,int n){
double Res=0;
int i;
for(i=0;i<n;i++) Res=Res+Dato[i];
return Res/n;
}

double Varianza(double *Dato,int n){
double Res=0;
double Med;
int i;
Med=Media(Dato,n);
for(i=0;i<n;i++) Res=Res+Dato[i]*Dato[i];
return Res/n-Med*Med;
}

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<n;i++){
printf("Dato %d:..",i);
scanf("%lf",&Dato[i]);
}
La variable n es leda con anterioridad y contiene el nmero de datos que se introducirn.
El clculo de la media y la varianza se hacen a travs de las funciones Media() y Varianza().
Ambas funciones tienen como argumentos el vector de datos y el nmero de datos.
El nmero de datos se pasa por valor y el vector se pasa por referencia; es decir, no se hace
copia de todos los datos si no que se pasa el nombre del vector, que es un puntero a la primera
posicin de los datos originales.
Las frmulas para el clculo de la media, la varianza y la desviacin tpica ya fueron
presentadas en el ejercicio 6 del mdulo 2.


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 <stdio.h>
#include <stdlib.h>

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:
R
ij
= A
i0
B
0j
+ A
i1
B
1j
+ A
i2
B
2j
+ + 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 <stdio.h>
#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<FA;I++){
for(J=0;J<CA;J++){
printf("A[%d,%d]=",I,J);
scanf("%lf",&A[I][J]);
}
}

MP 11 UF 01 Mdulo 4 Fundamentos Programacin. Pgina 24

//Introduccin de los elementos de B.
for (I=0;I<FB;I++){
for(J=0;J<CB;J++){
printf("B[%d,%d]=",I,J);
scanf("%lf",&B[I][J]);
}
}

//Clculo del producto A*B.
FR=FA;CR=CB; //Clculo de las dimensiones de 'R'.
for(I=0;I<FR;I++){
for(J=0;J<CR;J++){
for(K=0;K<fb;K++){
R[I][J]=R[I][J]+A[I][K]*B[K][J];
}
}
}

// Resultado.
for (I=0;I<FR;I++){
for(J=0;J<CR;J++){
printf("\n R[%d,%d]=%lf",I,J,R[I][J]);
}
}
return 0;
}
7.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.



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<FR;I++){
for(J=0;J<CR;J++){
for(K=0;K<fb;K++){
R[I][J]=R[I][J]+A[I][K]*B[K][J];
}
}
}
La parte resaltada corresponde realmente al clculo del elemento R
IJ
.


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 <stdio.h>
#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<n;I++){
for(J=0;J<N;J++){
printf("A[%d,%d]=",I,J);
scanf("%lf",&A[I][J]);}
}

// Matriz A antes de la transposicin.
for (I=0;I<N;I++){
for(J=0;J<N;J++){
printf("A[%d,%d]=%lf\t",I,J,A[I][J]);
}
printf("\n");
}
Transposicion(A,N);

// Matriz A despus de la transposicin.
printf("\n");
for (I=0;I<N;I++){
for(J=0;J<N;J++){
printf("A[%d,%d]=%lf\t",I,J,A[I][J]);
}
printf("\n");}
return 0;
}

void Transposicion(double A[][MAX_FILAS],int N){
double Temp;
int I,J;
for (I=1;I<N;I++){
for(J=0;J<I;J++){
Temp=A[I][J];
A[I][J]=A[J][I];
A[J][I]=Temp;}
}
}

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
A
T
, c.omo la matriz de M filas y N columnas que resulta de cambiar el elemento A
ij
por el
elemento A
ji
. 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 <stdio.h>
#include <stdlib.h>
#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<N_PAR; ++ct) {
printf("\n Partido %d: ", ct+1);
scanf("%d", &Votos[ct]);
}
for(ct=0; ct<N_ESC; ++ct) Escao[Nuevo_escao(Votos, Escao)]++;
for (ct=0; ct<N_PAR; ++ct)
printf("\n El partido %d ha obtenido %d escaos.", ct+1,
Escao[ct]);
return 0;
}

int Nuevo_escao( int Votos[], int Escao[]) {

int imax=0, ct;
int max=0;

for( ct=0; ct<N_PAR; ++ct) {
if( max<(Votos[ct]/(Escao[ct]+1)) ) {
max=votos[ct]/(Escao[ct]+1);
imax=ct;
}
}
return imax;
}

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 <stdio.h>
#include <stdlib.h>
#include <time.h>

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<=30000; I++ ){
Dato=rand() % 26 ; //Desde 0 a 25 ambos incluidos.
//En este caso, '%' retorna el resto entero de un nmero entre 0 y 25.
Valores[Dato]++;
}

//Resultados.
for(I=0;I<26;I++)
printf("\n Letra %c numero de veces %d",I+65,Valores[I]);

return 0;
}
10.2. CAPTURA DE LA EJECUCIN DEL PROGRAMA.


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<=30000; I++ ){
Dato=rand() % 26 ; //Desde 0 a 25 ambos incluidos.
Valores[Dato]++;
}
Tenemos un vector Valores[] de 26 posiciones (debemos recordar que los ndices van desde
0 a 25) y hacemos corresponder el ndice 0 con el 65, el 1 con el 66, , el ndice 25 con el 90.
De esta manera tenemos en la celda con ndice 0 el total de veces que ha salido el cero y lo
hacemos corresponder con la letra A que en la tabla ASCII ocupa la posicin 65 y as
sucesivamente.
Con las siguientes instrucciones se muestra en la pantalla el contenido de cada celda y el
ndice al que le sumamos 65:
//Resultados.
for(I=0;I<26;I++)
printf("\n Letra %c numero de veces %d",I+65,Valores[I]);
return 0;
}
La salida del programa ms o menos es la siguiente:



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 <iostream>
#include <stdlib.h>

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<4;++I) Afuncion[I](C,D);

return 0;
}

void Suma(int A,int B){
cout << A << " + " << B << " = " << A+B << endl;
}

void Resta(int A,int B){
cout<< A << " - " << B << " = " << A-B << endl;
}

void Multiplicacion(int A,int B){
cout << A << " * " << B << " = " << A*B << endl;
}

void Division(int A,int B){
cout << A << " / " << B << " = " << A/B << endl;
}

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<4;++I) Afuncion[I](C,D);
Esta lnea es un bucle que se ejecuta 4 veces. Cada vez que se ejecuta el valor de la variable
I vara de 0 hasta 3. El cuerpo del bucle es una llamada a la funcin Afuncion[I](). De hecho, no es
realmente una funcin si no un puntero en una funcin, el cual, s debe declarar al inicio como
cualquier otra variable. La declaracin se hace de la siguiente forma:
void (*Afuncion[4])(int,int);
De esta forma se declara un vector de punteros en una funcin que no retorna ningn valor
y tiene dos argumentos enteros.
Las lneas siguientes asignan a cada uno de estos cuatro punteros un valor inicial:
Afuncion[0]=Suma;
Afuncion[1]=Resta;
Afuncion[2]=Multiplicacion;
Afuncion[3]=Division;
El nombre de una funcin sin parntesis se interpreta como un puntero en esta funcin. Las
funciones Suma(), Resta(), Multiplicacin() y Divisin() se deben estar previamente declaradas
como funciones que no retornan ningn valor y tienen dos argumentos enteros.
Cuando se utiliza un puntero en funcin seguido de los parntesis y la lista de argumentos,
se interpreta como una llamada en la funcin apuntada por el puntero. La salida del programa es
la siguiente:
20 + 10 = 30
20 - 10 = 10
20 * 10 = 200
20 / 10 = 2


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 <math.h>
#include <stdio.h>
#include <stdlib.h>

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<NP;CT++,Valor=Valor+INC){
printf("%d: %4.2lf %4.2lf\n",CT,Valor,F(Valor));
}
}

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<N;I++){
for(J=0;J<M;J++){
printf("\n A[%d,%d]=",I,J);
scanf("%lf",&A[I*M+J]);
}
}
Tambin deben hacerse modificaciones en la funcin Transposicion(A,N), aadindole un
argumento que corresponda al nmero de columnas.
Denominaremos al programa m5e4.c dentro de la carpeta Mdulo_5.
13.1. PROBLEMAS COMPLEMENTARIOS.
5) Suavizacin de un vector.
Haremos un programa que "suavice" un vector introducido por
el usuario. Entenderemos por "suavizar" sustituir cualquier elemento
por la media aritmtica de los elementos ms cercanos; es decir:
U
S
[I]->(U[I-1]+U[I]+U[I+1])/3 si I diferente de 0 y N-1
U
S
[0]->(U[0]+U[1])/2
U
S
[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 U
S
de la segunda columna
Para entender bien el significado de esta "suavizacin" veremos
dos diagramas de barras correspondientes a los vectores U y U
S
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.

You might also like