sábado, 12 de junio de 2021

P6-Estructuras

 Estructuras en C

Las estructuras son colecciones de variables relacionadas bajo un nombre.
Pueden contener variables de muchos tipos diferentes de datos

a diferencia de los arreglos que contienen únicamente elementos de un mismo
tipo de datos.

 Definición de estructuras

Las estructuras son tipos de datos derivados, están construidas utilizando
objetos de otros tipos. Considere la siguiente definición de estructura:


struct ejemplo {
char c;
int i;};


La palabra reservada struct indica se está definiendo una estructura. El
identificador ejemplo es el nombre de la estructura. Las variables declaradas
dentro de las llaves de la definición de estructura son los miembros de la estructura. Los miembros de la misma estructura deben tener nombres únicos
mientras que dos estructuras diferentes pueden tener miembros con el mismo
nombre. Cada definición de estructura debe terminar con un punto y coma.
La definición de struct ejemplo contiene un miembro de tipo char y otro
de tipo int. Los miembros de una estructura pueden ser variables de los tipos
de datos básicos (int, char, float,etc) o agregados como ser arreglos y otras
estructuras. Una estructura no puede contener una instancia de si misma.
Declaramos variables del tipo estructura del siguiente modo:
struct ejemplo e1, a[10];
o alternativamente sin usar la palabra struct:
ejemplo e1, a[10];
Las declaraciones anteriores declaran variables e1 de tipo ejemplo y a de tipo
arreglo de ejemplo de dimensión 10.
Se pueden declarar variables de tipo estructura ejemplo colocando sus nombres a continuación de la llave de cierre de la definición de estructura y el punto
y coma, en el caso anterior:
struct ejemplo {
char c;

int i;} e1, a[10];

 Una operación valida entre estructuras es asignar variables de estructura a
variables de estructura del mismo tipo. Las estructuras no pueden compararse entre si.

Estructuras Anidadas

Una estructura puede estar dentro de otra estructura a esto se le conoce como anidamiento o estructuras anidadas. Ya que se trabajan con datos en estructuras si definimos un tipo de dato en una estructura y necesitamos definir ese dato dentro de otra estructura solamente se llama el dato de la estructura anterior.

Ejemplo escrito:

    1. /*
    2.        estructura2.c
    3.          
    4.    Nombre Miembro Tipo
    5.  
    6.    Titulo char[30]
    7.    Artista char[25]
    8.    Precio float
    9.   Total Canciones int
    10.  */

    11. #include <stdio.h>
    12. #include <string.h>

    13. /* creamos nuestra estructura con datos similares */
    14. struct infopersona
    15. {
    16. char direccion[25];
    17. char ciudad[20];
    18. char provincia[20];
    19. long int codigo_postal;
    20. }; /* las estructuras necesitan punto y coma (;) al final */

    21. /* creamos nuestra estructura empleado */
    22. struct empleado
    23. {
    24. char nombre_empleado[25];
    25. /* agregamos la estructura infopersona
    26. * con nombre direcc_empleado
    27. */
    28. struct infopersona direcc_empleado; 
    29. double salario;
    30. }; /* las estructuras necesitan punto y coma (;) al final */

    31. /* creamos nuestra estructura cliente */
    32. struct cliente
    33. {
    34. char nombre_cliente[25];
    35. /* agregamos la estructura infopersona
    36.   con nombre direcc_cliente
    37. */
    38. struct infopersona direcc_cliente;
    39. double saldo;
    40. }; /* las estructuras necesitan punto y coma (;) al final */

    41. int main(void)
    42. {
    43. /* creamos un nuevo cliente  */
    44. struct cliente MiCliente;
    45. /*inicializamos un par de datos de Micliente */
    46. strcpy(MiCliente.nombre_cliente,"Alexis");
    47. strcpy(MiCliente.direcc_cliente.direccion, "Altos del Cielo");
    48. /* notese que se agrega direcc_cliente haciendo referencia 
    49.   a la estructura infopersona por el dato direccion
    50. */
    51. /* imprimimos los datos */
    52. printf("\n Cliente: ");
    53. printf("\n Nombre: %s", MiCliente.nombre_cliente);
    54. /* notese la forma de hacer referencia al dato */
    55. printf("\n Direccion: %s", MiCliente.direcc_cliente.direccion); 
    56. /* creamos un nuevo empleado  */
    57. struct empleado MiEmpleado;
    58. /*inicializamos un par de datos de MiEmplado */
    59. strcpy(MiEmpleado.nombre_empleado,"Alexis");
    60. strcpy(MiEmpleado.direcc_empleado.ciudad,"Nueva York");
    61. /* para hacer referencia a ciudad de la estructura infopersona
    62. * utilizamos direcc_empleado que es una estructura anidada
    63. */
    64. /* imprimimos los datos */
    65. printf("\n");
    66. printf("\n Empleado: ");
    67. printf("\n Nombre: %s", MiEmpleado.nombre_empleado);
    68. /* notese la forma de hacer referencia al dato */
    69. printf("\n Ciudad: %s", MiEmpleado.direcc_empleado.ciudad);
    70. return 0;
    71. }

Arreglos de estructuras 

struct trabajador

{

char nombre[20];

char apellidos[40];

int edad;

};

struct trabajador fijo[20];

Así podremos almacenar los datos de 20 trabajadores. Ejemplos sobre como acceder a los campos y sus elementos: para ver el nombre del cuarto trabajador, fijo[3].nombre;. Para ver la tercera letra del nombre del cuarto trabajador, fijo[3].nombre[2];. Para inicializar la variable en el momento de declararla lo haremos de esta manera:
struct trabajador fijo[20]={{"José","Herrero Martínez",29},{"Luis","García Sánchez",46}};
Typedef

Es posible agrupar un conjunto de elementos de tipo estructura en un array. Esto se conoce como array de estructuras: El lenguaje 'C' dispone de una declaración llamada typedef que permite la creación de nuevos tipos de datos. Ejemplos:
typedef int entero; /* acabamos de crear un tipo de dato llamado entero */
entero a, b=3; /* declaramos dos variables de este tipo */




P2-Operadores y P3-Sentencias

 Símbolos de manipulación de datos 

Operadores de C

Los operadores de C son un subconjunto de los operadores integrados de C++.
Hay tres tipos de operadores. Una expresión unaria consta de un operador unario antepuesto a un operando, o la palabra clave sizeof seguida de una expresión. La expresión puede ser el nombre de una variable o una expresión de conversión. Si la expresión es una expresión de conversión, se debe incluir entre paréntesis. Una expresión binaria consta de dos operandos unidos por un operador binario. Una expresión ternaria consta de tres operandos unidos por el operador de expresión condicional.
C incluye los operadores unarios siguientes:
TABLA 1

Símbolo NOMBRE
- ~ !    Operadores de negación y complemento
* &        Operadores de direccionamiento indirecto y address-of
sizeof Operador de tamaño
+         Operador unario más
++ -- Operadores unarios de incremento y decremento


Los operadores binarios se asocian de izquierda a derecha. C proporciona los operadores binarios siguientes:
TABLA 2
Símbolo NOMBRE
* / %         Operadores de multiplicación
+ -                 Operadores aditivos
<< >>         Operadores de desplazamiento
< > <= >= == != Operadores relacionales
& | ^         Operadores bit a bit
&& ||         Operadores lógicos
,                 Operador de evaluación secuencial
 
El operador de expresión condicional tiene menos prioridad que las expresiones binarias y se diferencia de ellas en que es asociativo a la derecha.

Las expresiones con operadores también incluyen expresiones de asignación, que usan operadores de asignación unarios o binarios. Los operadores de asignación unarios son los operadores de incremento ( ++ ) y decremento ( -- ); los operadores de asignación binarios son el operador de asignación simple ( = ) y los operadores de asignación compuesta. Cada operador de asignación compuesta es una combinación de otro operador binario con el operador de asignación simple.

Operadores relacionales y de igualdad de C

Los operadores relacionales y de igualdad binarios comparan el primer operando con el segundo para probar la validez de la relación especificada. El resultado de una expresión relacional es 1 si la relación probada es true y 0 si es false. El tipo del resultado es int .

Sintaxis

relational-expression:

    shift-expression

    relational-expression < shift-expression

    relational-expression > shift-expression

    relational-expression <= shift-expression

    relational-expression >= shift-expression

equality-expression:

    relational-expression

    equality-expression == relational-expression

    equality-expression != relational-expression

Los operadores relacionales y de igualdad prueban las relaciones siguientes:

Operador Relación probada

< Primer operando menor que el segundo operando

> Primer operando mayor que el segundo operando

<= Primer operando menor o igual que segundo operando

>= Primer operando mayor o igual que segundo operando

== Primer operando igual a segundo operando

!= Primer operando no igual a segundo operando

Los cuatro primeros operadores de la lista anterior tienen mayor prioridad que los operadores de igualdad (== y !=). Vea la información de prioridad en la tabla Prioridad y asociatividad de los operadores de C.

Los operandos pueden tener tipo entero, flotante o puntero. Los tipos de operando pueden ser diferentes. Los operadores relacionales realizan las conversiones aritméticas habituales sobre operandos de tipo entero y flotante.

Operadores lógicos de C

Los operadores lógicos realizan operaciones AND lógicas ( && ) y OR lógicas ( || ).

Sintaxis

logical-AND-expression:

    inclusive-OR-expression

    logical-AND-expression && inclusive-OR-expression


logical-OR-expression:

    logical-AND-expression

    logical-OR-expression || logical-AND-expression

Los operadores lógicos no realizan las conversiones aritméticas habituales. En su lugar, evalúan cada operando para ver su equivalencia con 0. El resultado de una operación lógica es 0 o 1. El tipo del resultado es int .

A continuación se describen los operadores lógicos de C:

Operador                                           Descripción

&& El operador AND lógico genera el valor 1 si ambos operandos tienen valores          distintos de cero. Si alguno de los operandos es igual a 0, el resultado es 0. Si el primer  operando de una operación AND lógica es igual a 0, el segundo operando no se evalúa.

|| El operador OR lógico realiza una operación OR inclusivo en sus operandos. El resultado es 0 si ambos operandos tienen valores 0. Si cualquiera de los operandos tiene un valor distinto de cero, el resultado es 1. Si el primer operando de una operación OR lógica tiene un valor distinto de cero, el segundo operando no se evalúa.

Los operandos de las expresiones AND y OR lógicas se evalúan de izquierda a derecha. Si el valor del primer operando es suficiente para determinar el resultado de la operación, el segundo operando no se evalúa. Esto se denomina "evaluación de cortocircuito". Hay un punto de secuencia después del primer operando. Vea Puntos de secuencia de C para obtener más información.

Sentencias de selección

 Las sentencias ("Statements") especifican y controlan el flujo de ejecución del programa. Si no existen sentencias específicas de selección o salto, el programa se ejecuta de forma secuencial en el mismo orden en que se ha escrito el código fuente (es el que podríamos considerar orden "natural" de ejecución).

En este capítulo explicaremos los distintos tipos de sentencias que existen en C++, pero antes ofreceremos una descripción formal de las mismas señalando qué se entiende por sentencia.

Una expresión es una secuencia de operadores; operandos; elementos de puntuación y palabras clave, que especifican una computación. Tiene sentido computacional en sí misma y equivale a una frase en el lenguaje normal. Entre sus características distintivas están las de poder producir un resultado y posibles efectos laterales. Ejemplo:

extern x;        // No produce un valor

y = 22;          // Produce un valor

z = i++;         // Valor + efectos laterales

Las sentencias de selección, también llamadas de control de flujo, permiten decidir entre distintos cursos de acción en función de ciertos valores.  En C++ existen tres tipos de estas sentencias de selección:

if...else  .

else if    .

switch   .



Recuerde que de no ser por estas sentencias, el flujo de ejecución del programa estaría siempre constreñido a la ejecución de sus sentencias en el orden en que están colocadas en el fuente.

  if … else

En su forma abreviada, cuando no existe la cláusula else, esta sentencia permite escoger entre ejecutar o no una sentencia, en función del resultado de una expresión lógica.  En su forma ampliada, cuando la cláusula else está presente, permite escoger entre dos opciones alternativas.

 Sintaxis

if ( <condición> )  <sentencia1>;

[ else  <sentencia2>; ]

  Descripción

  <condición> debe ser una expresión relacional que devuelve un valor lógico, es decir, un bool ( 3.2.1b), y estar obligatoriamente entre paréntesis.  Pueden declararse variables dentro de la <condición>.  Por ejemplo, la siguiente es una sintaxis válida:

if (int val = func(arg))

   val = z ;

else  val = y;

El ámbito de la variable val incluye toda la sentencia if,  incluyendo, en su caso, el bloque <sentencia2> de else.  La cláusula else es opcional, pero no puede haber sentencias entre el if y else.    Recuerde las precauciones indicadas respecto de las expresiones relacionales , ya que son motivo frecuente de error en este tipo de sentencias.

  <sentencia1>. Es una sentencia o bloque de código que se ejecuta si <condicion> se evalúa como cierto (true  !=  0).

  <sentencia2> es una sentencia o bloque de código que se ejecuta si existe un else y <condicion> resulta falso (false  ==  0)

Puesto que el if simplemente chequea el valor resultante de <condicion> (igual o desigual a cero), las dos expresiones siguientes son equivalentes:

if ( expresion )  <sentencia> ;

if ( expresion !=0 ) <sentencia> ;

La forma más general es:

if (<condicion>) {

   <sentencia1>;

}

else  {

   <sentencia2>;

}

 Ejemplo

Uno sencillo:

if (salida == 'S') break;

Otro ejemplo:

if (a > b)

   z = a;

else

   z = b;

Se podría haber escrito de forma más comprimida:

if (a > b) z = a;

else z = b;

También:

a > b ? z = a : z = b ;

o mejor aún:

z = (a > b ? a : b);

Puesto que la cláusula else es opcional, en los if... else anidados podría haber ambigüedad sobre a qué if corresponde un else;  esto se evita asociando el else al if más interno sin else.   Por ejemplo, en los dos trozos de código siguientes, el primero tiene una indentación que no se corresponde con la realidad lógica del programa.

// mal indentado: ------------

if ( n > 0 )

   if ( a > b )

      z = a;

else

   z = b;

// bien indentado: -----------

if ( n > 0 )

   if ( a > b )

      z = a;

   else

      z = b;

 Else if

Estas sentencias no representan en realidad nada nuevo, solo una sucesión de if  else anidados, aunque de uso muy frecuente, por lo que haremos una consideración especial de este caso.

if ( <expresion1> )

   <sentencia1> ;

else if ( <expresion2> )

   <sentencia2> ;

else if ( <expresion3> )

   <sentencia3> ;

else

   <sentencia4> ;

En realidad, a la luz de lo expuesto en el apartado anterior, su indotación correcta sería:

if ( <expresion1> )
   <sentencia1> ;
else
   if ( <expresion2> )
      <sentencia2> ;
   else
      if ( <expresion3> )
         <sentencia3> ;
      else

         <sentencia4> ;


Las expresiones <expresion> son evaluadas correlativamente hasta que se encuentra la primera que devuelve un valor cierto ( != 0 ), en cuyo caso se ejecuta el bloque de código <sentencia> correspondiente y acaba la evaluación. En caso de que ninguna de las <expresion> sea cierta, se ejecuta la <sentencia> correspondiente al else (si existe).

switch

Se trata de una sentencia condicional multi-salida en la que las decisiones se toman en función de un valor numérico entero de entre una serie de opciones posibles.  Puede existir una cláusula por defecto o bien no adoptarse ninguna acción.

 Sintaxis

switch ( <expresion> ) {

  case <const1> : <sentencia1>; [break;]

  case <const2> : <sentencia2>; [break;]

  case <constN> : <sentenciaN>; [break;]

 [default : <sentenciaD>; ]

}

 Descripción

La sentencia switch comprueba cuando una expresión <expresion> entre paréntesis (que se traduce en un valor numérico) coincide con alguno de una serie de valores enteros constantes y diferentes  (<constX>). En cuyo caso, se ejecuta un bloque de código específico <sentencia>.  En caso de estar presente la cláusula opcional default y no existir concordancia con ninguno de los valores anteriores, se ejecuta una sentencia por defecto (<sentenciaD>).

Sentencias de iteración

Las sentencias de iteración permiten repetir una sentencia o conjunto de ellas. Es lo que se denomina ejecutar un bucle. En C++ existen tres formas de iteraciones: los bucles while; do…while y for.
Observe que en todos los casos el bucle puede estar constituido por una sola sentencia o por varias. En cuyo caso se trata de un bloque de código delimitado por un par de corchetes { } . Si se trata de una sola sentencia, los corchetes no son necesarios.


Bucle   while

La sentencia while permite ejecutar repetidamente un bloque de código mientras se cumpla una determinada condición que es chequeada antes de cada iteración.

Sintaxis

while ( <condicion> ) <sentencia> ;

La sentencia while ejecuta iterativamente el bucle definido por el bloque de código <sentencia> siempre que el valor devuelto por la expresión <condición> (que debe estar entre paréntesis) sea cierto.
Nota: recordemos que cierto (true) equivale numéricamente a distinto de cero, mientras que falso (false) equivale al valor cero.
Puesto que la condición se evalúa antes que cada ejecución del bucle, si al comienzo <condicion> devuelve falso, <sentencia> no se ejecuta ninguna vez, y el control pasa a la siguiente sentencia. Si <condición> devuelve cierto se ejecuta el bucle <sentencia>, y a continuación se vuelve a evaluar <condicion> con lo que se repite el ciclo.

Ejemplos

while (*p == ' ') p++;

while ( i <= j) i++;

La sentencia puede estar vacía, realizándose entonces toda la computación requerida en la cláusula <condición>. 

Ejemplo:

while ( getchar() != 'Z' );

Aunque lo normal es que la <sentencia> sea un bloque de código entre corchetes:

while (i < n) {

  cout << i << endl;

  ++i;

}

Intente por sí mismo la explicación de las salidas del programa adjunto antes de leer el comentario final (esta disposición es muy utilizada en bucles que deben repetirse un número n de veces).


#include <iostream>

using namespace std;

int main() {   // ==========

  int x = 5, y = 5;

  while ( x-- ) {

    cout << "x = " << x << endl;

  }

  while ( --y ) {

    cout << " y = " << y << endl;

  }

  cout << "Terminado!!" << endl;

}

Salida:

x = 4

x = 3

x = 2

x = 1

x = 0

y = 4

y = 3

y = 2

y = 1

En ambas iteraciones, la condición indicada en el paréntesis es chequeada antes de ejecutar la iteración (la salida en pantalla).  La diferencia entre ambos es que el postdecremento (x--) se realiza después de la evaluación del paréntesis (comprobación de que su contenido es cierto). En consecuencia, el ciclo del primer bucle es como sigue:
comprobación de que x es cierto (distinto de cero).  El resultado, que denominaremos R, es un bool.
decremento unitario de x
dos posibilidades:

R == true  →  ejecutar el bucle (salida en pantalla) →  volver al punto 1.

R == false  →  abandonar el bucle.

En cambio, en el segundo bucle, el predecremento (--x) se realiza antes de la evaluación del paréntesis (comprobación de la condición del bucle). En consecuencia, el ciclo del segundo bucle puede resumirse así:
decremento unitario de x
comprobación de que x es cierto (distinto de cero).  El resultado, que denominaremos R, es un bool.
dos posibilidades:

R == true  →  ejecutar el bucle (salida en pantalla) →  volver al punto 1.

R == false  →  abandonar el bucle.

Bucle  do...while

La sentencia do ...  while permite ejecutar repetidamente un bloque de código mientras se cumpla una determinada condición que es chequeada después de cada iteración.

 Sintaxis

do <sentencia> while ( <condición> );


La sentencia do ejecuta repetidamente el bucle definido por el bloque de código <sentencia> hasta que la sentencia de control <condición> devuelve el valor falso.
Puesto que el control se evalúa después de cada ejecución del bucle, resulta que este se ejecuta al menos una vez, aunque <condición> devuelva el valor falso desde el principio (si requiere que el bucle no se ejecute ninguna vez, es mejor utilizar while).
La forma más genérica de la expresión suele ser:

do {

   <sentencia> ;

}  while ( <condición> );

 Ejemplo
Este programa solicita una clave de acceso indefinidamente hasta que el usuario proporciona una que coincide con el valor almacenado en la matriz checkword.

#include <stdio.h>

#include <string.h>

int main () {        // ===================

   char checkword[80] = "password";

   char password[80]  = "";

   do {

      printf ("Introducir clave: ");

      scanf("%s", password);

   } while (strcmp(password, checkword));

   return 0;

}

A continuación se muestra un caso simétrico al presentado para los bucles while , que utiliza los operadores unitarios de decremento. Intente explicar por sí mismo las salidas obtenidas antes de leer el comentario:

#include <iostream>

using namespace std;

int main() {    // ========

  int x = 5, y = 5;

  do {

    cout << "x = " << x << endl;

  } while ( x-- );

  do {

    cout << "y = " << y << endl;

  } while ( --y );

  cout << "Terminado!!" << endl;

}

Salida:

x = 5

x = 4

x = 3

x = 2

x = 1

x = 0

y = 5

y = 4

y = 3

y = 2

y = 1


En este caso, las el bloque de código (salida en pantalla) es ejecutado antes del chequeo de la condición expresada en el paréntesis. La diferencia entre ambos bucles es que en el primero, el postdecremento (x--) se realiza después de la evaluación del paréntesis (comprobación de que su contenido es cierto). En consecuencia, el ciclo es como sigue:
ejecutar el bloque de código (salida en pantalla)
comprobación de que x es cierto (distinto de cero).  El resultado, que denominaremos R, es un bool.
decremento unitario de x
dos posibilidades:

R == true  →  volver al punto 1.

R == false  →  abandonar el bucle.

En cambio, en el segundo bucle, el predecremento (--x) se realiza antes de la evaluación del paréntesis (comprobación de la condición del bucle). En consecuencia, su ciclo puede resumirse así:
ejecutar el bloque de código (salida en pantalla)
decremento unitario de x
comprobación de que x es cierto (distinto de cero).  El resultado, que denominaremos R, es un bool.
dos posibilidades:

R == true  →  volver al punto 1.

R == false  →  abandonar el bucle.

 Bucle  for

Esta sentencia permite realizar un bucle repetidamente en base a una condición, la cual suele estar basada en el valor de un contador que se actualiza después de cada ejecución del bucle.
 Sintaxis

for ( [<inicio>] ; [<condicion>] ; [<incremento>] ) <sentencia>

Descripción

La sentencia for realiza un bucle iterativo, es equivalente al:

for <inicio> to <condición> step <incremento>

   <sentencia>

next

de otros lenguajes. <inicio> e <incremento> pueden ser llamadas a funciones o sentencias de asignación. <sentencia> es del cuerpo del bucle, y puede ser cualquier bloque de código.
La utilización más común suele adoptar la forma:

for ( <inicio> ; <condición> ; <incremento> ) {

   <sentencia>;

}

Ejemplo

for(i=0; i<n; i++) { /* sentencias del bucle */ }

  <inicio> inicia las variables para el bucle antes de la primera iteración. Puede ser una expresión o una declaración. El ejemplo que sigue sería correcto en C++:

for (int i=0; i<10; i++)  printf("i =%5.0d\n", i);

En cambio, para compilarlo en C sería necesario declarar i en una expresión anterior:

int i;

for (i=0; i<10; i++)  printf("i =%5.0d\n", i);

El ámbito de una variable definida en la expresión <inicio> es variable, depende del interruptor -Vd del compilador .
  <condición> Debe ser una expresión relacional (devuelva un valor lógico). Es comprobada antes de la primera ejecución del bloque <sentencia>, que es ejecutado repetidamente hasta que <condición> sea falso, por lo que si <condición> devuelve falso desde el principio, el bucle no se ejecuta nunca.
  <incremento>. Después de cada iteración del bucle, <incremento> incrementa un contador de bucle; en consecuencia j++ es funcionalmente equivalente a ++j.
  <sentencia> es el bucle de for; sentencia o bloque de código que se ejecuta iterativamente. El ámbito de cualquier identificador declarado dentro él se limita al final de la sentencia de control.
  Todas las expresiones son opcionales, pero los separadores ; no pueden faltar. Si falta <condición>, se supone que es siempre cierta, por lo que se trata de un bucle indefinido del que se saldrá por otro mecanismo externo al propio for, que pueden ser un break o un return. Es típico utilizar este tipo de construcciones para construir bucles con una o más condiciones de salida


P5-Archivos

 Archivos de datos 

Un archivo es un conjunto de datos estructurados en una colección de entidades elementales o básicas denominadas registros que son de igual tipo y constan a su vez de diferentes entidades de nivel más bajos denominadas campos.

Hay dos tipos de archivos, archivos de texto y archivos binarios. Un archivo de texto es una secuencia de caracteres organizadas en líneas terminadas por un carácter de nueva línea. En estos archivos se pueden almacenar canciones, fuentes de programas, base de datos simples, etc. Los archivos de texto se caracterizan por ser planos, es decir, todas las letras tienen el mismo formato y no hay palabras subrayadas, en negrita, o letras de distinto tamaño o ancho.

Un archivo binario es una secuencia de bytes que tienen una correspondencia uno a uno con un dispositivo externo. Así que no tendrá lugar ninguna traducción de caracteres. Además, el número de bytes escritos (leídos)será el mismo que los encontrados en el dispositivo externo. Ejemplos de estos archivos son Fotografías, imágenes, texto con formatos, archivos ejecutables (aplicaciones), etc.

En c, un archivo es un concepto lógico que puede aplicarse a muchas cosas desde archivos de disco hasta terminales o una impresora. Se asocia una secuencia con un archivo especifico realizando una operación de apertura. Una vez que el archivo está abierto, la información puede ser intercambiada entre este y el programa.

Se puede conseguir la entrada y la salida de datos a un archivo a través del uso de la biblioteca de funciones; C no tiene palabras claves que realicen las operaciones de E/S. La siguiente tabla da un breve resumen de las funciones que se pueden utilizar. Se debe incluir la librería STDIO.H. Observe que la mayoría de las funciones comienzan con la letra “F”, esto es un vestigio del estándar C de Unix

Nombre                 Función

fopen() Abre un archivo.

fclose() Cierra un archivo.

fgets() Lee una cadena de un archivo.

fputs() Escribe una cadena en un archivo

fseek() Busca un byte especifico de un archivo.

fprintf() Escribe una salida con formato en el archivo.

fscanf() Lee una entrada con formato desde el archivo.

feof() Devuelve cierto si se llega al final del archivo.

ferror() Devuelve cierto si se produce un error.

rewind() Coloca el localizador de posición del archivo al principio del mismo.

remove() Borra un archivo.

fflush() Vacía un archivo.

 El puntero a un archivo.
El puntero a un archivo es el hilo común que unifica el sistema de E/S con buffer. Un puntero a un archivo es un puntero a una información que define varias cosas sobre él, incluyendo el nombre, el estado y la posición actual del archivo. En esencia identifica un archivo especifico y utiliza la secuencia asociada para dirigir el funcionamiento
de las funciones de E/S con buffer. Un puntero a un archivo es una variable de tipo puntero al tipo FILE que se define en STDIO.H. Un programa necesita utilizar punteros a archivos para leer o escribir en los mismos. Para
obtener una variable de este tipo se utiliza una secuencia como esta:


FILE *F;

Apertura de un archivo.
La función fopen() abre una secuencia para que pueda ser utilizada y la asocia a un archivo. Su prototipo es:

FILE *fopen(const char nombre_archivo, cost charmodo);

 Donde nombre_archivo es un puntero a una cadena de caracteres que representan un nombre valido del archivo y puede incluir una especificación del directorio. La cadena a la que apunta modo determina como se abre el archivo. La siguiente tabla muestra los valores permitidos para modo.

Modo                 Significado

r            Abre un archivo de texto para lectura.

w          Crea un archivo de texto para escritura.

a           Abre un archivo de texto para añadir.

rb          Abre un archivo binario para lectura.

wb        Crea un archivo binario para escritura.

ab         Abre un archivo binario para añadir.

r+         Abre un archivo de texto para lectura / escritura.

w+       Crea un archivo de texto para lectura / escritura.

a+         Añade o crea un archivo de texto para lectura / escritura.

r+b       Abre un archivo binario para lectura / escritura.

w+b     Crea un archivo binario para lectura / escritura.

a+b      Añade o crea un archivo binario para lectura / escritura.

Lectura

Un archivo generalmente debe verse como un string (una cadena de caracteres) que esta guardado en el disco duro. Para trabajar con los archivos existen diferentes formas y diferentes funciones. Las funciones que podríamos usar para leer un archivo son:

char fgetc(FILE *archivo)

char *fgets(char *buffer, int tamano, FILE *archivo)

size_t fread(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);

int fscanf(FILE *fichero, const char *formato, argumento, ...);

Las primeras dos de estas funciones son muy parecidas entre si. Pero la tercera, por el numero y el tipo de parámetros, nos podemos dar cuenta de que es muy diferente, por eso la trataremos aparte junto al fwrite que es su contraparte para escritura.

Escritura

Así como podemos leer datos desde un fichero, también se pueden crear y escribir ficheros con la información que deseamos almacenar, Para trabajar con los archivos existen diferentes formas y diferentes funciones. Las funciones que podríamos usar para escribir dentro de un archivo son:

int fputc(int caracter, FILE *archivo)

int fputs(const char *buffer, FILE *archivo)

size_t fwrite(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);

int fprintf(FILE *archivo, const char *formato, argumento, ...);


 

P4-Arreglos

¿Qué es un arreglo? 

Un arreglo es una colección ordenada de variables del mismo tipo. Las variables que pertenecen a un arreglo se conocen por el nombre de elementos. El termino ordenado significa que en la colección hay un primer elemento, un segundo elemento, un tercer elemento, y así sucesivamente. Además, los elementos pueden a su vez organizarse en subgrupos llamadas dimensiones. 

Cada uno de esos elementos se distinguen por un índice o subíndice al que se puede apuntar con un puntero para acceder a dicha posición del array. Además, también se podría escribir código para acceder de forma aleatoria a estos elementos de los que se compone el arreglo.

Tipos

Si atendemos al tipo de array, se pueden encontrar los siguientes tipos:

Unidimensional

Un array de tipo unidimensional es básicamente un vector de datos o lista. Dicho de otro modo, es un conjunto de variables del mismo tipo y tamaño que ocupan posiciones consecutivas en una memoria. El tamaño de la memoria ocupada por el array es siempre fijo y no se puede variar.

Un ejemplo sencillo para este tipo de arreglo sería este programa que te pide introducir unos números para guardarlos en las posiciones del arreglo y luego muestra el contenido del array:

  1. #include<stdio.h>
  2. int main()
  3. {
  4.     int arreglo[5], i;
  5.     for (i = 0; i < 5; i++)
  6.     {
  7.         printf ("Introduce el dato de la posición [%d]: ", i);
  8.         scanf("%d", &arreglo[i]);
  9.     } 
  10.     printf("\nLos elementos del arreglo son: \n\n");
  11.     for(i = 0; i < 5; i++)
  12.     {
  13.         printf("%d ", arreglo[i]);
  14.     }
  15.     return 0;
  16. }

Bidimensional

Un array de tipo bidimensional es básicamente una tabla o matriz de datos. Es decir, tienen varias filas y columnas, siendo el resto de detalles común a los unidimensionales.

Un ejemplo sencillo sería este otro programa que hace lo mismo que el unidimensional, pero guarda los valores en dos dimensiones:

  1. #include<stdio.h>
  2. int main(){
  3.    int arreglo[2][3];
  4.    int i, j;
  5.    for(i=0; i<2; i++) {
  6.       for(j=0;j<3;j++) {
  7.          printf("Introduce el valor de la posición [%d][%d]:", i, j);
  8.          scanf("%d", &arreglo[i][j]);
  9.       }
  10.    }
  11.    printf("Los elementos del array son:\n");
  12.    for(i=0; i<2; i++) {
  13.       for(j=0;j<3;j++) {
  14.          printf("%d ", arreglo[i][j]);
  15.          if(j==2){
  16.             printf("\n");
  17.          }
  18.       }
  19.    }
  20.    return 0;
  21. }

 Arreglos multidimensionales

Es una estructura de datos estática y de un mismo tipo de datos, y de longitud fija que almacena datos de forma matricial. De igual forma que los arreglos unidimensionales, el almacenamiento de los datos en la memoria se realiza de forma secuencial y son accedidos mediante índices. Los arreglos multidimensionales son también conocidos como matrices. Por lo tanto se llama matriz de orden "m×n" a un conjunto rectangular de elementos dispuestos en filas "m" y en columnas "n", siendo m y n números naturales. Las matrices se denotan con letras mayúsculas: A, B, C, ... y los elementos de las mismas con letras minúsculas y subíndices que indican el lugar ocupado: a, b, c, ... Un elemento genérico que ocupe la fila i y la columna j se escribe i,j. Si el elemento genérico aparece entre paréntesis también representa a toda la matriz: A (i,j). s

#include <iostream>

2. using namespace std;

3. int main()

4. {

5. int matriz [3][2];

6. int valor;

7. for(int i=0;i<3;i++) // Recorre las filas de la matriz

8. {

9. for(int j=0; j<2;j++) // Recorre las columnas de la matriz

10. {

11. cout<<"Ingrese el valor de la matriz en la posicion ["<<i<<","<<j<<"]"<<endl;

12. cin>>valor;

13. matriz[i][j] = valor;

14. }

15. }

16. // Imprimiendo el arreglo en formato matricial

17. for(int i=0;i<3;i++)

18. {

19. cout<<"|";

20. for(int j=0; j<2;j++)

21. {

22. cout<<"\t"<<matriz[i][j]<<"\t";

23. }

24. cout<<"|"<<endl;

25. }

26. return 0;

27. }

Tridimensionales 

 La matriz tridimensional se utiliza, por ejemplo, para trabajos gráficos con objetos 3D.

En el ejemplo puedes ver como se rellena y visualiza una matriz bidimensional. Se necesitan dos bucles para cada una de las operaciones. Un bucle controla las filas y otro las columnas.



Si al declarar una matriz también queremos inicializarla, habrá que tener en cuenta el orden en el que los valores son asignados a los elementos de la matriz. Veamos algunos ejemplos:

int numeros[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

quedarían asignados de la siguiente manera:

numeros[0][0]=1 numeros[0][1]=2 numeros[0][2]=3 numeros[0][3]=4

numeros[1][0]=5 numeros[1][1]=6 numeros[1][2]=7 numeros[1][3]=8

numeros[2][0]=9 numeros[2][1]=10 numeros[2][2]=11 numeros[2][3]=12

También se pueden inicializar cadenas de texto:

char dias[7][10]={"lunes","martes","miércoles","jueves","viernes","sábado","domingo"};

Para referirnos a cada palabra bastaría con el primer índice:

printf("%s",dias[i]);

Funciones

Una función es un bloque de código que realiza alguna operación. Una función puede definir opcionalmente parámetros de entrada que permiten a los llamadores pasar argumentos a la función. Una función también puede devolver un valor como salida. Las funciones son útiles para encapsular las operaciones comunes en un solo bloque reutilizable, idealmente con un nombre que describa claramente lo que hace la función. La función siguiente acepta dos enteros de un llamador y devuelve su suma; a y b son parámetros de tipo int .

C++
int sum(int a, int b)
{
    return a + b;
}

Se puede invocar la función o llamarla desde cualquier número de lugares del programa. Los valores que se pasan a la función son los argumentos, cuyos tipos deben ser compatibles con los tipos de parámetro de la definición de función.

int main()

{

    int i = sum(10, 32);

    int j = sum(i, 66);

    cout << "The value of j is" << j << endl; // 108

}

No hay ningún límite práctico para la longitud de la función, pero un buen diseño tiene como objetivo funciones que realizan una sola tarea bien definida. Los algoritmos complejos deben dividirse en funciones más sencillas y fáciles de comprender siempre que sea posible.

Las funciones definidas en el ámbito de clase se denominan funciones miembro. En C++, a diferencia de otros lenguajes, una función también pueden definirse en el ámbito de espacio de nombres (incluido el espacio de nombres global implícito). Estas funciones se denominan funciones libres o funciones no miembro; se usan en gran medida en la biblioteca estándar.

Las funciones se pueden sobrecargar, lo que significa que las distintas versiones de una función pueden compartir el mismo nombre si difieren en el número o el tipo de parámetros formales. Para obtener más información, vea sobrecarga de funciones.

Elementos de una declaración de función
Una declaración de función mínima está formada por el tipo de valor devuelto, el nombre de función y la lista de parámetros (que puede estar vacía), junto con palabras clave opcionales que proporcionan instrucciones adicionales para el compilador. El ejemplo siguiente es una declaración de función:


int sum(int a, int b);

 

Una definición de función se compone de una declaración, más el cuerpo, que es todo el código entre las llaves:


int sum(int a, int b)
{
    return a + b;
}

Una declaración de función seguida de un punto y coma puede aparecer en varios lugares de un programa. Debe aparecer antes de cualquier llamada a esa función en cada unidad de traducción. La definición de función debe aparecer solo una vez en el programa, según la regla de una definición (ODR).

 

P6-Estructuras

 Estructuras en C Las estructuras son colecciones de variables relacionadas bajo un nombre. Pueden contener variables de muchos tipos difere...