-
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.