proyecto ETAC



etacalumnos@gmail.com

PROGRAMACION

10.04.2014 21:22

PROGRAMACION BASICA

 

SENTENCIAS DE CONTROL




C.0 Introducción

En C, cualquier expresión finalizada en un punto y coma ; forma una sentencia.
De todos los tipos, las estructuras (o sentencias ) de control son las que controlan la ejecución de las instrucciones de un programa.
La programacion estructurada se basa en la utilización de un reducido número de estructuras
que permiten hacer que un programa sea suficientemente legible, reduciendo considerablemente
el número de errores, y facilitando enormemente la detección y solución de estos.
La característica fundamental de la programación estructurada consiste en que todas las
estructuras tienen un único punto de entrada y un único punto de salida. Esto permite descomponer
fácilmente un problema en subproblemas, reduciendo la complejidad y facilitando la programación.


En C diferenciamos tres tipos de sentencias de control:
-Sentencias condicionales o selectivas.
-Sentencias de iteración o repetitivas (bucles).
-Sentencias de salto.

Se recomienda evitar la utilización de este ultimo tipo de sentencias.


C.1 Sentencias condicionales

Hay tres sentencias condicionales en C: if, else y switch


C.1.1 Sentencia if

La sentencia if nos permite elegir si se ejecuta o no un bloque de instrucciones. La "expresión" del if es una expresión que debe ser evaluada: falsa si es cero y verdadera si vale distinto de cero.

Ejemplo:
#include <stdio.h>
int main ()
{
int x;
printf(“Dame un numero”);
scanf(“%d”,&x);
if (x>0) {
printf(“El numero %d es positivo”,x);
}
return 0;
}


C.1.2 Sentencia else

Una sentencia if cuando incluye un else, permite ejecutar un bloque de código si se cumple la condición y otro bloque diferente de código si la condición no se cumple.

Ejemplo:
#include <stdio.h>
void main ()
{
int x;
printf(“Dame un numero: ”);
scanf(“%d”,&x);
if (x>=0) {
printf(“El numero %d es positivo”, x);
} else {
printf(“El numero %d es negativo”, x);
}
}


C.1.3 Sentencia else colgante

Ejemplo:
#include<stdlib.h>
int main()
{
float nota;
printf ("Dame una nota: ")
scanf ("%f", &nota)
if (nota>9){
printf("Sobresaliente");}
else if(nota >=7){
printf("Notable);}
else if(nota >=5){
printf("Aprobado");}
else{
printf ("Suspenso);}
return 0;
}


C.1.4 Sentencia switch

Permite seleccionar entre multiples alternativas posibles. La expresión del switch es una variable int o char, que puede tomar los valores, entre otros, dados por "opción 1", "opcion 2", etc.

Ejemplo:
#include <stdio.h>
void main()
{
int nota;
printf(“Calificación: ”);
scanf(“%d”, &nota);
switch (nota) {
case 0:
case 1:
case 2:
case 3:
case 4:
printf(“Suspenso”);
break;
case 5:
case 6:
printf(“Aprobado”);
break;
case 7:
case 8:
printf(“Notable”);
break;
case 9:
printf(“Sobresaliente”);
break;
case 10:
printf(“Matrícula”);
break;
default:
printf(“Error”);
}
}


C.2 Sentencias de control: Iteración

Las instrucciones de iteración también llamados bucles, se ejecutan hasta que se cumpla alguna condición predeterminada en el bucle en el caso del “for” o también en los casos del “while” y “do-while”. Podemos destacar los antes mencionados bucles que son los bucles for,while y do-while.



C.2.1 Bucles for:

Tienen una gran potencia y flexibilidad, y tienen un esquema muy sencillo y definido. Este esquema es así:
for(inicialización del bucle; condición; incremento).
Ahora vamos a proceder a definir cada una de las partes del esquema básico, inicialización (exp1): es una asignación que se utiliza para comenzar la variable del bucle, esto es de la variable de la que parte el bucle. Condición (exp2): es una expresión relacional que hace que el bucle concluya cuando no se cumpla. Por último el incremento (exp3): es la parte que determina como cambia la variable hasta que el bucle concluye. Es importante señalar que cada parte ha de ser separado por ; .Para que deje de ejecutarse el bucle como antes hemos mencionado depende de la condición, que deberá de ser falsa para que el bucle se detenga.
Debemos tener en cuenta que a diferencia de otros bucles este no llegará a ejecutarse si la condición es falsa, ya que la condición se comprueba antes de entrar en el bucle.

 

Hooolaaa.jpg



Un sencillo ejemplo:
#include <stdio.h>
int main( )
{
int x;
for(x=1; x<=100; x++)
printf (“%d”,x);
return 0;
}
Una de las utilidades del bucle for es en el bucle infinito, que pese a que puede hacerse con todos los bucles es el for con el que se usa. Estos bucles infinitos son usados para que el bucle no concluya nunca hasta que en el cuerpo se encuentre un break. Por otro lado la construcción de este bucle for es muy sencilla, for ( ; ; ).



C.2.2 Bucles while:

Tiene cierta semejanza con el bucle for, así es en el uso de una inicialización, una condición y un incremento. Otra de sus similitudes es el momento en el que analizan la condición que en ambos es antes de ejecutar el bucle. Sin embargo, en su esquema básico aunque parezcan diferentes, son el mismo:

 

papapa.jpg

while (condición)
{
cuerpo;
incremento;
}

Algunas de las veces podremos saber antes de empezar el bucle cuantas veces se va a ejecutar.



Ejemplo:
char esperar_caracter (void)
{
char c;
c=’\0’;
while (c!=’A’)
c=getchar ( );
return c;
}


C.2.3 Bucles do-while:

Este es el único bucle que al menos se va a ejecutar una vez puesto que este bucle examina la condición una vez se ha ejecutado el bucle, esto es, al final del mismo. El esquema básico de este bucle sería algo así:
do
{
cuerpo;
}
while (condición);

Este bucle es muy útil por ejemplo en menús dado que el menú debe de ejecutarse al menos una vez.

 

tititi.jpg



Ejemplo:
#include <stdio.h>
int main()
{
int digito=0;
do {
printf("%d ",digito++);
}
while (digito<=9);
}


C.3 Sentencias de salto

Hay cuatro sentencias de salto en C: break, return, goto y continue.
Suelen estar condicionadas (que solo las ejecute el programa en un determinado caso).
Se desaconseja la utilización de este tipo de sentencia de control, sobre todo el goto, ya que su uso implica un aumento de la probabilidad de cometer errores, dificulta la legibilidad del código y es mucho mas difícil corregir errores y cambiar secuencias de código.


C.3.1 Sentencia break

La instrucción de salto break se usa para interrumpir (romper) la ejecución normal de un bucle, es decir, la instrucción break finaliza la ejecución de un bucle y, por tanto, el control del programa se transfiere (salta) a la primera instrucción después del bucle.


Ejemplo:
#include <stdio.h>
int main()
{
int n, a;
a = 0;
do
{
printf( "Introduzca un numero entero: " );
scanf( "%d", &n );
if ( n == 0 )
{
printf( "ERROR: El cero no tiene opuesto.\n" );
break;
/* En el caso de que n sea un cero,
el bucle se interrumpe. */
}
printf( "El opuesto es: %d\n", -n );
a += n;
} while ( n >= -10 && n <= 10 );

printf( "Suma: %d", a );
return 0;
}



C.3.2 Sentencia return

La instrucción de salto return es utilizada en lenguaje C para devolver el control de ejecución desde la función que contiene el return a la rutina que la invocó y para indicar el valor de retorno de una función.

Ejemplo:
#include <iostream>
int z;
void funcion();
int main()
{
for(z=0;z<=5;z++)
{
printf("%i\n",z);
funcion();
system("pause");
}
return 0; Indica al ordenador que el programa ha fnalizado sin errores.
}

void funcion()
{
printf("Hola\n");
if(z==3){printf("Z vale 3\n"); return;} El return termina la función y entonces printf("Z no vale 3\n"); no se ejecutará
printf("Z no vale 3\n");
}


C.3.3 Sentencia goto

La instrucción de salto goto se puede usar en un programa, para transferir incondicionalmente el control del mismo a la primera instrucción después de una etiqueta, o dicho de otra forma, al ejecutar una instrucción goto, el control del programa se transfiere (salta) a la primera instrucción después de una etiqueta.

Ejemplo:
#include <stdio.h>
int main()
{
int n, a;
a = 0;
do
{
printf( "Introduzca un numero entero: " );
scanf( "%d", &n );
if ( n == 0 )
{
printf( "ERROR: El cero no tiene opuesto.\n" );
goto etiqueta_1;
/* En el caso de que n sea un cero,
el control de programa salta a la
primera instrucción después de
etiqueta_1. */
}
printf( "El opuesto es: %d\n", -n );
a += n;
} while ( n >= -10 && n <= 10 );

etiqueta_1:
printf( "Suma: %d", a );
return 0;
}



C.3.4 Sentencia continue

La instrucción de salto continue siempre se usa para interrumpir (romper) la ejecución normal de un bucle. Sin embargo, el control del programa no se transfiere a la primera instrucción después del bucle, como sí hace la instrucción break, es decir, el bucle no finaliza, sino que, finaliza la iteración en curso, transfiriéndose el control del programa a la condición de incremento de contadores y después a la condición de salida del bucle, para decidir si se debe realizar una nueva iteración o no.


Ejemplo:
#include <stdio.h>
int main()
{
int n, a;
a = 0;
do
{
printf( "Introduzca un numero entero: " );
scanf( "%d", &n );
if ( n == 0 )
{
printf( "ERROR: El cero no tiene opuesto.\n" );
continue;
/* En el caso de que n sea un cero,
la iteración en curso del bucle
se interrumpe aquí. */
}
printf( "El opuesto es: %d\n", -n );
a += n;
} while ( n >= -10 && n <= 10 );

printf( "Suma: %d", a );
return 0;
}

 

 

Constantes

 

El concepto de constante (expresión con la palabra reservada const) se creó para permitir a los programadores marcar la diferencia entre lo que puede cambiar y lo que no. Esto facilita el control y la seguridad en un proyecto de programación.

Desde su origen, const ha sido utilizada para diferentes propósitos. Mientras tanto FIXME:it trickled back en el lenguaje C en el que su significado cambió. Todo esto puede parecer un poco confuso al principio, y en este capítulo aprenderá cuándo, porqué y cómo usar la palabra reservadaconst. Hacia el final se expone una disertación sobre volatile, que es familia de const (ambos se refieren a los cambios) y su sintaxis es idéntica.

El primer motivo para la creación de const parece que fue eliminar el uso de la directiva del preprocesador #define para sustitución de valores. Desde entonces se usa para punteros, argumentos de funciones, tipos de retorno, objetos y funciones miembro. Todos ellos tienen pequeñas diferencias pero su significado es conceptualmente compatible. Se tratarán en las siguientes secciones de este capítulo.

8.1. Sustitución de valores

Cuando se programa en C, se usa libremente el preprocesador para crear macros y sustituir valores. El preprocesador simplemente hace un reemplazo textual y no realiza ninguna comprobación de tipo. Por ello, la sustitución de valores introduce pequeños problemas que se pueden evitar usando valores constantes.

El uso más frecuente del preprocesador es la sustitución de valores por nombres, en C es algo como:

#define BUFSIZE 100

BUFSIZE es un nombre que sólo existe durante el preprocesado. Por tanto, no ocupa memoria y se puede colocar en un fichero de cabecera para ofrecer un valor único a todas las unidades que lo utilicen. Es muy importante para el mantenimiento del código el uso de sustitución de valores en lugar de los también llamados «números mágicos». Si usa números mágicos en su código. no solamente impedirá al lector conocer su procedencia o significado si no que complicará innecesariamente la edición del código si necesita cambiar dicho valor.

La mayor parte del tiempo, BUFSIZE se comportará como un valor ordinario, pero no siempre. No tiene información de tipo. Eso puede esconder errores difíciles de localizar. C++ utiliza const para eliminar estos problemas llevando la sustitución de valores al terreno del compilador. Ahora, puede escribir:

const int bufsize = 100;

Puede colocar bufsize en cualquier lugar donde se necesite conocer el valor en tiempo de compilación. El compilador utiliza bufsize para hacer propagación de constantes[61], que significa que el compilador reduce una expresión constante complicada a un valor simple realizando los cálculos necesarios en tiempo de compilación. Esto es especialmente importante en las definiciones de vectores:

char buf[bufsize];

Puede usar const con todos los tipos básicos(charintfloat y double) y sus variantes (así como clases y todo lo que verá después en este capítulo). Debido a los problemas que introduce el preprocesador deberá utilizar siempre const en lugar de #define para la sustitución de valores.

8.1.1. const en archivos de cabecera

Para poder usar const en lugar de #define, debe ser posible colocar las definiciones const en los archivos de cabecera como se hacía con los #define. De este modo, puede colocar la definición de una constante en un único lugar y distribuirla incluyendo el archivo de cabecera en las unidades del programa que la necesiten. Una constante en C++ utiliza enlazado interno, es decir, es visible sólo desde el archivo donde se define y no puede verse en tiempo de enlazado por otros módulos. Deberá asignar siempre un valor a las constantes cuando las defina, excepto cuando explícitamente use la declaración extern:

extern const int bufsize;

Normalmente el compilador de C++ evita la asignación de memoria para las constantes, pero en su lugar ocupa una entrada en la tabla de símbolos. Cuando se utiliza extern con una constante, se fuerza el alojamiento en memoria (esto también ocurre en otros casos, como cuando se solicita la dirección de una constante). El uso de la memoria debe hacerse porque extern dice «usa enlazado externo», es decir, que varios módulos deben ser capaces de hacer referencia al elemento, algo que requiere su almacenamiento en memoria.

Por lo general, cuando extern no forma parte de la definición, no se pide memoria. Cuando la constante se utiliza simplemente se incorpora en tiempo de compilación.

El objetivo de no almacenar en memoria las constantes tampoco se cumple con estructuras complicadas. Cuando el compilador se ve obligado a pedir memoria no puede realizar propagación de constantes (ya que el compilador no tiene forma de conocer con seguridad que valor debe almacenar; si lo conociese, no necesitaría pedir memoria).

Como el compilador no siempre puede impedir el almacenamiento para una constante, las definiciones de constantes utilizan enlace interno, es decir, se enlazan sólo con el módulo en que se definen. En caso contrario, los errores de enlace podrían ocurrir con las expresiones constantes complicadas ya que causarían petición de almacenamiento en diferentes módulos. Entonces, el enlazador vería la misma definición en múltiples archivos objeto, lo que causaría un error en el enlace. Como las constantes utilizan enlace interno, el enlazador no intenta enlazar esas definiciones a través de los módulos, y así no hay colisiones. Con los tipos básicos, que son los se ven involucrados en la mayoría de los casos, el compilador siempre realiza propagación de constantes.

8.1.2. constantes seguras

El uso de las constantes no está limitado a la sustitución de los #define por expresiones constantes. Si inicializa una variable con un valor que se produce en tiempo de ejecución y sabe que no cambiará durante la vida de la variable, es una buena práctica de programación hacerla constante para que de ese modo el compilador produzca un mensaje de error si accidentalmente alguien intenta modificar dicha variable. Aquí hay un ejemplo:

//: C08:Safecons.cpp
// Using const for safety
#include <iostream>
using namespace std;
 
const int i = 100;  // Typical constant
const int j = i + 10; // Value from const expr
long address = (long)&j; // Forces storage
char buf[j + 10]; // Still a const expression
 
int main() {
  cout << "type a character & CR:";
  const char c = cin.get(); // Can't change
  const char c2 = c + 'a';
  cout << c2;
  // ...
} ///:~

Listado 8.1. C08/Safecons.cpp

 

Puede ver que i es una constante en tiempo de compilación, pero j se calcula a partir de i. Sin embargo, como i es una constante, el valor calculado para j es una expresión constante y es en si mismo otra constante en tiempo de compilación. En la siguiente línea se necesita la dirección de j y por lo tanto el compilador se ve obligado a pedir almacenamiento para j. Ni siquiera eso impide el uso de j para determinar el tamaño de buf porque el compilador sabe que j es una constante y que su valor es válido aunque se asigne almacenamiento, ya que eso se hace para mantener el valor en algún punto en el programa.

En main(), aparece un tipo diferente de constante en el identificador c, porque el valor no puede ser conocido en tiempo de compilación. Eso significa que se requiere almacenamiento, y por eso el compilador no intenta mantener nada en la tabla de símbolos (el mismo comportamiento que en C). La inicialización debe ocurrir, aún así, en el punto de la definición, y una vez que ocurre la inicialización, el valor ya no puede ser cambiado. Puede ver que c2 se calcula a partir de c y además las reglas de ámbito funcionan para las constantes igual que para cualquier otro tipo, otra ventaja respecto al uso de #define.

En la práctica, si piensa que una variable no debería cambiar, debería hacer que fuese una constante. Esto no sólo da seguridad contra cambios inadvertidos, también permite al compilador generar código más eficiente ahorrando espacio de almacenamiento y lecturas de memoria en la ejecución del programa.

8.1.3. Vectores

Es posible usar constantes para los vectores, pero prácticamente está dando por hecho que el compilador no será lo suficientemente sofisticado para mantener un vector en la tabla de símbolos, así que le asignará espacio de almacenamiento. En estas situaciones, const significa «un conjunto de datos en memoria que no pueden modificarse». En cualquier caso, sus valores no puede usarse en tiempo de compilación porque el compilador no conoce en ese momento los contenidos de las variables que tienen espacio asignado. En el código siguiente puede ver algunas declaraciones incorrectas.

//: C08:Constag.cpp
// Constants and aggregates
const int i[] = { 1, 2, 3, 4 };
//! float f[i[3]]; // Illegal
struct S { int i, j; };
const S s[] = { { 1, 2 }, { 3, 4 } };
//! double d[s[1].j]; // Illegal
int main() {} ///:~

Listado 8.2. C08/Constag.cpp

 

En la definición de un vector, el compilador debe ser capaz de generar código que mueva el puntero de pila para dar cabida al vector. En las definiciones incorrectas anteriores, el compilador se queja porque no puede encontrar una expresión constante en la definición del tamaño del vector.

8.1.4. Diferencias con C

Las constantes se introdujeron en las primeras versiones de C++ mientras la especificación del estándar C estaba siendo terminada. Aunque el comité a cargo de C decidió entonces incluir consten C, por alguna razón, vino a significar para ellos «una variable ordinaria que no puede cambiarse». En C, una constante siempre ocupa espacio de almacenamiento y su ámbito es global. El compilador C no puede tratar const como una constante en tiempo de compilación. En C, si escribe:

const int bufsize = 100;
char buf[bufsize];

aparecerá un error, aunque parezca algo razonable. bufsize está guardado en algún sitio y el compilador no conoce su valor en tiempo de compilación. Opcionalmente puede escribir:

const int bufsize;

en C, pero no en C++, y el compilador C lo acepta como una declaración que indica que se almacenará en alguna parte. Como C utiliza enlace externo para las constantes, esa semántica tiene sentido. C++ utiliza normalmente enlace interno, así que, si quiere hacer lo mismo en C++, debe indicar expresamente que se use enlace externo usando extern.

extern const int bufsize;  // es declaración, no definición

Esta declaración también es válida en C.

En C++, const no implica necesariamente almacenamiento. En C, las constantes siempre necesitan almacenamiento. El hecho de que se necesite almacenamiento o no depende de cómo se use la constante. En general, si una constante se usa simplemente para reemplazar un número por un nombre (como hace #define), entonces no requiere almacenamiento. Si es así (algo que depende de la complejidad del tipo de dato y de lo sofisticación del compilador) los valores pueden expandirse en el código para conseguir mayor eficiencia después de la comprobación de los tipos, no como con#define. Si de todas formas, se necesita la dirección de una constante (aún desconocida, para pasarla a una función como argumento por referencia) o se declara como extern, entonces se requiere asignar almacenamiento para la constante.

En C++, una constante que esté definida fuera de todas las funciones tiene ámbito de archivo (es decir, es inaccesible fuera del archivo). Esto significa que usa enlace interno. Esto es diferente para el resto de identificadores en C++ (y que las constantes en C) que utilizan siempre enlace externo. Por eso, si declara una constante con el mismo nombre en dos archivos diferentes y no toma sus direcciones ni los define como extern, el compilador C++ ideal no asignará almacenamiento para la constante, simplemente la expandirá en el código. Como las constantes tienen implícito el ámbito a su archivo, puede ponerlas en un archivo de cabecera de C++ sin que origine conflictos en el enlace.

Dado que las constante en C++ utilizan por defecto enlace interno, no puede definir una constante en un archivo y utilizarla desde otro. Para conseguir enlace externo para la constante y así poder usarla desde otro archivo, debe definirla explícitamente como extern, algo así:

extern const int x = 1;  // definición, no declaración

Señalar que dado un identificador, si se dice que es extern, se fuerza el almacenamiento para la constante (aunque el compilador tenga la opción de hacer la expansión en ese punto). La inicialización establece que la sentencia es una definición, no una declaración. La declaración:

extern const int x;

en C++ significa que la definición existe en algún sitio (mientras que en C no tiene porqué ocurrir así). Ahora puede ver porqué C++ requiere que las definiciones de constantes incluyan la inicialización: la inicialización diferencia una declaración de una definición (en C siempre es una definición, aunque no esté inicializada). Con una declaración const extern, el compilador no hace expansión de la constante porque no conoce su valor.

La aproximación de C a las constantes es poco útil, y si quiere usar un valor simbólico en una expresión constante (que deba evaluarse en tiempo de compilación) casi está obligado a usar#define.

 

 

 

OPERADORES
Indican una acción específica. Pueden ser unarios (afecta a una única variable u operando), binarios (afectan a dos variables u operandos) o ternarios (afectan a tres variables u operandos).

Tipos

De asignación: x = y

De comparación: ==, !=, <=, >=, >, <

Aritméticos: +, -, /, *, % (% significa módulo o resto)
++: pre/post incremento
--: pre/postdecremento

Lógicos o booleanos: && (AND), || (OR), ! (NOT)

A nivel de bit: &, |, ^, ~, <<, >>

Compuestos +=, -=, *= , /=, %=

Condicionalescondición ? valor1 : valor2.
X=(a>=b)?1:0 significa si a>=b: x=1 sino x=0.

Para punteros: Referencia o dirección de memoria: p=&x
Desreferencia o contenido de la memoria: *p=x.

Sizeof: tamaño de una variable o tipo de dato.
x=sizeof(int) tamaño de x=4 (bytes).

Postfijos: [],{},(),.,->

 

Ficheros Estándar

Cuando se inicia la ejecución de un programa C se produce la apertura automàtica de tres ficheros, antes de que llegue a producirse la llamada a main(). Estos ficheros son la entrada estándar "stdin" (standard input, normalmente el teclado) la salida estàndar "stdout" (standard output, normalmente la pantalla de vídeo) y el fichero estàndar de salida de errores "stederr" (standard error, normalmente la pantalla de video).

 

Este encaminamiento normal de los ficheros estándar (pantalla y teclado por defecto), puede verse modificado a través del intérprete de comandos de Unix y reencaminado hacia ficheros, "tuberías" (pipes) o regiones de memoria compartida.

 

La librería estándar de E/S declara stdin, stdout y stderr como punteros a estructuras FILE para los ficheros de ejitrada estándar, salida estándar y fichero estándar de errores, respectivamente.

 

Las funciones getchar y putehar son macros, en lugar de auténticas funciones, definidas en como:

 

#define getchar() getc(stdin)

 

#define putchar(c) putc(c, stdout)

 

Hay que advertir que stdin, stdout y stderr son constantes y no pueden ser reasingnados mediante fopen como podrìa parecer natural.

 

stdout = fopen("myfile", "w");

 

no es un procedimiento válido para redireccionar la salida estándar al fichero myfile. Sin embargo,

 

freopen("myfile", "w", stdout);

 

Bibliografía