Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
PROGRAMACION
Y
METODOS NUMERICOS
1
Índice general
I. Generalidades 1
I.1. ¿Como creo un programa? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
I.2. Trabajando con DEV C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
I.3. ¿Como escribo un programa? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
I.4. Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
I.5. Comandos útiles de la librerı́a stdio.h . . . . . . . . . . . . . . . . . . . . . . . . . 6
I.5.1. printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
I.5.2. scanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
I.6. Algunos comandos importantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
I.6.1. Tabla de códigos útiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
I.6.2. // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
I.6.3. /* */ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
III.FUNCIONES 18
III.1. Declaración de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
III.1.1. Tipos de función . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
III.2. Construcción de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
III.3. Parámetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
III.3.1. Paso por valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
III.3.2. Paso por referencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
III.4. Distibución de un programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
III.5. Funciones Recursivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2
ÍNDICE GENERAL ÍNDICE GENERAL
IV.AGRUPAMIENTO DE VARIABLES 27
IV.1. Arreglos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
IV.2. Cadenas de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
IV.3. apuntadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
IV.3.1. Asignación de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
IV.3.2. Liberación de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
IV.4. Arreglos en funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
IV.5. Vectores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
IV.6. Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
IV.6.1. Arreglos bidimensionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
IV.6.2. Matrices con apuntador . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
V. ESTRUCTURAS 51
V.0.3. Sistemas numéricos en estructuras . . . . . . . . . . . . . . . . . . . . . . 52
V.1. arreglos de estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
VI.ARCHIVOS 60
VI.1. Comandos importantes para el manejo de archivos . . . . . . . . . . . . . . . . . 61
VI.1.1. fopen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
VI.1.2. fclose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
VI.1.3. fscanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
VI.1.4. fprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
VI.2. Archivos como parámetros de funciones . . . . . . . . . . . . . . . . . . . . . . . 64
VI.2.1. Inconvenientes con los datos . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3
INTRODUCCIÓN
En 1970 nace un programa conocido como B, diseñado en 1970 por Ken Thompson (AT&T),
inspirado en el programa BCP L. En 1972 es Dennis Ritchie diseña finalmente C a partir del
modelo aportado por el programa B, la novedad que ofrecı́a C era la eficacia superior gracias a
su diseño basado en tipos y estructuras de datos.
Este nuevo programa nos permite realizar con mayor eficacia una programación estructurada
(división del programa en funciones independientes que se unifican)1 , debido a la variedad de
opciones que nos ofrece, esto sin tener en cuenta la optimización de los recursos del ordenador,
lo cual nos ofrece programas mas veloces. La principal ventaja de C es su versatilidad, ya que
no es un programa diseñado con orientación hacia algún area en especifico.
En 1980 surge C++2 de la mano de Bjarne Stroustrup (AT&T), este nuevo lenguaje es una
extensión de C, ya que dota de nuevas caracterı́sticas entre las que destacan la gran cantidad
de funciones y expresiones, además de la oportunidad de declarar variables en cualquier lugar
del programa. Entre las ventajas mas destacadas por los programadores de este nuevo lenguaje
es la mejora en el concepto de herencia, lo cual permite llevar la programación al nivel de la
programación orientada a objetos (POO)3 , de esta forma se conquista el terreno de la simulación
de eventos.
El éxito de C++ fue tal que el concepto de prototipos de funciones fue incluido en los diseños
posteriores de C. No obstante, muchas compañı́as a través de los años buscaron diseñar su propia
versión de C, lo cual dificultó el intercambio de información debido a las discrepancias que
pudieron surgir entre cada versión; esto llevo a la intervención de la ANSI (American National
Standars Institute) en 1983 para crear una estandarización del lenguaje C.
En el año 2000, Microsoft presenta .NET con el lanzamiento de una nueva extensión C#4
creado por Anders Hejlsberg, que servirá de lenguaje principal de la plataforma .NET. Este
nuevo programa resulta de combinar aspectos de C++ con Java, lo cual le permite llevar la
programación orientada a objetos a un nivel muy superior, ya que facilita la manipulación de
clases permitiendo que el programa en sı́ sea parte de una clase5 .
1
Este es el tipo de programación que se maneja en el curso
2
El nombre es debido a que la linea C++ en código denota un incremento en el valor asignado a la variable C
3
Este tema no es abarcado en el curso
4
C# es una extensión de C + +, de allı́ su nombre que es una abreviación de C++++
5
Este tema será tratado en el curso, veremos que una clase es un caso particular de los objetos
I
CAPÍTULO I
Generalidades
1. Lo primero es crear una carpeta en la cual guardar los programas, por ello crearemos
la carpeta “programas”, de este modo no tendremos problemas si no trabajamos todo el
tiempo en el mismo ordenador.
Para crear la carpeta iremos a la terminal (Aplicaciones→Accesorios→Terminal), donde
escribimos:
mkdir programas
1
I.1. ¿COMO CREO UN PROGRAMA? CAPÍTULO I. GENERALIDADES
#include <stdio.h>
int main()
{
printf(" hola ");
return 0;
}
cd programas
Esto nos permite ingresar a la carpeta programas, de este modo podemos trabajar sobre los
documentos en ella guardados. Para compilar introducimos alguna de las siguiente lı́neas.
Esto si nuestro programa se llama prog1.cpp, nótese que después de la instrucción “ -o.el
nombre del programa es colocado sin la extension (.cpp), esto es porque -o es la parte
del compilador encargada de nombrar el archivo ejecutable de nuestro programa, (por
supuesto el ejecutable puede tener cualquier nombre, por cuestiones de orden se sugiere
dejar el mismo nombre que tiene el documento).
2
I.2. TRABAJANDO CON DEV C++ CAPÍTULO I. GENERALIDADES
5. Después de compilado, debemos ejecutar el programa, de este modo el usuario podrá ver
la tarea que realiza el programa, recordemos que en Ubuntu lo ejecutables no se ejecutan
directamente, para ello en la terminal escribimos.
./prog1
Nota Si modificamos el código del programa, debemos guardar los cambios en el docu-
mento, luego ir a la terminal para compilar el programa, de este modo el sistema operativo
modifica el archivo ejecutable, y después ejecutamos el programa.
#include <stdio.h>
int main()
{
printf(" hola ");
return 0;
}
Una vez guardado, compilado y ejecutado, el programa parece no hacer nada, no obstante el
programa se ha ejecutado es solo que la ventana de ejecución se ha cerrado automaticamente.
Para evitar este inconveniente, debemos agregar la librerı́a stdlib.h la cual contiene el comando
system(”PAUSE”), que permite al programa hacer una pausa antes de cerrar automaticamente
el resultado del ejecutable. Luego, nuestro código se convierte en:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf(" hola ");
system("PAUSE");
return 0;
}
3
I.3. ¿COMO ESCRIBO UN PROGRAMA? CAPÍTULO I. GENERALIDADES
#include <stdio.h>
int main()
{
printf(" hola ");
return 0;
}
La primera lı́nea es quizás la mas rara de todas, pero no debemos preocuparnos es solo
la declaración de una librerı́a. Las librerı́as o bibliotecas son archivos (de extensión .h)
que contienen un conjunto de funciones que pueden ser aplicadas en la construcción de un
programa.
En este caso se utiliza la librerı́a stdio.h ya que contiene el comando printf que será utilizado
durante el programa; esta librerı́a es conocida como la librerı́a estándar y será utilizada a
lo largo del curso. Si el programa anterior no incluye la declaración de la librerı́a stdio.h,
mostrará un error de compilación ya que se intenta acceder al comando printf sin haber
enunciado la librerı́a que le contiene, en pocas palabras la librerı́a es un baúl lleno de
funciones a las cuales podemos acceder solo si el baúl se encuentra abierto.
printf es un comando especial que nos permite emitir mensajes en la pantalla del programa.
Debido a la naturaleza de la función int main() debemos regresarle algún numero entero,
en particular le regresamos 0, por ello aparece la lı́nea return 0;
I.4. Variables
Los lenguajes de programación, en particular C, nos permiten utilizar parte de la memoria del
computador para almacenar datos, una variable será una porcion de memoria que se identifica
con un nombre en particular; cabe destacar que el valor de la variable (valor almacenado en la
memoria) puede modificarse a lo largo del programa.
Por supuesto, es de esperar que existan diversos tipos de variable que se pueden utilizar para cada
tarea a realizar. A continuación se presentan algunos tipos de variable y sus correspondientes
extensiones.
4
I.4. VARIABLES CAPÍTULO I. GENERALIDADES
int a,b;
double c;
float z;
Nota El lenguaje permite declarar varias variables del mismo tipo en la misma lı́nea.
Los nombres de las variables deben ser escogidos de tal manera que permitan determinar fácil-
mente su utilidad en el programa; por ejemplo, si hablamos de un multiplicador de Lagrange
conviene más un nombre de variable lambda y no algo como a o b. Además es recomendable no
utilizar nombres reservados para una variable, por ejemplo:
int int;
double double;
float float;
En este caso el nombre de la variable es el mismo nombre del tipo de variable, lo cual puede
generar algo de confusion en el compilador. Por ejemplo, nombres como
int printf;
double scanf;
int x;
x=5;
Será la forma correcta de hacer que la variable x tome el valor 5. Mientras la instrucción
x=5;
También podemos utilizar operaciones aritméticas para dar valores a nuevas variables a partir
de valores dados. Por ejemplo, la secuencia de instrucciones
5
I.5. COMANDOS ÚTILES DE LA LIBRERÍA STDIO.H CAPÍTULO I. GENERALIDADES
int x,y,suma;
x=5;
y=6;
suma=x+y;
Asigna espacio para 3 variables enteras, dos de las cuales (x,y) toman valores, la tercera toma
valor a partir de las demás. Ası́ la asignación de valores x = 5, y = 6 nos permite obtener una
nueva variable en la cual se almacena la adición de los valores anteriores, dicha variable se llama
suma. La siguiente secuencia de instrucciones es equivalente
int x=5,y=6,suma;
suma=x+y;
Pues nuestro lenguaje de programación nos permite asignar valores a las variables incluso cuando
se están declarando. No obstante, la siguiente secuencia es erronea:
int x=5,y,suma;
suma=x+y;
Ya que si bien hemos almacenado espacio en memoria para todas las variables a utilizar, la
asignación de valor sobre la variable suma depende de los valores almacenados en x,y, sin
embargo la variable y no posee un valor almacenado, razón por la cual nuestro programa no
producira los resultados deseados.
Hasta el momento, los valores de las variables han sido asignados dentro del programa, pero
no es la única manera de hacerlo, de hecho el objetivo es que el usuario del programa pueda
modificar los valores de las variables a utilizar, para ello hablaremos un poco de las ventajas del
uso de la librerı́a stdio.h.
El comando printf nos permite publicar el valor asignado a alguna variable, esto se hace usando
la siguiente lı́nea de código.
6
I.5. COMANDOS ÚTILES DE LA LIBRERÍA STDIO.H CAPÍTULO I. GENERALIDADES
En este caso la variable a es entero, si fuese double debemos cambiar la asignación por %lf.
Debemos tener muy en cuenta las asignaciones para int y double, ya que son las que mas
trabajaremos a lo largo del curso. Podemos publicar varias variables en el mismo printf.
Cabe destacar que la primer asignación de extensión de variable que aparece corresponde a la
primera variable en aparecer después de las comillas, el segundo código de extensión corresponde
a la segunda variable y ası́ sucesivamente. En este caso %d corresponde a la variable r por tanto
el radio es entero, mientras %lf corresponde al area representado por la variable A, de donde se
concluye que el area es un número real.
CODIGO FUNCION
\n cambio de interlinea
\t Tabulación horizontal
\v Tabulación vertical
\’ comilla
\a Alerta de error
I.5.2. scanf
Este comando de la librerı́a stdio.h permite reconocer variables y asignarle un valor en especifico,
por ejemplo, si le pedimos al usuario digitar un número, scanf lo identificara y asignara este
numero a una variable, para ası́ poder ser trabajado en el programa, la semántica es:
scanf(“Tipo de Variable”,&Variable);
Un ejemplo serı́a:
scanf("%d",&a);
En la primera parte, entre las comillas vemos el código de asignación %d, esto permite que
de antemano sepamos que la variable es tipo entero, sin embargo vemos que el nombre de la
variable es acompañado del signo &; esto se conoce como paso por referencia, en pocas palabras,
el compilador asigna el valor numérico a la variable, en este caso a.
Ejemplo 3 Como le digo al usuario que digite un número entero para que este sea usado en el
programa?
7
I.5. COMANDOS ÚTILES DE LA LIBRERÍA STDIO.H CAPÍTULO I. GENERALIDADES
int a;
printf("Digite un numero entero");
scanf("%d",&a);
Esta lı́nea hace que al usuario en pantalla le aparezca el letrero “ digite un numero ”, el programa
se detiene hasta que el usuario introduzca un numero y luego pulse Enter.
Si pedimos dos números al usuario, tendremos que escribir dos veces el scanf asignándolo a
variables distintas, claro esta solo por buena presentación del programa.
Nota En el ejemplo anterior se le dijo al usuario que digite un numero entero, sin embargo
nada garantiza que el nos digite un número de otra naturaleza, más adelante veremos como
evitar problemas de este tipo.
Ejemplo 4 Como le digo al usuario que digite un número entero para que este sea usado en el
programa, y además mostrarle al usuario cual fue el número que el nos dio para verificarlo?
int a;
printf("Digite un numero entero");
scanf("%d",&a);
printf("El numero digitado fue %d",a);
Nota No sobra destacar que en el printf la variable no va acompañada de &, ya que estamos
publicando su valor pero no lo estamos modificando
Ejemplo 5 Como le digo al usuario que digite dos números enteros para que estos sean usados
en el programa, y además mostrarle al usuario los números que el digito para verificarlos?
OPCION 1
int a,b;
printf("Digite dos numeros enteros");
scanf("%d%d",&a,&b);
printf("Los numeros digitados fueron. %d \t %d",a,b);
OPCION 2
int a,b;
printf("Digite el primer numero");
scanf("%d",&a);
printf("Digite el segundo numero");
scanf("%d",&a);
printf("Los numeros digitados fueron. %d \t %d",a,b);
8
I.6. ALGUNOS COMANDOS IMPORTANTES CAPÍTULO I. GENERALIDADES
Los dos programas realizan la misma labor, e incluso muestran el mismo resultado al usuario.
La diferencia radica en las necesidades del programador. Si el programador desea escribir lo
menos posible usará la opción 1, sin embargo si el programador desea trabajar de manera mas
ordenada y estructurada utilizará la opción 2.
Nota Personalmente, considero mejor la opcion 2 ya que es mucho más clara, además
permite reutilizar el código como será visto más adelante.
x∗ = i equivale a x=x∗i
x+ = i equivale a x=x+i
x/ = i equivale a x = x/i
i++ equivale a i=i+1
i−− equivale a i=i−1
I.6.2. //
Este comando permite escribir un comentario de una lı́nea, los comentarios son ignorados por
el compilador, pero están a la vista en el código del programa, son útiles si queremos colocar
nuestro nombre en cada programa, o para recordar la utilidad de las variables, etc.
9
I.6. ALGUNOS COMANDOS IMPORTANTES CAPÍTULO I. GENERALIDADES
I.6.3. /* */
Los comandos /* , */ hacen que todo lo que se encuentre en su interior sea un comentario, de
este modo podemos ignorar un conjunto de lı́neas completa, su uso mas común es para que el
programador introduzca una explicación detallada acerca del funcionamiento del programa.
#include<stdio.h>
#include<math.h>
/*
Esta linea de comandos nos permite hallar el area y la longitud de una circunferencia,
el usuario debe digitar el radio para que el programa trabaje.
Cabe destacar que pi es una constante que el programa C reconoce ya que se encuentra
definida en la librerı́a math.h
*/
int main()
{
double l,a,r;
printf("Digite el valor del radio de la circunferencia ");
scanf("%lf",&r);
l=2*pi*r; // calcula la longitud de la circunferencia
a=pi*(r*r);
printf("\n La longitud de la circunferencia es: %lf \n",l);
printf(" El area de la circunferencia es: %lf \n \n",a);
return 0;
}
10
CAPÍTULO II
ESTRUCTURAS DE CONTROL
II.1. CONDICIONAL
II.1.1. if
Las sentencias del tipo condicional son las mismas que se han analizado en los cursos preliminares,
como el de fundamentos. Por ejemplo si llueve no saldré de casa; esta sentencia tiene como
condición la aparación de la lluvia, la consecuencia serı́a la no salida de casa.
Nota Cabe destacar que en la frase del ejemplo, si no salgo de la casa no implica que este
lloviendo.
Este tipo de sentencias se manejan con el operador condicional if. la semántica de este operador
es:
if (condición)
{
sentencia 1;
sentencia 2;
..
.
sentencia n;
}
11
II.1. CONDICIONAL CAPÍTULO II. ESTRUCTURAS DE CONTROL
#include <stdio.h>
int main()
{
int a;
a=0;
if(a<0)
{
printf("a es negativo");
}
if(a>0)
{
printf("a es positivo");
}
return 0;
}
Debido a que en el programa a = 0, las condiciones a < 0 y a > 0 no se satisfacen, por esta
razón el compilador pasa automáticamente a la lı́nea return 0;.
• if else
Es útil en ocasiones contar con una ejecución en caso de que la condición inicial no se satisfaga.
La semántica es la siguiente
if (condición)
{
sentencia 1;
..
.
sentencia n;
}
else
{
sentencia n + 1;
..
.
12
II.1. CONDICIONAL CAPÍTULO II. ESTRUCTURAS DE CONTROL
sentencia n + m;
}
• if anidados
Las sentencias if pueden incluir otros if dentro de sus sentencias, por esta razón se les conoce
como anidados. Un ejemplo concreto serı́an las lı́neas
if (a >= b)
{
if (b != 0)
c = a/b;
}
Vemos que la primer condición dice a ≥ b, para poder efectuar una division de tal modo que el
resultado sea mayor que 1, sin embargo para poder dividir se requiere que el denominador sea
distinto de cero, es decir b 6= 0.
Nota Si una estructura de control cuenta con una sola sentencia en su interior no es
necesario colocar los corchetes { , } ya que el compilador ejecutara únicamente la lı́nea inmedi-
atamente siguiente a la aparición de la estructura de control.
Claramente esta linea de comandos se puede escribir mucho mas fácilmente como:
Podemos también decir que avise al usuario cuando b sea nulo, para ello colocamos
if (b==0)
printf("b es negativo, por ello no se puede efectuar la division");
13
II.1. CONDICIONAL CAPÍTULO II. ESTRUCTURAS DE CONTROL
II.1.2. Switch
La familia de las condicionales se extiende con la sentencia switch, ya que nos permite múltiples
ramificaciones manipuladas desde una única estructura. La semántica de la sentencia switch es
la siguiente:
switch (expresión)
{
case 1:
sentencia 1;
..
.
sentencia n;
break;
case 2:
sentencia 12 ;
..
.
sentencia p2 ;
break;
case 3:
..
.
case m:
sentencia 1m ;
..
.
sentencia rm ;
break;
}
El funcionamiento es similar a las sentencias if else, se ingresa en la expresión del switch (nor-
malmente es una variable), se mira si toma los valores descritos en cada caso, si toma el valor
asignado en algún caso entonces entra a realizar la familia de sentencias en el consignadas.
Nota El comando break hace que se salga del case, con lo cual la estructura condicional
se cumple.
Esto queda mucho mas claro en un ejemplo.
Ejemplo 9 El usuario tiene un programa que le determina el numero de dias que tiene cada
mes, para ello el programador le diseño un programa de tal modo que a cada mes le corresponde
un numero asignado por el orden de aparición en el año
switch (mes)
{
case 1: //Enero
No-dias=31;
break;
14
II.2. BUCLES O CICLOS CAPÍTULO II. ESTRUCTURAS DE CONTROL
case 2: //Febrero
No-dias=28 //año no bisiesto
break;
..
.
case 12: //Diciembre
No-dias=31;
break;
default:
printf(“El año tiene 12 meses en el calendario que manejamos”);
break;
}
Nota El comando default considera todos los valores posibles no consignados en los valores
constantes que toma cada case.
Nota En ausencia del comando default, el programa funciona similar salvo que en caso
de digitar un numero no correspondiente a algún mes, el programa continua en la lı́nea siguiente
al } que concluye el switch.
int i;
for(i=1; i<=5; i++)
{
printf("El valor de i es %d \n",i);
}
El valor de i es 1
El valor de i es 2
El valor de i es 3
El valor de i es 4
El valor de i es 5
15
II.2. BUCLES O CICLOS CAPÍTULO II. ESTRUCTURAS DE CONTROL
for (i = 1; 1 <= n; i + +)
Es fácil darnos cuenta que el ciclo serı́a infinito ya que i toma los valores 1, 2, · · · , n, · · · pero la
condición de control 1 <= n siempre sera cierta, por tanto el ciclo no finalizara.
II.2.2. while
Esta sentencia es muy versátil ya que permite ejecutar repetidamente un bloque de sentencias,
mientras se satisfaga una condición definida en su encabezado. La semántica es la siguiente:
while(condición de control)
{
instruccion 1;
instruccion 2;
..
.
instruccion n;
}
Este manejo de los ciclos es bastante útil para construir menus, ya que si el usuario digita
un numero que no corresponde al deseado, no es necesario sacarlo del programa para volverle
a mostrar las instrucciones, es cuestión de colocar en la condición los posibles numeros que
tenemos, si el numero digitado no coincide con ellos debemos mostrar el menu.
Sin embargo, se constituye en un arma de doble filo ya que si se coloca una expresión tautológica
en la condición de control, el ciclo no para de ejecutarse, por ejemplo un encabezado con una
16
II.2. BUCLES O CICLOS CAPÍTULO II. ESTRUCTURAS DE CONTROL
condición como while(1 < 2). Esto es debido a que 1 < 2 se cumple sin importar lo que
realicemos.
Otro problema es cuando dejamos la condición a cargo de una constante que no se modifica.
int i=1;
while(i<=3)
{
printf("El valor de i es %d \n",i);
printf("Veamos que sucede \n");
}
Es claro que i no modifica su valor, por tanto el ciclo se ejecutara siempre ya que la condición
de control será verdadera todo el tiempo. La forma correcta serı́a escribir
int i=1;
while(i<=3)
{
printf("El valor de i es %d \n",i);
printf("Veamos que sucede \n");
i++
}
De este modo al mostrar los dos letreros al usuario el valor de i se incrementa, lo cual garantiza
que en algún momento i deje de ser menor o igual a 3, por tanto la condición de control será falsa
después de dos iteraciones.
Nota Los encabezados de las estructuras de control no llevan ; ya que son funciones espe-
ciales del programa que se ejecutan, mas no son sentencias a realizar.
17
CAPÍTULO III
FUNCIONES
Una función en lenguaje C puede ser entendida como un bloque de instrucciones encargados de
realizar un proceso. El uso de funciones nos permite convertir programas de gran tamaño, en
bloques de código más ordenados y manejables.
Dividir un programa en un conjunto de funciones nos permite además reducir el tiempo de
ejecución de los programas, ya que una función (o rutina) puede ser utilizada muchas veces en
un programa sin incrementar excesivamente el número de lı́neas de código, reduciendo ası́ la
probabilidad de cometer errores en los programas.
El manejo de un programa en el lenguaje C es realizado a partir de funciones, ya que el main
es también una función, en nuestro caso de naturaleza entera ya que se enuncia int main(). A
continuación se presenta la forma general de una función.
En pocas palabras, deben ser definidas con: un tipo que nos permite identificar si la función
regresa un valor y si es ası́ de que tipo es dicho valor; un nombre que nos permite realizar
llamados en la función main; una lista de parámetros a los cuales daremos valores para realizar
el proceso modelado en el cuerpo de la función (el cuerpo es una cadena de instrucciones).
18
III.2. CONSTRUCCIÓN DE FUNCIONES CAPÍTULO III. FUNCIONES
Entre las funciones del primer tipo (que retornan valor) tendremos un tipo de función por cada
tipo de variable existente. En particular tendremos:
También existiran funciones long int, char, . . . . Lo importante a tener en cuenta es que el tipo
de función debe coincidir con el tipo de variable que la función retorna.
Nota int main() es una función de tipo int de nombre main y sin parámetros. Por ser de
naturaleza entera, requiere que se retorne un valor entero, de allı́ la razón por la cual se ubica la
lı́nea de código return 0 (personalmente uso 0 o 1 para retornar, pero puede ser cualquier valor
entero).
Las funciones del segundo tipo (que no retornan valor) son conocidas como funciones vacı́as,
como no tienen tipo de variable asignado, son conocidas bajo el tipo de función void.
Nota Si las funciones son del primer tipo, requieren al final la instrucción return. Si son
del segundo tipo (void) no se debe ubicar return al final de la función.
2. Un nombre sencillo que permita identificar fácilmente la labor que desempeña la función
Ejemplo 12 Construir una función que permita saludar al usuario un número de veces deter-
minado.
19
III.2. CONSTRUCCIÓN DE FUNCIONES CAPÍTULO III. FUNCIONES
Esta función solo debe enviar un número de saludos que, posiblemente, sea digitado por el
usuario, por esa razón sabemos que el número de saludos es un parámetro, ya que no tenemos
un número fijo. Como la función solo envia saludos, no es necesario regresar ningún valor a la
función principal (main), por tanto la función es de tipo void
void saludo(int n)
{ //inicio de funcion
int i;
for (i=1;i<=n;i++)
{
printf("\nHOLA");
}
printf("\n\n");
} //Fin de la funcion
Ejemplo 13 Construir una función que permita calcular n!, para cualquier valor n.
Esta función tendrá como parámetro la variable n ya que el valor no es fijo y además puede ser
dado por el usuario. Posiblemente el resultado n! se requiera para ser utilizado en el programa,
por ello es mejor retornarlo; debido a que la función factorial funciona con números enteros,
podemos concluir que el tipo de función correspondiente será int (por supuesto, también podrı́a
ser long int)
int factorial(int n)
{
// funcion que calcula el factorial
int i,prod=1;
for (i=1;i<=n;i++)
{
prod=prod*i;
}
printf("\n\n (%d)!=%d\n\n",n,prod);
return prod;
}
20
III.3. PARÁMETROS CAPÍTULO III. FUNCIONES
III.3. Parámetros
Las funciones, hasta el momento nos han sido de utilidad para distribuir de una manera eficiente
nuestros programas. Para definir una funcion, debemos tener en cuenta las variables que se
requieren para que la funcion realice el proceso para el cual fue diseñada, entre ellas distinguiamos
algunas variables que se consideraban como parámetros. Sin embargo, durante el desarrollo de
la función, es posible que los parámetros modifiquen su valor, en dicho caso es de esperar que
al trabajar la función en el main, las variables utilizadas como parámetro hallan modificado su
valor debido a que han sido utilizadas en la función, pero esto no siempre ocurre.
#include<stdio.h>
int main()
{
double a,b;
lee(a);
lee2(b);
printf("a= %lf \t b=%lf \n\n",a,b);
return 0;
}
void lee(double x)
{
printf("Digite un valor\n");
scanf("%lf",&x);
}
//---------------------
Aparentemente las funciones lee y lee2 son equivalentes, sin embargo solo una de ellas realiza la
lectura del valor digitado por el usuario, la razón es que mientras una de las funciones considera
la variable que le es dada como parámetro, la otra considera una copia del parámetro.
21
III.4. DISTIBUCIÓN DE UN PROGRAMA CAPÍTULO III. FUNCIONES
void lee(double x)
{
printf("Digite un valor\n");
scanf("%lf",&x);
}
Tiene un parámetro que dentro de la función es identificado como x, el cual es pasado por valor,
es decir el compilador crea una copia del valor dado como parámetro y trabaja con ella. En el
caso de la función lee, que fue llamada en el main como lee(a), el valor del parámetro no se
modifica ya que se trabaja con una copia de la variable a (la original fue creada en el main()),
es decir una copia de la variable a es ingresada a la función y recibe el valor dado por el usuario,
mientras la variable a original no se usa.
Esto hace que al publicar el valor asignado a la variable a, no coincida con el valor dado por el
usuario, razón por la cual la lectura, pese a estar bien en términos semánticos, no se realiza.
Tiene un parámetro que dentro de la función es identificado como x, el cual es pasado por
referencia, es decir el compilador trabaja con el parámetro original. En el caso de la función
lee2, que fue llamada en el main como lee2(b), el valor del parámetro se modifica ya que se
trabaja con la variable b (creada en el main()), es decir la función se aplica sobre la variable b
que es ingresada a la función y recibe el valor dado por el usuario.
Esto hace que al publicar el valor asignado a la variable b, coincida con el valor dado por el
usuario.
Nota En C + + el paso por referencia es aplicado utilizando el sı́mbolo & sobre el parámetro.
Si se desea modificar el valor de algún parámetro, se le aplica paso por referencia; si no deseamos
modificar el valor de los parámetros entonces hacemos paso por valor.
22
III.4. DISTIBUCIÓN DE UN PROGRAMA CAPÍTULO III. FUNCIONES
factorial y saludo que construimos anteriormente, el cual puede ser escrito de dos maneras: El
código puede ser descrito ası́: :
MANERA I
→ Llamado de librerı́as
→ Prototipos de funciones1
#include<stdio.h>
#include<math.h>
//---------------------------
int main()
{
int x,y;
saludo(5); // llama a la funcion saludo con parametro 5
printf("\n\n");
x=factorial(5); // Calcula 5 factorial, y lo almacena en x.
y=factorial(6); // Calcula 6 factorial, y lo almacena en y.
return 0;
}
//----------------------------
for (i=1;i<=n;i++)
{
prod=prod*i;
}
1
El prototipo de una función es una instrucción que pemite al compilador saber que dicha función será creada.
Para construir el prototipo, solo debemos colocar el encabezado de la funcion(tipo,nombre y parámetros ) seguidos
de ;
23
III.4. DISTIBUCIÓN DE UN PROGRAMA CAPÍTULO III. FUNCIONES
printf("\n\n (%d)!=%d\n\n",n,prod);
return prod;
}
//----------------------------
// Funcion que imprime n letreros de saludo
void saludo(int n)
{ //inicio de funcion
int i;
for (i=1;i<=n;i++)
{
printf("\nHOLA");
}
} //Fin de funcion
MANERA II
→ Llamado de librerı́as
#include<stdio.h>
#include<math.h>
for (i=1;i<=n;i++)
{
prod=prod*i;
}
printf("\n\n (%d)!=%d\n\n",n,prod);
return prod;
}
//----------------------------
// Funcion que imprime n letreros de saludo
void saludo(int n)
{ //inicio de funcion
24
III.5. FUNCIONES RECURSIVAS CAPÍTULO III. FUNCIONES
int i;
for (i=1;i<=n;i++)
{
printf("\nHOLA");
}
} //Fin de funcion
//---------------------------
int main()
{
int x,y;
saludo(5); // llama a la funcion saludo con parametro 5
printf("\n\n");
x=factorial(5); // Calcula 5 factorial, y lo almacena en x.
y=factorial(6); // Calcula 6 factorial, y lo almacena en y.
return 0;
}
//----------------------------
Las dos formas de trabajar son equivalentes, no obstante la primera manera es más cómoda
para los programadores que vean nuestro código, ya que de antemano les permite conocer las
funciones que van a ser construidas, y ademas permiten tener a la vista la función main.
Ejemplo 14 Diseñar una función recursiva que permita obtener la sumatoria desde 1 hasta un
valor entero n dado como parámetro.
int suma(int n)
{
if(n<0)
{
printf("\n\nEl valor dado no es conveniente.\n\n");
return 0;
}
if(n==0) return n;
25
III.5. FUNCIONES RECURSIVAS CAPÍTULO III. FUNCIONES
suma(n) = n + suma(n − 1)
= n + [n − 1 + suma(n − 2)]
= n + (n − 1) + [n − 2 + suma(n − 3)]
= n + (n − 1) + · · · + 2 + suma(1)
= n + (n − 1) + · · · + 2 + 1 + suma(0)
suma(n) = n + (n − 1) + · · · + 2 + 1 + 0
n
X
suma(n) = i
i=1
int factorial(int n)
{
if(n<0)
{
printf("\n\nEl valor dado no es conveniente.\n\n");
return 0;
}
if(n==0 || n==1) return 1;
return n*factorial(n-1);
}
26
CAPÍTULO IV
AGRUPAMIENTO DE VARIABLES
IV.1. Arreglos
Los arreglos son un conjunto de variables, del mismo tipo, que se identifican bajo el mismo
nombre, para acceder a cada uno de los valores de las variables se utilizan ı́ndices consecutivos;
el ı́ndice más bajo corresponde al primer valor del arreglo y el ı́ndice más alto corresponde al
último ı́ndice del arreglo. Los arreglos son de gran utilidad cuando se desean agrupar variables
del mismo tipo.
Matemáticamente los arreglos pueden ser vistos como vectores, es decir, n-uplas de valores a los
cuales se accede por un indice. Por ejemplo:
X[0] = 1
X[1] = 12
X[2] = 15
X[3] = 6
Nota En C++ los ı́ndices inician desde 0 ya que este ı́ndice denota la posición inicial en
memoria del arreglo.
Cabe destacar que los arreglos, pese a componerse de variables del mismo tipo, deben declararse
de una manera especial ya que el compilador debe asignar el espacio correspondiente en memoria;
para realizar la declaración, debemos tener en cuenta:
27
IV.2. CADENAS DE CARACTERES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
La semántica es la siguiente
Tipo nombre[tamaño]
double vector[50];
El arreglo anterior contiene 50 variables tipo double, y las identifica bajo el nombre vector. Para
darle valor a las componentes del arreglo, se hace accediendo a los ı́ndices de la siguiente manera:
vector[0] = 10
vector[1] = 10
vector[2] = 20
vector[3] = 30
..
.vector[49] = 319
Nota No sobra recordar que los ı́ndices del arreglo para el usuario van de 1 hasta n, mientras
para el programa los ı́ndices van de 0 hasta n − 1.
N[0]&=’M’\\
N[1]&=’a’\\
N[2]&=’r’\\
N[3]&=’i’
N[4]&=’a’
28
IV.2. CADENAS DE CARACTERES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
Debemos tener en cuenta que para poder utilizar de manera adecuada las cadenas de caracteres,
debemos limitar el tamaño del arreglo que la contiene ya que de no hacerlo desbordariamos la
memoria del computador. En el caso que requiramos el nombre del usuario, serı́a pésima idea
pedirle que digite el tamaño del arreglo (en este caso el número de letras que componen su
nombre), por esta razón es mejor crear un arreglo de dimensión fija, pero lo suficientemente
grande para que el usuario no utilice más caracteres de los esperados por el arreglo.
La función gets() se encarga de reconocer la cadena de caracteres dada por el usuario, por
supuesto puede ocurrir que el nombre dado tenga menos de 80 caracteres, no obstante el com-
pilador al guardar la cadena en el arreglo solo ocupara las casillas necesarias, las demás tendrán
un señalador que indica al compilador que estas no contienen información razón por la cual, no
se muestran al publicar la cadena.
Nota Un char tiene extensión %c, una cadena de caracteres tiene extensió %s (tipo string).
Sin embargo, las demás casillas c[6], · · · ,c[79] tendrán el valor ’\0’, el cual indica el final de la
cadena. En pocas palabras, como c[6]=’\0’, tenemos que la cadena finaliza en c[5].
Ejemplo 18 Construir una funcion que permita saber si el nombre del usuario requiere mas de
n caracteres (n dado).
29
IV.3. APUNTADORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
IV.3. apuntadores
Los apuntadores son variables en las cuales se almacena la dirección en memoria que ocupa
alguna variable. Para poder visualizar con mayor facilidad la relación entre el apuntador y el
arreglo, debemos decir que el nombre del arreglo es en realidad un apuntador que apunta a la
primera componente del arreglo. Para ello tomemos la siguiente declaración:
double X[10];
Si extraigo el valor que esta contenido en la dirección en la cual se ubica el arreglo X, es decir
utilizo la instrucción
double p=*X;
#include<stdio.h>
#include<stdlib.h>
int main()
{
double X[3];
X[0]=5;
X[1]=7;
X[2]=11;
30
IV.3. APUNTADORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
Nota Recuerde que la dirección en memoria esta en formato hexadecimal, o base 16 (la
extensión %p especial para apuntadores, permite visualizarlo)
Ahora que sabemos que el arreglo es un puntero a la primera posición, se puede decir que el
identificador (nombre del arreglo) nos permite indexar componentes en el apuntador de manera
analoga a como se hace en el arreglo. Es decir, solo debemos cambiar la declaración de arreglo,
a declaración de apuntador en nuestros programas.
En este momento, cabe una pregunta, ¿como limito el tamaño de un vector si lo declaro como
apuntador?.
Para dar respuesta a este interrogante debemos hablar de asignación de memoria.
No obstante, solo una de ellas es la forma correcta de trabajar, y es desde luego la segunda.
Cuando creamos un vector y no utilizamos toda su capacidad, estamos desperdiciando la memo-
ria del computador ya que se ocupa en algo que no será de utilidad, por supuesto, esta mala
práctica nos lleva a los errores de desbordamiento1 .
Con el fin de optimizar los recursos de memoria el lenguaje C++ nos permite asignar la memoria
estrictamente necesaria para realizar nuestras labores, para ello nos brinda el comando new con
el cual declaramos el número de variables que contendrá nuestro arreglo. La declaración de un
arreglo via apuntador se hará de la siguiente manera:
double *X;
X=new double[10];
La primera lı́nea nos permite apuntar a X, mientras la segunda lı́nea nos permite definir el
número de componentes de los cuales dispondremos en nuestro arreglo. En este caso, como el
número de componentes del arreglo es fijo, diremos que se realiza asignación estática de
memoria.
double *X;
X=new double[n];
Donde n es dado por el usuario, diremos que se realiza asignación dinámica de memoria,
ya que la asignación de memoria se realiza durante la ejecucuión del programa.
1
Como el lector habrá observado, son errores muy frecuentes al iniciarse en el mundo de los arreglos, además
que no son fáciles de localizar en el programa
31
IV.4. ARREGLOS EN FUNCIONES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
delete X;
La combinación new, delete, nos permite controlar de manera eficiente la memoria, ya que
utilizamos la cantidad estricta y la liberamos una vez no sea necesaria.
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Digite el tama~
no del arreglo\n\n");
scanf("%d",&n);
double X[n];
lectura(X,n);
escritura(X,n);
system("PAUSE");
return 0;
}
//----------------------------
2
En términos generales, new es un constructor de objetos, mientras delete es un destructor
3
Estos serán estudiados más adelante
32
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
}
}
IV.5. Vectores
Los arreglos, matemáticamente, pueden ser vistos como vectores que almacenan información,
por esta razón es natural pensar en construir un programa que permita reconocer vectores y
aplicar operaciones básicas sobre ellos.
Ejemplo 19 Diseñar un programa que permita al usuario digitar dos vectores, y le permita
aplicar sobre ellos:
Suma
Resta
Producto Punto
Producto Vectorial
33
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
El programa siguiente fue escrito en DEV-C++4 , la razón es la inclusión de las pausas utilizando
el comando system. Este programa funciona también en Ubuntu.
El programa funciona con arreglos
void presentacion();
int menu();
void lectura(int n, double X[]);
void escritura(int n, double X[]);
void suma(int n, double X[],double Y[], double suma[]);
void resta(int n, double X[],double Y[], double resta[]);
double productopunto(int n, double X[],double Y[]);
void productovectorial(int n, double X[],double Y[],double cruz[]);
//-----------------------------------------------------------------------------
int main()
{
presentacion();
//---inicio del programa
int m,n,k;
printf("\nDigite la longitud del primer vector: ");
scanf("%d",&n);
printf("\nDigite la longitud del segundo vector: ");
scanf("%d",&m);
if(n!=m)
{
printf("\nLOS VECTORES DEBEN TENER LA MISMA LONGITUD\n");
system("PAUSE");
return 0;
}
double A[n],B[m];
printf("\nDigite los datos del primer vector: \n");
lectura(n,A); //Lectura de los datos del vector A
printf("\n\n El vector es:\n\n");
escritura(n,A);
4
Se programo en DEV-C++ para que el lector que trabaje bajo el sistema operativo Windows no tenga
problemas de cierre automático de pantalla
34
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
printf("\n\n");
printf("\nDigite los datos del segundo vector: \n");
lectura(m,B); //Lectura de los datos del vector B
printf("\n\n El vector es:\n\n");
escritura(m,B);
printf("\n\n");
k=menu();
if(k==1)
{
double producto;
producto=productopunto(n,A,B);
printf("< ");
escritura(n,A);
printf(" , ");
escritura(m,B);
printf(" >");
printf("=%lf",producto);
printf("\n\n");
system("PAUSE");
return 0;
}
if(k==2)
{
double sum[n];
suma(n,A,B,sum);
escritura(n,A);
printf(" + ");
escritura(n,B);
printf(" = ");
escritura(n,sum);
printf("\n\n");
system("PAUSE");
return 0;
}
if(k==3)
{
double res[n];
resta(n,A,B,res);
escritura(n,A);
printf(" - ");
escritura(n,B);
printf(" = ");
35
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
escritura(n,res);
printf("\n\n");
system("PAUSE");
return 0;
}
if(k==4)
{
if(m!=3 || n!=3)
{
printf("\nLos vectores deben tener dimension 3\n\n");
system("PAUSE");
return 0;
}
double Z[3];
productovectorial(n,A,B,Z);
escritura(n,A);
printf(" X ");
escritura(n,B);
printf(" = ");
escritura(n,Z);
}
printf("\n\n");
system("PAUSE");
return 1;
}
//============================================================
void presentacion()
{
printf("\n *****************************************************************\n");
printf("Este programa requiere dos vectores de la misma dimension.\n");
printf("Como resultado podemos obtener las operaciones basicas de vectores, \n");
printf("aplicadas sobre dichos vectores. Las posibles operaciones son:\n");
printf(" * Suma\n * Resta \n * Producto Punto\n * Producto Vectorial");
printf("\n *****************************************************************\n");
}
//============================================================
int menu()
{
int k=5;
double k2;
while(k!=1 && k!=2 && k!=3 && k!=4)
36
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
{
printf("\n------------------MENU------------------\n");
printf("\n -> Digite 1 si quiere calcular <A,B>");
printf("\n -> Digite 2 si quiere calcular A+B");
printf("\n -> Digite 3 si quiere calcular A-B");
printf("\n -> Digite 4 si quiere calcular A X B");
printf("\n----------------------------------------\n");
scanf("%lf",&k2);
k=(int)k2;
if(k!=k2) k=5; //Si el usuario no digita un numero entero, continua en el menu
}
return k;
}
//============================================================
void lectura(int n, double X[])
{
//Funcion que lee los datos dados por el usuario en la terminal
int i;
for (i=1;i<=n;i++)
{
printf("digite la componente [%d]",i);
scanf("%lf",&X[i-1]);
}
}
//============================================================
void escritura(int n, double X[])
{
// Funcion que escribe los datos dados por el usuario como vector.
int i;
printf("(");
for (i=1;i<n;i++)
{
printf("%lf,",X[i-1]);
}
printf("%lf)",X[n-1]);
}
//============================================================
void suma(int n, double X[],double Y[],double suma[])
{
//Suma de dos vectores X,Y. El resultado se almacena en un vector llamado suma
int i;
for (i=1;i<=n;i++)
{
suma[i-1]=X[i-1]+Y[i-1];
37
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
}
}
//============================================================
void resta(int n, double X[],double Y[],double diferencia[])
{
//Resta de dos vectores X,Y. El resultado se almacena en un vector llamado diferencia
int i;
for (i=1;i<=n;i++)
{
diferencia[i-1]=X[i-1]-Y[i-1];
}
}
//============================================================
double productopunto(int n, double X[],double Y[])
{
//Producto punto de X,Y (<X,Y>). El resultado es un escalar llamado Prod
int i;
double Prod=0;
for (i=1;i<=n;i++)
{
Prod+=X[i-1]*Y[i-1];
}
return Prod;
}
//============================================================
void productovectorial(int n, double X[],double Y[],double cruz[])
{
//Producto vectorial, permite construir un vector que es ortogonal a X, Y a la vez
//la construccion no es la mejor, pero de momento funciona.
//Esta definicion solo funciona para vectores de tama~
no 3.
cruz[0]= X[1]*Y[2]-X[2]*Y[1];
cruz[1]=-(X[0]*Y[2]-X[2]*Y[0]);
cruz[2]= X[0]*Y[1]-X[1]*Y[0];
}
El programa anterior incluye algunos controles sobre el menu. No obstante, el lector como
ejercicio puede modificar el programa de tal manera que permita al usuario calcular nuevamente
operaciones sin tener que salir de la ventana de ejecución, claro esta permitiendo al usuario salir
de la ventana de ejecución, además de controlar que el usuario no digite caracteres cuando debe
digitar numeros.
La declaración de los vectores se hizo vı́a arreglos, el lector puede modificar el programa de tal
manera que la declaración se haga con apuntadores.
38
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
Ejemplo 20 Diseñar un programa que permita al usuario digitar un conjunto de datos, y que
le de la opcion de calcular:
Media
Varianza
Desviación estandar
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main()
{
int n;
printf("Digite el numero de datos");
scanf("%d",&n);
double a,desv,var;
//-----
double *X; //declaracion
X=new double[n]; //asignacion de memoria
if(X==NULL)
{
printf("\nLa memoria es insuficiente\n");
system("PAUSE");
return 0;
}
//-----
lectura(X,n);
escritura(X,n);
a=media(X,n);
printf("\n\n LA MEDIA ES: %lf\n\n",a);
var=varianza(X,n);
39
IV.5. VECTORES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
//============================================================
double varianza(double *X,int n)
{
double suma=0.0;
double mid,d;
mid=media(X,n);
for(int i=1;i<=n;i++) suma+=(mid -X[i-1])*(mid -X[i-1]);
d=suma/n;
return d;
}
//============================================================
double media(double X[],int n)
{
double suma,mid;
suma=0.0;
for(int i=1;i<=n;i++)
{
suma+=X[i-1];
}
mid=suma/n;
return mid;
}
//============================================================
void lectura(double *X,int m)
{
for (int i=1;i<=m;i++)
{
printf("\nX[%d]= ",i);
scanf("%lf",&X[i-1]); //Almacenamiento en cada posicion.
}
}
//============================================================
void escritura(double *X,int m)
{
for (int i=1;i<=m;i++)
{
printf("\nX[%d]= %lf ",i,X[i-1]);
40
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
}
}
El programa anterior funciona, pero esta escrito de una manera poco agradable. Queda como
ejercicio al lector modificar el programa de tal manera que de todas las comodidades al usuario,
además de controlar que el usuario digite datos que no se puedan reconocer.
Nota En la función main se observa la comparación X==NULL, esto indica si el apuntador
es nulo, en cuyo caso no habrá espacio disponible en memoria para almacenar el arreglo
IV.6. Matrices
IV.6.1. Arreglos bidimensionales
En términos de programación, las matrices pueden ser vistas como arreglos bidimensionales, es
decir arreglos cuyas componentes a su vez son arreglos.
El concepto de arreglo bidimensional nos permite poder movernos en dos direcciones indepen-
dientemente (filas y columnas) lo cual resulta ventajoso a la hora de escribir los programas, ya
que se pueden analizar con mayor facilidad. En el caso de declaración via arreglos el manejo es
similar, solo se debe tener en cuenta el número de componentes del arreglo de arreglos, es decir,
el número de filas y columnas que debe tener nuestra matriz; veamos la siguiente declaración:
double X[5][5];
Esta instrucción reserva espacio en memoria para recibir 5 × 5 elementos tipo double, de este
modo hemos podemos construir la siguiente matriz:
X[2][4]=5;
De este modo podemos dar valores a cada una de las componentes de la matriz, no obstante, lo
ideal serı́a darle al usuario la opcion de digitar los valores de cada término de la matriz, para
ello se procede como lo hemos hecho antes, solo que esta vez se trabaja de esta forma
scanf("%lf",&X[i][j]);
41
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
Puesto que X[i][j] es una variable tipo double, claro esta, este proceso se debe hacer para 0 ≤
i, j ≤ 4.
Sin embargo, para el trabajo desde funciones se recomienda el uso de los apuntadores ya que
la declaración ilimitada double X[][] no puede ser utilizada como parámetro en una función, el
paso como parámetro requiere que sea de una manera restringida, es decir con un número de
columnas fijo.
Ejemplo 21 Construir una función de lectura y una de escritura para matrices con 10 colum-
nas.
//----------------------------------------------------------
void escrituraMatriz(double X[][10], int m, int n)
{
for(int i =0;i<m; i++)
{
for(int j=0; j<n; j++) printf("%lf\t",X[i][j]);
printf("\n");
}
printf("\n\n");
}
Claro esta, solo podemos trabajar matrices que tengan 10 columnas, si quisieramos trabajar
matrices con 20 columnas tendrı́amos que diseñar una funciones especı́ficas para matrices de 20
columnas; este inconveniente hace que los arreglos bidimensionales sean la peor opcion a la hora
de trabajar con matrices, ya que no ofrecen al usuario la oportunidad de decidir el tamaño que
tendrán las matrices que desea construir. La mejor opcion para dicha tarea son los apuntadores.
42
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
Esta idea, desde el punto de vista matemático es muy razonable, no obstante desde el punto
de vista de ingenierı́a no es tan simple. Recordemos que un apuntador contiene la dirección de
la variable a la que apunta, mientras que en un apuntador a apuntador, el primer apuntador
contiene la dirección del segundo apuntador el cual apunta a la variable que tiene el valor que
buscamos.
Debemos recordar que la construcción de arreglos via apuntador no nos permite inicializar
mientras declaramos, es decir, no podemos definir el tamaño del arreglo en el momento de
declarar el apuntador, requerimos del comando new para poder realizar dicha labor ya que la
asignación de memoria se debe realizar de manera dinámica, de otro modo el usuario no podrı́a
decidir el tamaño de la matriz que desea trabajar
Ejemplo 22 Construir una función que permita declarar una matriz de tamaño m × n
Por supuesto, la función se puede construir tipo void, sin embargo se opta por trabajar con
retorno para ası́ mostrar un ejemplo de la manera en que se retornan variables puntero.
43
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
Ejemplo 23 Construir una función que permita construir la matriz identidad de cualquier
tamaño (la matriz identidad es una matriz de ceros con unos en la diagonal)
Ejemplo 24 Diseñar una función que retorne 0 si dos matrices dadas son distintas, 1 si las
dos matrices dadas son iguales
cabe destacar que dos matrices son iguales si y solo si todas sus componentes son iguales. Por
esta razón basta con que difieran en solo un término para que concluyamos que las dos matrices
son diferentes.
Sumar matrices
Restar matrices
Multiplicar matrices
44
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
#include<stdio.h>
#include<stdlib.h>
int main()
{
int opcion=0;
while(opcion<1 || opcion>4)
{
presentacion(opcion); //menu que funciona solo con opciones entre 1 y 4
}
if(opcion==1)
{
double **A,**B,**SUM;
int m,n,p,q;
A=construyeMatriz(m,n);
B=construyeMatriz(p,q);
if(m!=p || n!=q)
{
printf("\n ERROR:La dimension de las matrices impide la operacion\n\n");
system("PAUSE");
return 0;
}
SUM=creaMatriz(m,n);
sumaMatriz(A,B,SUM,m,n);
}
if(opcion==2)
{
double **A,**B,**RES;
int m,n,p,q;
A=construyeMatriz(m,n);
B=construyeMatriz(p,q);
if(m!=p || n!=q)
45
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
{
printf("\n ERROR:La dimension de las matrices impide la operacion\n\n");
system("PAUSE");
return 0;
}
RES=creaMatriz(m,n);
restaMatriz(A,B,RES,m,n);
}
if(opcion==3)
{
double **A,**B,**PROD;
int m,n,p,q;
A=construyeMatriz(m,n);
B=construyeMatriz(p,q);
if(n!=p)
{
printf("\n ERROR:La dimension de las matrices impide la operacion\n\n");
system("PAUSE");
return 0;
}
PROD=creaMatriz(m,q);
productoMatriz(A,B,PROD,m,n,q);
}
if(opcion==4)
{
double **A,**At;
int m,n;
A=construyeMatriz(m,n);
At=creaMatriz(n,m);
traspuesta(A,At,m,n);
}
system("PAUSE");
return 0;
}
//====================================================
void presentacion(int &opcion)
{
printf("\n**************************************************\n");
printf(" PROGRAMA PARA TRABAJAR MATRICES\n");
printf(" \nEl programa permite al usuario trabajar las operaciones \n");
printf("Suma, Resta, Producto, Traspuesta\n");
printf("\n->Digite 1 para sumar dos matrices");
46
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
int i;
for( i = 0; i < m; i++) delete X[i];
delete X; //Delete libera la memoria, piensese como el puesto de new
}
47
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
//===========================================================
void lecturaMatriz(double **X, int m, int n)
{
// lectura de un matriz de tama~no mXn
int i, j;
for( i=0; i<m; i++)
{
for( j=0; j<n; j++)
{
printf("X[%d][%d] = ",i+1,j+1);
scanf("%lf", &X[i][j]);
}
}
}
//===========================================================
void escrituraMatriz(double **X, int m, int n)
{
// escritura de un matriz de tama~no mXn
printf("\n\n");
int i, j;
for( i =0;i<m; i++)
{
for( j=0; j<n; j++) printf("%lf\t",X[i][j]);
printf("\n");
}
}
//===========================================================
double **construyeMatriz(int &m,int &n)
{
//Funcion para construir una matriz, utiliza las funciones creadas anteriormente
//Se usa para reducir el numero de instrucciones en la funcion main
printf("\nA continuacion se solicitara informacion de una matriz\n");
leetamano(m,n);
double **X;
X=creaMatriz(m,n);
lecturaMatriz(X,m,n);
escrituraMatriz(X,m,n);
return X;
}
//===========================================================
void sumaMatriz(double **X,double **Y,double **S,int m, int n)
{
int i,j;
for(i=0;i<m;i++)
48
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
{
for(j=0;j<n;j++)
{
S[i][j]=X[i][j]+Y[i][j];
}
}
printf("\n\nEl resultado de la suma es: ");
escrituraMatriz(S,m,n);
}
//===========================================================
void restaMatriz(double **X,double **Y,double **R,int m, int n)
{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
R[i][j]=X[i][j]-Y[i][j];
}
}
printf("\n\nEl resultado de la resta es: ");
escrituraMatriz(R,m,n);
}
//===========================================================
void productoMatriz(double **X,double **Y,double **P,int m, int n,int q)
{
//Recordemos que el producto de matrices se define como:
//P[i][j]=<A_i,B^j> donde A_i es fila i-esima de A, B^j es columna j-esima de B
// <,> indica el producto punto de dos vectores
for(int i=0;i<m;i++)
{
for(int j=0;j<q;j++)
{
P[i][j]=0;
for(int k=0;k<n;k++)
{
P[i][j]+=X[i][k]*Y[k][j];
}
}
}
printf("\n\nEl resultado del producto es: ");
escrituraMatriz(P,m,q);
}
//===========================================================
49
IV.6. MATRICES CAPÍTULO IV. AGRUPAMIENTO DE VARIABLES
50
CAPÍTULO V
ESTRUCTURAS
Las estructuras son entes que permiten agrupar variables bajo un mismo identificador, a difer-
encia de los arreglos, se permite el agrupamiento de variables de distinto tipo. El agrupamiento
bajo una estructura permite que las variables que lo componen sean tratadas juntas.
struct NOMBRE{
tipo1 variable1 ;
..
.
tipon variablen ;
};
Cabe destacar que las variables de las cuales se compone la estructura no necesariamente son del
mismo tipo. El llamado o referenciado de una estructura se realiza por su nombre, pero además
de eso, podemos acceder a cada uno de los elementos que lo componen, para ello basta colocar
el nombre de la estructura seguido de un punto el cual se sigue del nombre del elemento que
deseamos extraer (este . es un operador de selección).
Nombre completo
Número de documente
Código
Edad
51
CAPÍTULO V. ESTRUCTURAS
struct Alumno{
char Nombre[100];
long int documento;
int codigo;
int edad;
};
Nota La estructura puede ser visualizada como la construccion de un nuevo tipo de variable,
por esta razón debe ir un “;.al final de la declaración.
Esta estructura permite agrupar bajo un tipo de variable “Alumno”toda la información que el
usuario necesita (nombre,documento de identidad, código, edad).
Ejemplo 27 Construir una estructura que permita trabajar una pareja ordenada bajo un nombre
dado por un caracter.
struct Coordenada{
char nombre;
double coord1;
double coord2
};
En la funcion main(), si queremos darle valor a una pareja ordenada, procedemos de la siguiente
manera:
Las instrucciones anteriores nos permiten construir la pareja ordenada A=(3,4.5), la cual es
identificada en el programa bajo el nombre X. Este ejemplo nos permite observar el manejo que
se da al operador de selección (.), el cual nos permite dar a valor a cada uno de los elementos
que integra nuestra estructura.
52
CAPÍTULO V. ESTRUCTURAS
El uso de estructuras nos permite definir un tipo de variable asociado a complejos o fraccionarios,
con lo cual podremos agrupar datos de una manera mas sencilla y eficiente. Debemos tener en
cuenta que las estructuras se construyen a partir de tipos conocidos, en el caso de los fraccionarios
requerimos dos variables tipo int, mientras en el caso de los complejos serán dos variables tipo
double.
Por supuesto, al crear una estructura (por lo pronto pensemos en crear un nuevo tipo de variable)
podemos también definir operaciones entre elementos de la estructura, por ejemplo en el caso de
los números fraccionarios podemos definir operaciones tales como: suma, resta, multiplicacion,
división. Para ello debemos recordar como se definen estas matemáticamente, por ejemplo la
suma se define como:
a c ad + bc
+ =
b d bd
si consideramos dos variables x, y del tipo definido en la estructura de números fraccionarios
tales que x = ab , y = dc , tendremos lo siguiente en términos de las variables del tipo definido en
la estructura.
Ejemplo 28 Construir una estructura que permita identificar numeros fraccionarios, ademas
de permitir realizar las operaciones:
Suma de fraccionarios
Resta de fraccionarios
Producto de fraccionarios
#include<stdio.h>
struct fraccionario{
int num;
int den;
};
53
CAPÍTULO V. ESTRUCTURAS
int main()
{
fraccionario Z,Y,S,R,P;
lectura(Z);
lectura(Y);
sumafrac(Z,Y,S);
restafrac(Z,Y,R);
prodfrac(Z,Y,P);
printf("\n (%d/%d) + (%d/%d) =(%d/%d)\n",Z.num,Z.den,Y.num,Y.den,S.num,S.den);
printf("\n (%d/%d) - (%d/%d) =(%d/%d)\n",Z.num,Z.den,Y.num,Y.den,R.num,R.den);
printf("\n (%d/%d) * (%d/%d) =(%d/%d)\n",Z.num,Z.den,Y.num,Y.den,P.num,P.den);
return 0;
}
//================================================================================
void lectura(fraccionario &W)
{
printf("\nDigite el fraccionario, primero el numerador, luego el denominador");
scanf("%d%d",&W.num,&W.den);
}
//================================================================================
void sumafrac(fraccionario X,fraccionario Y,fraccionario &SUMA)
{
SUMA.num=(X.num*Y.den+X.den*Y.num);
SUMA.den=X.den*Y.den;
}
//================================================================================
void restafrac(fraccionario X,fraccionario Y,fraccionario &RESTA)
{
RESTA.num=(X.num*Y.den-X.den*Y.num);
RESTA.den=X.den*Y.den;
}
//================================================================================
void prodfrac(fraccionario X,fraccionario Y,fraccionario &PROD)
{
PROD.num=(X.num*Y.num);
PROD.den=(X.den*Y.den);
}
54
CAPÍTULO V. ESTRUCTURAS
I La estructura, al ser vista como variable, admite paso por valor y por referencia
Las funciones que operan fraccionarios se construyen aplicando paso por referencia, sin embargo
podemos modificarlas levemente para trabajarlas como funciones con retorno, ası́ obtenemos:
//================================================================================
fraccionario sumafrac(fraccionario X,fraccionario Y)
{
fraccionario SUMA;
SUMA.num=(X.num*Y.den+X.den*Y.num);
SUMA.den=X.den*Y.den;
return SUMA;
}
//================================================================================
fraccionario restafrac(fraccionario X,fraccionario Y)
{
fraccionario RESTA;
RESTA.num=(X.num*Y.den-X.den*Y.num);
RESTA.den=X.den*Y.den;
return RESTA;
}
//================================================================================
fraccionario prodfrac(fraccionario X,fraccionario Y)
{
fraccionario PROD;
PROD.num=(X.num*Y.num);
PROD.den=(X.den*Y.den);
return PROD;
}
Un error frecuente a la hora de diseñar programas con estructuras es colocar las funciones
antes de la definición de la estructura. Por ejemplo, usando el ejemplo anterior, serı́a tener un
encabezado
#include<stdio.h>
55
CAPÍTULO V. ESTRUCTURAS
struct fraccionario{
int num;
int den;
};
Como el compilador lee de izquierda a derecha y de arriba hacia abajo, tendremos un inconve-
niente respecto al tipo de variable fraccionario, ya que cuando es utilizado en las funciones, el
compilador no le reconoce como un tipo. La declaración de la estructura se suele hacer antes
de las funciones para que el programador pueda disponer de la estructura como parámetro de
función.
Queda al usuario como ejercicio definir la función cociente de fraccionarios, además de expo-
nenciación de fraccionarios, radicación de fraccionarios, entre otras operaciones posibles. Por
supuesto, mejorar la escritura de los resultados en el programa ya que la presentación no es
agradable cuando se digitan fraccionarios negativos.
Ejemplo 29 Construir una estructura que permita manipular numeros complejos, y además
diseñar funciones que permitan realizar las siguientes operaciones:
56
CAPÍTULO V. ESTRUCTURAS
57
V.1. ARREGLOS DE ESTRUCTURAS CAPÍTULO V. ESTRUCTURAS
Se deja como ejercicio al usuario construir un programa en el cual se utilicen estas funciones,
además de construir otras funciones que permitan la utilizacion de complejos, como por ejemplo
el cociente de dos complejos, la norma de un complejo, entre otras.
#include<stdio.h>
#include<stdlib.h>
int main()
{
complejo *Z;
int n,p;
printf("\nDigite el tama~
no del arreglo\n");
scanf("%d",&n);
Z=new complejo[n];
for(int i=0;i<n;i++)
{
lectura(Z[i]);
p=escritura(Z[i]);
}
system("PAUSE");
return 0;
58
V.1. ARREGLOS DE ESTRUCTURAS CAPÍTULO V. ESTRUCTURAS
}
}
//==============================================================
void lectura(complejo &W)
{
printf("\nDigite la parte real del numero complejo");
scanf("%lf",&W.preal);
printf("\nDigite la parte real del numero complejo");
scanf("%lf",&W.pimag);
}
//==============================================================
int escritura(complejo W)
{
Ası́ como podemos tomar arreglos compuestos de variables de tipo complejo, también podemos
crear estructuras que se compongan de elementos tipo complejo, no obstante anidar estructuras
no es una manera eficiente de trabajar.
59
CAPÍTULO VI
ARCHIVOS
La inclusión de datos en nuestros procesos, hasta el momento, se ha realizado via teclado por el
usuario durante la ejecución del programa, este modo de trabajo puede ser un inconveniente ya
que, si el usuario desea trabajar una matriz de tamaño 10 × 10 forzosamente debera digitarla
cada vez que ejecute el programa.
El manejo de información desde archivos nos permite almacenar los datos en un archivo, el cual
reconoceremos en el programa para poder leer los datos de trabajo, incluso el resultado del
programa puede ser entregado al usuario en otro archivo, lo cual mejora la presentacion de los
resultados.
Al igual que el procesamiento del programa por parte del compilador, la lectura de datos desde
archivos se realiza iniciando de izquierda a derecha y de arriba hacia abajo en el documento. Es
decir, para el compilador las siguientes presentaciones de datos son iguales:
--------------
2 3
1 2 3
4 5 6
--------------
--------------
2
3 1 2 3
4
5 6
--------------
60
VI.1. COMANDOS IMPORTANTES PARA EL MANEJO DE ARCHIVOS
CAPÍTULO VI. ARCHIVOS
--------------
2
3
1
2
3
4
5
6
--------------
Nota los ——- no se escriben en el programa, son usados para indicar el inicio y fin del
archivo
La lectura de datos se realiza de manera secuencial, es decir, no se omiten carácteres.
Para poder procesar un archivo dentro de un programa, debemos establecer el protocolo a seguir
para que nuestro procesamiento sea exitoso. Para ello debemos cuestionarnos:
Cada una de las preguntas anteriores tiene su respuesta en un comando de la libreria stdio.h1 ,
además de contar con el tipo de variable FILE.
a: Modo escritura-al final: El archivo permite escribir resultados sin perder la información an-
terior
1
Estos comandos de la librerı́a son, en su mayorı́a, muy parecidos a los comandos usados hasta el momento
salvo que se ante pone la letra f, con lo cual se indica que el trabajo es desde archivos.
61
VI.1. COMANDOS IMPORTANTES PARA EL MANEJO DE ARCHIVOS
CAPÍTULO VI. ARCHIVOS
a+: Modo lecto-escritura al final: El archivo permite leer y escribir resultados sin perder la
información anterior
Dependiendo del tipo de tarea que deseemos realizar, escogemos el modo en el cual abrimos
nuestro archivo. Claro esta, debemos tener en cuenta las propiedades de cada modo, por ejemplo
un modo r nos permitirá utilizar los datos, pero no modificar el archivo, el modo w nos permitira
modificarlo pero no leer información.
Se sugiere no trabajar los tipos que combinan el modo de los archivos (los modos que incluyen
+ en su declaración) ya que al admitir lectura y escritura, es muy probable que el usuario al
trabajar genere pérdida de información.
FILE *A;
A=fopen("datos.txt","r");
VI.1.2. fclose
El comando fclose es el antipodal de fopen, ya que nos permite cerrar los archivos que han sido
abiertos. Normalmente el no cerrar un archivo no genera mayor problema para el compilador,
no obstante se recomienda hacerlo ya que no es recomendable no cerrar lo que hemos abierto,
prueba de ello es que al salir de nuestros hogares no dejamos la puerta abierta. La semántica es
la siguiente
FILE *A;
A=fopen("datos.txt","r");
..
.
fclose(A);
62
VI.1. COMANDOS IMPORTANTES PARA EL MANEJO DE ARCHIVOS
CAPÍTULO VI. ARCHIVOS
VI.1.3. fscanf
Este comando de lectura desde archivos, como es de esperarse, funciona solo con archivos de
lectura, ya que si se intenta utilizar sobre archivos de escritura nos presenta un error, puesto
que no contamos con los permisos para extraer información del archivo.
double x;
FILE *A;
A=fopen("datos.txt","r");
fscanf(A,"%lf",&x);
Como el archivo A que hemos abierto es de lectura, podemos realizar la lectura de un valor,
ası́ el comando
fscanf(A,"%lf",&x);
tiene sentido. Los parámetros son los mismos que cuando se trabajo con lectura desde teclado, no
obstante como la lectura se realiza desde archivo, debemos indicarle desde que archivo se realiza
la lectura(pues podemos cargar más de un archivo en un programa), de alli la aparición de la
dirección de la variable tipo file A. EL compilador busca el número que sigue en el indicador de
posición, una vez lo localiza lo lee y lo descarga en la variable indicada, luego el indicador de
posición del archivo pasa al lugar justo después del valor leı́do.
VI.1.4. fprintf
Este comando de escritura desde archivos, como es de esperarse, funciona solo con archivos de
escritura, ya que si se intenta utilizar sobre archivos de lectura nos presenta un error, puesto
que no contamos con los permisos para modificar la información del archivo.
double x;
FILE *A,*B;
A=fopen("datos.txt","r");
B=fopen("salida.txt","w");
if(A==NULL)
{
printf("\nERROR: El archivo de datos no existe\n\n");
system("PAUSE");
return 0;
}
63
VI.2. ARCHIVOS COMO PARÁMETROS DE FUNCIONES CAPÍTULO VI. ARCHIVOS
fscanf(A,"%lf",&x);
fprintf(B,"\nEl valor leido es: %lf \n",x);
Como el archivo A que hemos abierto es de lectura, podemos realizar la lectura de un valor.
Además el archivo B que hemos abierto es de escritura, por tanto podemos escribir en el archivo
los resultados, ası́ las instrucciones anteriores nos permiten leer un valor que se encuentra en el
archivo A y escribirlo en el archivo B.
No sobra destacar el gran parecido entre las funciones scanf, printf respecto a fscanf,fprintf, ya
que es una de las ventajas de trabajar la libreria estandar, pues la semántica en los comandos
de manejo desde teclado y archivos se mantiene.
Nota El control if(A==NULL) será de gran importancia, ya que permite salir del programa
en caso de que el archivo de datos no se localice.
¿Porque no se controla el archivo B?
#include<stdio.h>
#include<stdlib.h>
void instrucciones();
void lectura(FILE *A,double *X,int n);
void escritura(FILE *B,double *X,int n);
void media(FILE *B,double *X,int n);
int main()
{
instrucciones();
FILE *A,*B;
double *X;
int n;
if(A==NULL)
{
printf("\nERROR: El archivo de datos no existe\n\n");
system("PAUSE");
return 0;
}
64
VI.2. ARCHIVOS COMO PARÁMETROS DE FUNCIONES CAPÍTULO VI. ARCHIVOS
//============================================================
void instrucciones()
{
printf("\n***********************************************\n");
printf("PROGRAMA QUE CALCULA LA MEDIA DE UN CONJUNTO DE DATOS\n\n");
printf("En la carpeta de compilacion podra encontrar el documento dat.txt");
printf("\neste documento debe contener los siguientes datos.\n\n");
printf("-> Tama~
no del arreglo\n");
printf("-> Valor de cada componente del arreglo\n");
printf("***********************************************\n\n");
}
//============================================================
void lectura(FILE *A,double *X,int n)
{
//Funcion que lee los datos dados por el usuario en el arcihvo dat.txt
int i;
for (i=1;i<=n;i++)
{
fscanf(A,"%lf",&X[i-1]);
}
}
//============================================================
void escritura(FILE *B,double *X,int n)
{
// Funcion que escribe los datos dados por el usuario como vector.
int i;
fprintf(B,"(");
for (i=1;i<n;i++)
{
fprintf(B,"%lf,",X[i-1]);
}
fprintf(B,"%lf)",X[n-1]);
}
65
VI.2. ARCHIVOS COMO PARÁMETROS DE FUNCIONES CAPÍTULO VI. ARCHIVOS
//============================================================
void media(FILE *B,double *X,int n)
{
double s=0.0,mid;
for(int i=1;i<=n;i++) s+=X[i-1];
mid=s/n;
fprintf(B,"\n\nLa media es %lf",mid);
}
El archivo puede ser utilizarse como parámetro de función, ya que es tratado como apun-
tador a variable
---------------
5
1 2 3 4 5
---------------
---------------
(1.000000,2.000000,3.000000,4.000000,5.000000)
La media es 3.000000
---------------
66
VI.2. ARCHIVOS COMO PARÁMETROS DE FUNCIONES CAPÍTULO VI. ARCHIVOS
---------------
6
1 2 3 4 5 9
---------------
---------------
(1.000000,2.000000,3.000000,4.000000,5.000000,9.000000)
La media es 4.000000
---------------
---------------
(1.000000,2.000000,3.000000,4.000000,5.000000)
La media es 3.000000
(1.000000,2.000000,3.000000,4.000000,5.000000,9.000000)
La media es 4.000000
---------------
67
VI.2. ARCHIVOS COMO PARÁMETROS DE FUNCIONES CAPÍTULO VI. ARCHIVOS
---------------
5
1 2 3 4 5 9
---------------
Pese a que hay 6 datos, el primer dato indica la existencia de solo 5, por ello el compilador solo
leera los 5 primeros datos. En este caso el resultado será el siguiente:
---------------
(1.000000,2.000000,3.000000,4.000000,5.000000)
La media es 3.000000
---------------
Ahora supongamos que el número de datos es mayor a los que hemos consignado, por ejemplo,
supongamos que el archivo de datos tiene la siguiente información
---------------
10
1 2 3 4 5 9
---------------
En este caso, la información de los últimos 4 datos será inexistente, por esta razón el compilador
se verá forzado a rellenarlo con información basura, la cual producirá resultados de poca utilidad.
Por esta razón se sugiere dar información detallada al usuario de la manera en la cual deben ser
ubicados los datos en el archivo de datos.
68