Algoritmo
Secuencia ordenada de pasos que resuelve un problema concreto. Caractersticas - Correccin (sin errores). - Precisin (ausencia de ambigedades). - Repetitividad (solucin genrica de un problema dado). - Finitud (nmero finito de rdenes no implica finitud). - Eficiencia (temporal [tiempo necesario] y espacial [memoria utilizada])
Programa
Implementacin de un algoritmo en un lenguaje de programacin
Datos de entrada
Programa
Instrucciones
Datos de salida
Conjunto ordenado de instrucciones que se dan al ordenador indicndole las operaciones o tareas que ha de realizar para resolver un problema.
Introduccin a la Programacin
-1-
Lenguajes de programacin
Una instruccin es un conjunto de smbolos que representa una orden para el ordenador: la ejecucin de una operacin con datos. Las instrucciones se escriben en un lenguaje de programacin: - Se forman con smbolos tomados de un determinado repertorio (componentes lxicos) - Se construyen siguiendo unas reglas precisas (sintaxis) Lenguaje mquina El nico que entiende directamente la CPU del ordenador Depende del modelo de ordenador Repertorio de instrucciones reducido (operaciones muy elementales) Muy difcil programar en l (en binario, con cadenas de ceros y unos) Lenguaje ensamblador Equivalente al lenguaje mquina, cada lnea de cdigo se traduce en una instruccin para la mquina. Le asocia mnemnicos a las operaciones que entiende la CPU Repertorio de instrucciones reducido (operaciones muy elementales) Programas difciles de entender Lenguajes de alto nivel Permiten que el programador exprese el procesamiento de datos de forma simblica, sin tener en cuenta los detalles especficos de la mquina. Independientes del modelo de ordenador Proporcionan un mayor nivel de abstraccin
Introduccin a la Programacin -2-
Ejemplos de lenguajes de programacin de alto nivel FORTRAN (FORmula TRANslation) 1957, IBM (John Backus) Orientado a la resolucin de problemas cientficos y tcnicos COBOL (COmmon Business Oriented Language) 1959, Codasyl (Committee on Data System Languages) Aplicaciones comerciales de gestin LISP (LISt Processing) 1959, John McCarthy (MIT) Procesamiento de datos no numricos (usado en IA) BASIC (Beginners All-purpose Symbolic Instruction Code) 1964, John Kemeny & Thomas Kurtz (Darmouth College) Lenguaje interactivo para principiantes Simula 1967, Ole-Johan Dahl & Krysten Nygaard (Noruega) Primer lenguaje de programacin orientada a objetos Pascal 1971, Niklaus Wirth Lenguaje estructurado diseado para aprender a programar C 1972, Denis Ritchie (Bell Labs) Lenguaje pequeo, flexible y eficiente Smalltalk 1972, Alan Kay (Xerox PARC) Origen de los interfaces WIMP (Windows, Icons, Mouse & Pull-down menus) PROLOG (PROgramming in Logic) 1972, Alain Colmerauer (Universidad de Marsella) Basado en Lgica (usado en IA) Ada 1980, US Department of Defense Basado en Pascal, muy usado en aplicaciones militares
Introduccin a la Programacin -3-
C++ 1983, Bjarne Stroustroup (AT&T Bell Labs) Extensin de C que permite la programacin orientada a objetos Java 1995, Sun Microsystems Similar a C++, aunque ms sencillo de aprender y usar. C# 2000, Microsoft Corporation Alternativa de Microsoft a Java, muy similar a ste
Clasificacin de los lenguajes de programacin de alto nivel Lenguajes imperativos: Los programas indican al ordenador de forma inequvoca los pasos a seguir para la resolucin de un problema. o Programacin estructurada: La estructura del texto del programa debe auxiliarnos para entender la funcin que realiza: estrategia divide y vencers (la resolucin de un problema se divide en tareas y, stas, en subtareas). Ejemplos: C, Pascal, Fortran... o Programacin orientada a objetos: Estilo de programacin que basa la estructura de un programa en mdulos deducidos de los tipos de objetos que manipula (en lugar de basarse en las tareas que el sistema debe realizar). Ejemplos: Smalltalk, C++, Java, C#... Lenguajes declarativos (funcionales y lgicos): Los programas se implementan como conjuntos de funciones (o reglas lgicas) cuya evaluacin nos dar el resultado deseado. Ejemplos: LISP, PROLOG...
Introduccin a la Programacin -4-
Introduccin a la Programacin
-5-
Introduccin a la Programacin
-6-
Traductores
Los traductores transforman programas escritos en un lenguaje de alto nivel en programas escritos en cdigo mquina:
Tipos de traductores Compiladores Generan un programa ejecutable a partir del cdigo fuente
Intrpretes Van analizando, traduciendo y ejecutando las instrucciones del programa una a una. No se traduce una instruccin hasta que la ejecucin de la anterior haya finalizado.
Herramientas de programacin
Editores, depuradores, profilers... IDEs (entornos integrados de desarrollo) Ejemplos Microsoft Visual Studio .NET Borland C++Builder/Delphi Eclipse
Introduccin a la Programacin -7-
Planificacin
Delimitacin del mbito del proyecto, estudio de viabilidad, anlisis de riesgos, estimacin de costos, planificacin temporal y asignacin de recursos.
Implementacin:
Adquisicin de componentes, creacin de los mdulos de la aplicacin en un lenguaje de programacin e integracin de los recursos necesarios para que el sistema funcione.
Depuracin y pruebas:
Comprobacin del funcionamiento de la aplicacin
Pruebas de unidad y de integracin, pruebas alfa, pruebas beta, test de aceptacin.
Verificacin (si se est realizando lo que se pretenda) Validacin (si se realiza lo correcto).
Introduccin a la Programacin: C
- 11 -
Historia de C
Ao 1963 CPL (Combined Programming Language) Universidades de Cambridge y Londres Simplificacin derivada de ALGOL 60 (no implementado) 1967 BCPL (Basic CPL [Combined Programming Language]) Martin Richards (Universidad de Cambridge) Lenguaje sin tipos creado como herramienta para la construccin de compiladores y sistemas operativos. 1970 B (BCPL simplificado) Ken Thompson(AT&T Bell Labs, New Jersey) Lenguaje sin tipos creado para el primer sistema UNIX (para la PDP-7 de Digital Equipment Corporation [DEC]) 1972 Creacin del lenguaje de programacin C Dennis Ritchie (AT&T Bell Labs, New Jersey) 1974 UNIX reescrito en C 1978 Brian W. Kernighan & Dennis Ritchie The C Programming Language Prentice Hall, ISBN 0-13-110370-9 1983 C++ Bjarne Stroustroup (AT&T Bell Labs, New Jersey) Extensin de C (programacin orientada a objetos) 1989 Estndar ANSI C #X3J11/99-090 aprobado por el American National Standards Institute 1989 Segunda edicin del libro de Kernighan & Ritchie 1995 Java James Gosling (Sun Microsystems) Similar a C++, aunque ms sencillo de aprender y usar 1997 Estndar ANSI C++ aprobado por el American National Standards Institute 2000 C# Microsoft Corporation Alternativa a Java (base de la plataforma .NET)
Introduccin a la Programacin: C - 12 -
Herramientas de programacin en C
Existen mltiples compiladores de C y muchos entornos integrados de desarrollo [IDEs: Integrated Development Environments]
http://www.microsoft.com/ Microsoft Visual Studio .NET http://gcc.gnu.org/ GCC GNU Compiler Collection
Aplicaciones en C
Datos de entrada Cdigo fuente (ANSI C) Cdigo mquina (.o|.obj) Compilacin Enlazado Ejecucin Resultados
Un programa puede tener miles (e incluso millones) de lneas de cdigo fuente. A medida que el programa va creciendo, ste sera inmanejable si no fusemos dividiendolo en mdulos mucho ms pequeos y manejables. Todos los programas en C consisten en una o ms funciones (fragmentos de cdigo que realizan tareas concretas). La ejecucin del programa escrito en C comienza en una funcin denominada main(), que siempre debe existir para que podamos crear un programa ejecutable. Una aplicacin se implementa como un conjunto de funciones a las que podemos llamar desde el programa principal (la funcin main). Las distintas funciones de nuestro programa, a su vez, pueden llamar a otras funciones cuando sea necesario. La biblioteca estndar de C define algunas funciones comunes que vienen implementadas para que podamos usarlas directamente (sin preocuparnos de su implementacin). Al compilar un programa en C, creamos el cdigo mquina correspondiente a la parte del programa que hayamos escrito nosotros. A continuacin, enlazamos nuestro cdigo mquina con el correspondiente a las funciones ya implementadas en bibliotecas para obtener un programa ejecutable.
Introduccin a la Programacin: C - 14 -
Programa de ejemplo
Cdigo fuente en C: Fichero programa.c
/* Mi primer programa en C */ #include <stdio.h> int main (int argc, char *argv) { printf(Hola); return 0; }
La primera lnea, entre /* y */, es un comentario (algo que no forma parte del cdigo del programa en s pero que se incluye como aclaracin para facilitar su lectura). La lnea #include <stdio.h> le indica al preprocesador de C que incluya en el programa el contenido del fichero de cabecera stdio.h, donde estn las declaraciones de las funciones estndar de entrada/salida en C. La lnea int main() define la cabecera de la funcion main, el punto donde comienza la ejecucin de un programa en C. Las llaves { } sirven para delimitar la secuencia de instrucciones que forman parte de la funcin main. La llamada a la funcin printf("Hola "); le indica al ordenador que muestre por pantalla el mensaje que se le indica entre comillas. La sentencia return indica el valor que devuelve la funcin main (por convencin, 0 indica que todo fue bien).
Introduccin a la Programacin: C - 15 -
Compilacin A continuacin tenemos que traducir nuestro programa escrito en C a un programa que pueda ejecutar directamente el ordenador:
cc programa.c
NOTA:
Segn el compilador de C que utilicemos, puede que tengamos que escribir gcc (GNU C), cl (Microsoft), wcc386 (Watcom), bcc o bcc32 (Borland).
Ejecucin Una vez compilado el programa, para ejecutarlo basta con escribir su nombre
programa
Introduccin a la Programacin: C
- 16 -
Introduccin a la Programacin: C
Caractersticas clave de C
Lenguaje de programacin de propsito general Lenguaje estructurado (como Pascal) Lenguaje pequeo Lenguaje muy eficiente Lenguaje portable (independiente de la mquina) A menudo es elegido para el desarrollo de software de sistemas: es un lenguaje de programacin de alto nivel caracterizado por su acusada proximidad a la mquina Origen de muchos de los lenguajes usados actualmente (C++, Java, C#...)
"No es una herramienta para tontos y nios. En manos de un artesano habilidoso es capaz de trabajar de forma potente pero delicada. Su posibilidad de causar un serio dao es tan obvia que ese peligro proporciona el nico mecanismo de seguridad; un sano respeto por lo que puede hacer su uso despreocupado!"
B. Cox, "Software ICs and Objective-C", Productivity Products International (ahora StepStone Inc.), 1985
Introduccin a la Programacin: C
- 18 -
Tipo de dato
Especificacin de un dominio (rango de valores) y de un conjunto vlido de operaciones a los que normalmente los traductores asocian un esquema de representacin interna propio.
Clasificacin de los tipos de datos En funcin de quin los define: Tipos de datos estndar Tipos de datos definidos por el usuario En funcin de su representacin interna: Tipos de datos escalares o simples Tipos de datos estructurados
Introduccin a la Programacin
- 19 -
El sistema binario slo emplea dos smbolos: 0 y 1 Un bit nos permite representar 2 smbolos diferentes: 0 y 1 Dos bits nos permiten codificar 4 smbolos: 00, 01, 10 y 11 Tres bits nos permiten codificar 8 smbolos distintos: 000, 001, 010, 011, 100, 101, 110 y 111 En general, con N bits podemos codificar 2N valores diferentes N
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
2N
2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
Si queremos representar X valores diferentes, necesitaremos N bits, donde N es el menor entero mayor o igual que log2 X
Introduccin a la Programacin - 20 -
Representacin de datos de tipo numrico Representacin posicional Un nmero se representa mediante un conjunto de cifras, cuyo valor depende de la cifra en s y de la posicin que ocupa en el nmero
NMEROS ENTEROS Ejemplo: Si utilizamos 32 bits para representar nmeros enteros, disponemos de 232 combinaciones diferentes de 0s y 1s: 4 294 967 296 valores. Como tenemos que representar nmeros negativos y el cero, el ordenador ser capaz de representar del 2 147 483 648 al +2 147 483 647. Con 32 bits no podremos representar nmeros ms grandes. 2 147 483 647 + 1 = 2 147 483 648 !!!
NMEROS REALES (en notacin cientfica) (+|) mantisa x 2exponente El ordenador slo puede representar un subconjunto de los nmeros reales (nmeros en coma flotante) Las operaciones aritmticas con nmeros en coma flotante estn sujetas a errores de redondeo.
Estndar IEEE 754 Precisin sencilla (bit de signo + 8 bits exponente + 23 bits mantisa) Precisin doble (bit de signo + 11 bits exponente + 52 bits mantisa)
Introduccin a la Programacin - 21 -
Representacin de textos Se escoge un conjunto de caracteres: alfabticos, numricos, especiales (separadores y signos de puntuacin), grficos y de control (por ejemplo, retorno de carro). Se codifica ese conjunto de caracteres utilizando n bits. Por tanto, se pueden representar hasta 2n smbolos distintos.
Ejemplos de cdigos normalizados
ASCII (American Standard Code for Information Interchange) - ANSI X3.4-1968, 7 bits (128 smbolos) - ISO 8859-1 = Latin-1, 8 bits (256 smbolos)
Introduccin a la Programacin
- 22 -
Caracteres Nmeros enteros Nmeros en coma flotante (32 bits) Nmeros en coma flotante de doble precisin (64 bits) Tipo nulo Punteros Direcciones de memoria
Modificadores
Tamao del dato
short long
Nmeros enteros
[unsigned] char, [unsigned] short, [unsigned] long
Tipo de dato
char unsigned char short unsigned short long unsigned long
int
El tipo de dato int es equivalente - al tipo de dato short en compiladores de 16 bits - al tipo de dato long en compiladores de 32 bits
unsigned int El tipo de dato unsigned int es equivalente - al tipo de dato unsigned short en compiladores de 16 bits - al tipo de dato unsigned long en compiladores de 32 bits
Introduccin a la Programacin: C
- 24 -
Literales enteros Los literales enteros pueden expresarse: - En decimal (base 10):
255
( 15*161 + 15 = 255)
Los literales enteros son de tipo int por defecto. Un literal entero es de tipo long si va acompaado del sufijo l o L:
123456789L es de tipo long
NOTA:
Operaciones con nmeros enteros Desbordamiento Si sobrepasamos el valor mximo que se puede representar con un tipo de dato entero, nadie nos avisa de ello: en la ejecucin de nuestro programa obtendremos un resultado incorrecto. Tipo
char short long
Para obtener el resultado correcto, hemos de tener en cuenta el rango de valores de cada tipo de dato, de tal forma que los resultados intermedios de un clculo siempre puedan representarse correctamente: Tipo
short long
Divisin por cero Si dividimos un nmero entero por cero, se produce un error en tiempo de ejecucin:
Divide error
La ejecucin del programa termina de forma brusca al intentar hacer la divisin por cero.
Introduccin a la Programacin: C
- 26 -
Tipo Espacio en Mnimo Mximo Dgitos de dato memoria (valor absoluto) (valor absoluto) significativos
float double long double
6 15 18
Por defecto, los literales reales representan valores de tipo double Para representar un valor de tipo float, hemos de usar el sufijo f o F:
123.45F 0.0f .001f
Introduccin a la Programacin: C
- 27 -
Operaciones con nmeros en coma flotante Segn el estndar IEEE 754, las operaciones aritmticas en coma flotante pueden dar como resultado valores especiales: - Cuando el resultado de una operacin est fuera de rango, se obtiene +Inf o Inf (infinito). - Cuando el resultado de una operacin est indeterminado, se obtiene NaN (Not a Number) El estndar IEEE 754 establece los siguientes resultados: Operacin 1.0 / 0.0 -1.0 / 0.0 0.0 / 0.0 Resultado
+Inf -Inf NaN
No obstante, en funcin del compilador que utilicemos, puede que nos encontremos con un error en tiempo de ejecucin:
Floating point error: Domain. Abnormal program termination
O bien:
Floating point error: Divide by 0. Abnormal program termination
Precisin Las operaciones en coma flotante no son exactas debido a la forma en que se representan los nmeros reales en el ordenador Operacin 1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1 1.0 - 0.9 Resultado
0.5000000000000001 0.09999999999999998
Introduccin a la Programacin: C
- 28 -
Operadores aritmticos C incluye cinco operadores para realizar operaciones aritmticas: Operador
+ * / %
Operacin Suma Resta o cambio de signo Multiplicacin Divisin Mdulo (resto de la divisin)
- Si los operandos son enteros, se realizan operaciones enteras. - En cuanto uno de los operandos es de tipo float, double, o long double, la operacin se realiza en coma flotante. - No existe un operador de exponenciacin: para calcular xy hay que utilizar la funcin pow(x,y) que se encuentra en math.h Divisin (/) Operacin 7/3 7 / 3.0f 5.0 / 2 7.0 / 0.0 0.0 / 0.0 Tipo
int float double double double
Resultado
2 2.333333333f 2.5 +Inf NaN
- Si se dividen enteros, el resultado es entero y el resto se pierde. - Una divisin entera por cero produce un error. - Una divisin por cero, en coma flotante, produce Inf o NaN.
Mdulo (%): Resto de dividir nmeros enteros (no puede usarse con nmeros en coma flotante) Operacin 7%3
Introduccin a la Programacin: C
Tipo
int
- 29 -
Resultado
1
Expresiones aritmticas Se pueden combinar literales y operadores para formar expresiones complejas.
Ejemplo
- Las expresiones aritmticas se evalan de izquierda a derecha. - Los operadores aritmticos mantienen el orden de precedencia habitual (multiplicaciones y divisiones antes que sumas y restas). - Para especificar el orden de evaluacin deseado, se utilizan parntesis. NOTA: Es recomendable utilizar parntesis para eliminar interpretaciones errneas y posibles ambigedades
Caracteres
char, unsigned char
Tipo Espacio en de dato memoria char 8 bits Literales de tipo carcter Valores entre comillas simples
a b c 1 2 3
Codificacin ASCII
Cdigos ASCII (en hexadecimal): \x?? \x0a (avance de lnea) \x0d (retorno de carro) Secuencias de escape para representar caracteres especiales: Secuencia de escape \t \n \r \b \f \a \ \ \\ \? \0
Descripcin Tabulador (tab) Avance de lnea (new line) Retorno de carro (carriage return) Retroceso (backspace) Salto de pgina (form feed) Sonido de alerta Comillas simples (apstrofe) Comillas dobles Barra invertida Signo de interrogacin Carcter nulo (NULL)
Cadenas de caracteres en C
En ANSI C no existen las cadenas de caracteres como tipo predefinido: una cadena de caracteres no es ms que un vector de caracteres
Las secuencias de escape son necesarias para introducir determinados caracteres dentro de una cadena:
\Esto es una cadena entre comillas\
Formacin de cadenas de caracteres Para construir cadenas de caracteres en las que mostrar datos, se utilizan plantillas que se sustituirn por una representacin adecuada de los valores del tipo indicado: Plantilla %c %s %d %o %x %ld %f %lf %Lf
Introduccin a la Programacin: C
Tipo de dato
char
Cadena de caracteres int (en decimal) int (en octal) int (en hexadecimal)
long float double long double
- 32 -
Expresiones de tipo booleano Se construyen a partir de expresiones de tipo numrico con operadores relacionales. Se construyen a partir de otras expresiones booleanas (que en C son expresiones de tipo entero) con operadores lgicos.
Operadores relacionales - Operadores de comparacin vlidos para nmeros y caracteres - Generan un resultado de tipo int que interpretamos como booleano
Operador
== != < > <= >=
Introduccin a la Programacin: C
- 33 -
Operadores lgicos/booleanos - Operandos booleanos. - Tienen menos precedencia que los operadores de comparacin. Operador Nombre ! NOT && AND || OR ^ XOR Significado Negacin lgica y lgico o inclusivo o exclusivo
Tablas de verdad X
0 1
!X
1 0
A
0 0 1 1
B
0 1 0 1
A&&B
0 0 0 1
A||B
0 1 1 1
A^B
0 1 1 0
- NOT (!) cambia el valor booleano. - AND (&&) devuelve verdadero si los dos son operandos son verdaderos. No evala el segundo operando si el primero es falso - OR (||) devuelve falso si los dos operandos son falsos. No evala el segundo operando si el primero es verdadero - XOR (^) devuelve verdadero si los dos operandos son diferentes. Con operandos booleanos es equivalente a != Ejemplos Nmero x entre 0 y 10 Nmero x fuera del intervalo [0,10] o bien
Introduccin a la Programacin: C - 34 -
(0 <= x) && (x <= 10) !((0 <= x) && (x <= 10)) (0 > x) || (x > 10)
Extra: Operadores a nivel de bits - Se pueden utilizar a nivel de bits con nmeros enteros. - No se pueden usar con datos de otro tipo (p.ej. reales).
Los operadores NOT (~), AND (&), OR(|) y XOR (^) - NOT (~) realiza el complemento a 1 de un nmero entero: Cambia los 0s por 1s y viceversa - AND(&), OR(|) y XOR(^) funcionan a nivel de bits como los operadores booleanos AND (&&), OR(||) y XOR (^), respectivamente.
A nivel de bits
~000001010 (111110101) 000001010 & 00001 (000000000) 000001010 & 00010 (000000010) 000001010 & 00011 (000000010) 000001010 | 00001 (000001011) 000001010 | 00010 (000001010) 000001010 | 00011 (000001011) 000001010 ^ 00001 (000001011) 000001010 ^ 00010 (000001000) 000001010 ^ 00011 (000001001)
Resultado
-11 0 2 2 11 10 11 11 8 9
Introduccin a la Programacin: C
- 35 -
Los operadores de desplazamiento <<, >> y >>> - El operador de desplazamiento a la izquierda (<<) desplaza los bits del primer operando tantas posiciones a la izquierda como indica el segundo operando. Los nuevos bits se rellenan con ceros. - El operador de desplazamiento a la derecha (>>) desplaza los bits del primer operando tantas posiciones a la derecha como indica el segundo operando. Los nuevos bits se rellenan con unos (si el primer operando es negativo) y con ceros (si es positivo).
A nivel de bits
00001010 << 1 (0010100) 00000111 << 3 (00111000) 00001010 >> 1 (00000101) 00011011 >> 3 (0000011) 11001110 >> 2 (11110011) 111001110 << 2 (11100111000)
Resultado
20 (==10*2) 56 (==7*23) 5 (==10/2) 3 (==27/23) -13 (!=-50/22) -200 (==-50*22)
x<<b es equivalente a
multiplicar por 2b
x>>b es equivalente a
Introduccin a la Programacin: C
- 36 -
Variables
Una variable no es ms que un nombre simblico que identifica una direccin de memoria:
Declaracin de variables Para usar una variable en un programa hay que declararla. - El ordenador conoce as cmo codificar la informacin que se va a almacenar en la posicin de memoria correspondiente. - Al declarar una variable, se reserva el espacio de memoria necesario para almacenar un valor del tipo de la variable. - El identificador asociado a la variable se puede utilizar para acceder al dato almacenado en memoria y para modificarlo.
Introduccin a la Programacin - 37 -
Declaracin de variables en C
<tipo> identificador; <tipo> lista de identificadores;
Las variables se han de declarar antes de poder usarlas. Los identificadores de las variables son los nombres que utilizaremos para referirnos a ellas. Al declarar una variable, hay que definir su tipo: la variable slo admitir valores del tipo especificado. En una misma declaracin se pueden declarar varias variables, siempre que sean del mismo tipo. En este caso, los identificadores de las variables se separan por comas.
Introduccin a la Programacin: C
- 38 -
Identificadores en C El primer smbolo del identificador ser un carcter alfabtico (a, , z, A, , Z, _) pero no un dgito. Despus de ese primer carcter, podremos poner caracteres alfanumricos (letras del alfabeto ingls o dgitos decimales) y guiones de subrayado (_). Los identificadores no pueden coincidir con las palabras reservadas, que ya tienen significado en C:
auto const enum goto else sizeof register unsigned break continue extern if return static switch void case default float int short struct typedef volatile char do for long signed double union while
Las maysculas y las minsculas se consideran diferentes. El guin de subrayado (_) se interpretan como una letra ms. Ejemplos vlidos
a, pepe, r456, tu_re_da, AnTeNa, antena
Ejemplos no vlidos
345abc caada mi variable camin Nombre.Largo usd$
Convenciones Los identificadores deben ser descriptivos: deben hacer referencia al significado de aquello a lo que se refieren.
int n1, n2; int anchura, altura; // MAL // BIEN
Cuando el identificador est formado por varias palabras, la primera palabra va en minsculas y el resto de palabras se inician con una letra mayscula (o bien se separan las distintas palabras por guiones de subrayado).
int mayorvalor; int mayor_valor; int mayorValor; // MAL // BIEN // BIEN
NOTA:
La inicializacin puede consistir en una expresin compleja que se evala cuando se ejecuta el programa.
- 40 -
Introduccin a la Programacin: C
Definicin de constantes en C
Una constante hace referencia a un valor que no puede modificarse
Si el identificador est formado por varias palabras, las distintas palabras se separan con un guin de subrayado
#define RETORNO_DE_CARRO \n #define ELECTRONIC_CHARGE 1.6E-19
Expresiones y sentencias
Expresin
Construccin (combinacin de tokens) que se evala para devolver un valor.
Sentencia
Representacin de una accin o una secuencia de acciones. En C, todas las sentencias terminan con un punto y coma [;].
Construccin de expresiones
Literales y variables son expresiones primarias:
1.7 sum // Literal real de tipo double // Variable
- Los literales se evalan a s mismos. - Las variables se evalan a su valor. Los operadores nos permiten combinar expresiones primarias y otras expresiones formadas con operadores:
1 + 2 + 3*1.2 + (4 +8)/3.0
Los operadores se caracterizan por: - El nmero de operandos (unarios, binarios o ternarios). - El tipo de sus operandos (p.ej. numricos o booleanos). - El tipo del valor que generan como resultado.
Introduccin a la Programacin: C - 42 -
Descripcin Cambio de signo Operador NOT Complemento a 1 Descripcin Operadores aritmticos Operadores relacionales Operadores booleanos Operadores a nivel de bits
Descripcin Operadores aritmticos Operadores de igualdad Operadores de comparacin Operadores booleanos Operadores a nivel de bits
Descripcin Operadores aritmticos Operadores relacionales Operadores booleanos Operadores a nivel de bits
Introduccin a la Programacin: C
- 43 -
Sentencias de asignacin
Las sentencias de asignacin constituyen el ingrediente bsico en la construccin de programas con lenguajes imperativos.
Sintaxis:
<variable> = <expresin>;
Al ejecutar una sentencia de asignacin: 1. Se evala la expresin que aparece a la derecha del operador de asignacin (=). 2. El valor que se obtiene como resultado de evaluar la expresin se almacena en la variable que aparece a la izquierda del operador de asignacin (=).
Restriccin: El tipo del valor que se obtiene como resultado de evaluar la expresin ha de ser compatible con el tipo de la variable.
Ejemplos
x = x + 1;
Efectos colaterales
Al evaluar una expresin, algunos operadores provocan efectos colaterales (cambios en el estado del programa; es decir, cambios en el valor de alguna de las variables del programa).
Operadores de incremento (++) y decremento (--) El operador ++ incrementa el valor de una variable. El operador -- decrementa el valor de una variable. El resultado obtenido depende de la posicin relativa del operando: Operador
x++ ++x x---x
Descripcin Post-incremento Evala primero y despus incrementa Pre-incremento Primero incrementa y luego evala Post-decremento Evala primero y luego decrementa Pre-decremento Primero decrementa y luego evala Equivalencia
i=0; i=i+1; i=1; i=i+1; j=i; i=1; j=i; i=i+1; i=3; i=i+1; n=2*i; i=3; n=2*i; i=i+1; i=1; i=i+1; k=i+i;
Ejemplo
i=0; i++; i=1; j=++i; i=1; j=i++; i=3; n=2*(++i); i=3; n=2*(i++); i=1; k=++i+i;
Resultado
i=1; j=2; j=1; n=8; n=6; k=4;
El uso de operadores de incremento y decremento reduce el tamao de las expresiones pero las hace ms difciles de interpretar. Es mejor evitar su uso en expresiones que modifican mltiples variables o usan varias veces una misma variable.
Introduccin a la Programacin: C
- 45 -
Operadores combinados de asignacin (op=) C define 10 operadores que combinan el operador de asignacin con otros operadores (aritmticos y a nivel de bits): Operador
+= -= *= /= %= &= |= ^= <<= >>=
Ejemplo
i f n n n k k k x x += 1; -= 4.0; *= 2; /= 2; %= 2; &= 0x01; |= 0x02; ^= 0x04; <<= 1; >>= 2;
Equivalencia
i++; f = f n = n n = n n = n k = k k = k k = k x = x x = x 4.0; * 2; / 2; % 2; & 0x01; & 0x02; & 0x04; << 1; >> 2;
OJO:
Las expresiones con y sin operadores combinados de asignacin no son siempre equivalentes.
Ejemplo
v[i++]+= 2; y v[i++]=v[i++]+2; no son equivalentes.
Introduccin a la Programacin: C - 46 -
Conversin de tipos
En determinadas ocasiones, nos interesa convertir el tipo de un dato en otro tipo para poder operar con l. Ejemplo Convertir un nmero entero en un nmero real para poder realizar divisiones en coma flotante C permite realizar conversiones entre datos de tipo numrico (enteros y reales), as como trabajar con caracteres como si fuesen nmeros enteros: - La conversin de un tipo con menos bits a un tipo con ms bits es automtica (vg. de short a long, de float a double), ya que el tipo mayor puede almacenar cualquier valor representable con el tipo menor (adems de valores que no caben en el tipo menor). - La conversin de un tipo con ms bits a un tipo con menos bits se realizar de forma explcita con castings. Como se pueden perder datos en la conversin, un buen compilador de C nos avisa de posibles conversiones errneas (warnings)
int i; char b; i = 13; b = 13; b = i; // No se realiza conversin alguna // Se permite porque 13 est dentro // del rango permitido de valores // Podra ser un error // Fuerza la conversin // Almacena 14 en i // Sigue almacenando 14
Introduccin a la Programacin: C
- 47 -
Castings Para realizar una conversin explcita de tipo (un casting) basta con poner el nombre del tipo deseado entre parntesis antes del valor que se desea convertir:
char short long double c; x; k; d;
Introduccin a la Programacin: C
- 48 -
Algunas conversiones de inters De nmeros en coma flotante a nmeros enteros Al convertir de nmero en coma flotante a entero, el nmero se trunca (redondeo a cero). En la biblioteca math.h existen funciones que nos permiten realizar el redondeo de otras formas:
floor(x), ceil(x)
Conversin entre caracteres y nmeros enteros Como cada carcter tiene asociado un cdigo ASCII, los caracteres pueden interpretarse como nmeros enteros
int i; char c;
Ejemplo
i c c c = = = = a; 97; a+1; i+2;
Equivalencia
i c c c = = = = (int) a; (char) 97; (char) ((int)a+1); (char) (i+2);
Resultado
i c c c = = = = 97 a b c
Evaluacin de expresiones
- La precedencia de los operadores determina el orden de evaluacin de una expresin (el orden en que se realizan las operaciones): 3*4+2 es equivalente a (3*4)+2 porque el operador * es de mayor precedencia que el operador +
- Cuando en una expresin aparecen dos operadores con el mismo nivel de precedencia, la asociatividad de los operadores determina el orden de evaluacin. a b + c d es equivalente a ((a b) + c) d porque los operadores aritmticos son asociativos de izquierda a derecha a = b += c = 5 es equivalente a a = (b += (c = 5)) porque los operadores de asignacin son asociativos de derecha a izquierda
- La precedencia y la asociatividad determinan el orden de los operadores, pero no especifican el orden en que se evalan los operandos de un operador binario (un operador con dos operandos): En C, los operandos se evalan de izquierda a derecha: el operando de la izquierda se evala primero. Si los operandos no tienen efectos colaterales (esto es, no cambian el valor de una variable), el orden de evaluacin de los operandos es irrelevante.
NOTA: Siempre es recomendable el uso de parntesis. Los parntesis nos permiten especificar el orden de evaluacin de una expresin, adems de hacer su interpretacin ms fcil.
Introduccin a la Programacin: C - 50 -
Programas
Estructura de un programa simple
Los programas ms simples escritos en lenguajes imperativos suelen realizar tres tareas de forma secuencial: Entrada de datos Procesamiento de los datos Salida de resultados
La funcin main
El punto de entrada de un programa en C es la funcin main:
int main (int argc, char *argv[]) {
Las llaves {} delimitan bloques de cdigo en C (conjuntos de declaraciones y sentencias). La ejecucin de un programa escrito en C comienza invocando a la funcin main().
Introduccin a la Programacin: C
- 51 -
El preprocesador de C
#include Inclusin de ficheros de cabecera
#include <stdio.h> #include biblioteca.h
#ifndef #endif Usado en ficheros de cabecera para no incluir lo mismo dos veces
#ifndef __XXX__ #define __XXX__ ... #endif
Introduccin a la Programacin: C
- 52 -
Operaciones de entrada/salida
Salida por pantalla con la funcin printf La funcin printf, que forma parte de la biblioteca estndar de funciones de entrada/salida <stdio.h>, nos permite mostrar mensajes de texto en la pantalla cuando ejecutamos un programa:
#include <stdio.h> int main (int argc, char *argv[]) { ... printf(Mi programa v1.0); ... }
Entrada desde el teclado con la funcin scanf La funcin scanf, de la biblioteca estndar de funciones de entrada/salida <stdio.h>, nos permite leer datos desde el teclado para suministrarle datos de entrada a un programa:
#include <stdio.h> int main (int argc, char *argv[]) { ... scanf(%d,&dato); ... }
Operaciones de entrada/salida
printf(plantilla de formato, lista de variables); scanf(plantilla de formato, lista de referencias a variables);
Introduccin a la Programacin: C
- 55 -
Salida de datos con formato Al representar un nmero o una cadena, podemos especificar cmo deseamos hacerlo:
Sintaxis general
%-n.mX
El nmero n indica el nmero de caracteres que se utilizarn como mnimo para reprentar el dato (nmero total de dgitos en el caso de los nmeros, tanto enteros como reales). El nmero .m indica el nmero mximo de caracteres que se utilizarn para representar el dato. En el caso de los nmeros reales, indica el nmero de decimales que se mostrarn. El signo menos (-) es opcional y lo usaremos para indicar que el texto ha de justificarse a la izquierda. X indica el tipo del dato:
%d %x %o %c %s %f %e
Nmero entero en decimal Nmero entero en hexadecimal Nmero entero en octal Carcter Cadena de caracteres Nmero real Nmero real en notacin cientfica
Introduccin a la Programacin: C
- 56 -
Ejemplos
Introduccin a la Programacin: C
- 57 -
Ejemplo
Longitud de la hipotenusa de un tringulo rectngulo
/* Hipotenusa de un tringulo rectngulo calculada segn el teorema de Pitgoras */ #include <stdio.h> #include <math.h> int main () { // Declaraciones float lado1, lado2, hipotenusa; // Entrada de datos printf( Clculo de la hipotenusa \n); printf(de un tringulo rectngulo\n); printf(--------------------------\n); printf(Primer lado: ); scanf(%f, &lado1); printf(Segundo lado: ); scanf(%f, &lado2); // Clculos hipotenusa = sqrt(lado1*lado1 + lado2*lado2); // Salida de resultados printf (La hipotenusa mide %f.\n, hipotenusa); return 0; }
Introduccin a la Programacin: C
- 58 -
Ejemplo
Programa para comprobar si un ao es bisiesto o no Un ao es bisiesto si es divisible por 4 pero no por 100, o bien es divisible por 400.
#include <stdio.h> int main () { // Declaracin de variables int year; int bisiesto; // Entrada de datos printf(Introduzca un ao: ); scanf(%d, &year); // Clculos bisiesto = ((year%4==0) && (year%100!=0)) || (year%400==0); // Salida de resultados if (bisiesto) { printf (El ao es bisiesto.); } else { printf (El ao no es bisiesto.); } return 0; }
NOTA: La sentencia if nos permite controlar la ejecucin de un conjunto de sentencias en funcin de que se cumpla una condicin.
Introduccin a la Programacin: C - 59 -
Ejemplo
Cuota de una hipoteca intersMensual () = intersAnual / 12
cuotaMensual = cantidad 1 1 (1 + ) aos12
#include <stdio.h> #include <math.h> int main () { // Declaracin de variables double double int double cantidad; interes; tiempo; cuota; // // // // en en en en euros porcentaje (anual) aos euros (mensual)
double interesMensual; // en tanto por uno // Entrada de datos printf("Importe de la hipoteca (): "); scanf("%lf", &cantidad); printf("Tipo de inters (%): "); scanf("%lf", &interes); printf("Perodo de amortizacin (aos)"); scanf("%d", &tiempo); // Clculo de la cuota mensual interesMensual = interes/(12*100); cuota = (cantidad*interesMensual) / (1.0 - 1/pow(1+interesMensual,tiempo*12)); // Resultado printf("Cuota mensual: %.2lf ", cuota); } return 0;
- 60 -
Introduccin a la Programacin: C
Es bueno incluir comentarios que expliquen lo que hace el programa y sus caractersticas claves (p.ej. autor, fecha, algoritmos utilizados, estructuras de datos, peculiaridades).
// Clculo del MCD // usando el algoritmo de Euclides // Fernando Berzal, 2004
Los comentarios nunca han de limitarse a decir en lenguaje natural lo que ya est escrito en el cdigo: Jams se utilizarn para parafrasear el cdigo y repetir lo que es obvio.
i++; // Incrementa el contador
Los comentarios han de aclarar; esto es, ayudar al lector en las partes difciles (y no confundirle). Si es posible, escriba cdigo fcil de entender por s mismo: cuanto mejor lo haga, menos comentarios necesitar.
int mes; int mes; // Mes // Mes del ao (1..12)
ax = 0x723;
/* RIP L.v.B. */
Sangras Conviene utilizar espacios en blanco o separadores para delimitar el mbito de las estructuras de control de nuestros programas. Lneas en blanco Para delimitar claramente los distintos segmentos de cdigo en nuestros programas dejaremos lneas en blanco entre ellos. Identificadores Los identificadores deben ser descriptivos (reflejar su significado).
p, i, s... precio, izquierda, suma...
Declaraciones Usualmente, declararemos una nica variable por lnea. Nunca mezclaremos en una misma lnea la declaracin de variables que sean de distintos tipos o que se utilicen en el programa para distintos fines. Constantes Se considera una mala costumbre incluir literales de tipo numrico (nmeros mgicos) en medio del cdigo. Se prefiere la definicin de constantes simblicas (mediante la directiva #define del preprocesador de C).
Introduccin a la Programacin: C
- 62 -
Expresiones Uso de parntesis: Aunque las normas de precedencia de los operadores vienen definidas en el lenguaje, no abusaremos de ellas. Siempre resulta ms fcil interpretar una expresin si sta tiene los parntesis apropiados. Adems, stos eliminan cualquier tipo de ambigedad. Uso de espacios en blanco: Resulta ms fcil leer una expresin con espacios que separen los distintos operadores y operandos involucrados en la expresin.
a%x*c/b-1 ( (a%x) * c ) / b - 1
Expresiones complejas: Es aconsejable dividirlas para mejorar su legibilidad Claridad: Siempre buscaremos la forma ms simple de escribir una expresin.
key = key >> ( bits ((bits>>3)<<3)); key >>= bits & 0x7;
Conversiones de tipo (castings): Evitaremos las conversiones implcitas de tipo. Cuando queramos realizar una conversin de tipo, lo indicaremos explcitamente.
i = (int) f;
Siempre se han de evitar los efectos colaterales (modificaciones no deseadas pueden afectar a la ejecucin del programa sin que nos demos cuenta de ello).
Introduccin a la Programacin: C - 63 -
IDEA CLAVE Escribimos cdigo para que lo puedan leer otras personas, no slo para que lo traduzca el compilador (si no fuese as, podramos seguir escribiendo nuestros programas en binario).
No comente el cdigo malo (uso de construcciones extraas, expresiones confusas, sentencias poco legibles...): Reescrbalo. No contradiga al cdigo: Los comentarios suelen coincidir con el cdigo cuando se escriben, pero a medida que se corrigen errores y el programa evoluciona, los comentarios suelen dejarse en su forma original y aparecen discrepancias. Si cambia el cdigo, asegrese de que los comentarios sigan siendo correctos.
El cdigo bien escrito es ms fcil de leer, entender y mantener (adems, seguramente tiene menos errores)
Errores de programacin
Errores sintcticos Errores detectados por el compilador en tiempo de compilacin. Errores semnticos Slo se detectan en tiempo de ejecucin: Causan que el programa finalice inesperadamente su ejecucin (p.ej. divisin por cero) o que el programa proporcione resultados incorrectos.
Introduccin a la Programacin: C - 64 -
Elementos lxicos de C
Token
Componente lxico de un lenguaje de programacin
Palabra reservada
Palabra que tiene un significado concreto en el lenguaje de programacin, sin necesidad de que se lo asignemos nosotros. auto const enum goto else sizeof register unsigned break continue extern if return static switch void case default float int short struct typedef volatile char do for long signed double union while
Identificador
Palabra que podemos utilizar para denominar algo en el lenguaje. Identificadores en C - El primer smbolo del identificador ser un carcter alfabtico (a, , z, A, , Z, _). Despus de ese primer carcter podremos poner caracteres alfanumricos (a, , z) y (0, 1, , 9) y el guin de subrayado _. - Las maysculas y las minsculas se consideran diferentes. - El guin de subrayado se interpreta como una letra ms. - Los identificadores no pueden coincidir con las palabras reservadas. Ejemplos vlidos a, pepe, r456, tu_re_da, AnTeNa, antena Ejemplos no vlidos 345abc, mi variable, Nombre.Largo, caada, camin
Introduccin a la Programacin: C - 66 -
Literal
Especificacin de un valor concreto de un tipo de dato. Nmeros 3 3.1416 u|U l|L f|F 0 0x 0.31416e1 0.31416e+1 .31416e1f (unsigned) (long) (float) (octal) (hexadecimal)
Sufijos:
Prefijos:
Secuencias de escape \a \b \f \n \r \t \v \\ \' \" \? \O \xH \XH vg: \0 0x07 0x08 0x0C 0x0A 0x0D 0x09 0x0B 0x5c 0x27 0x22 0x3F BEL BS FF LF CR HT VT \ ' " ? Sonido de alerta Retroceso (Backspace) Salto de pgina (Form feed) Salto de lnes (Line feed) = Nueva lnea Retorno de carro Tabulador horizontal Tabulador vertical Barra invertida (Backslash) Apstrofe = Comilla simple Comillas = Comilla doble Signo de interrogacin O = Cadena de dgitos octales H = Cadena de dgitos hexadecimales H = Cadena de dgitos hexadecimales Carcter nulo
NULL
Operador
Igual que en Matemticas, realizan una accin especfica: - Suelen estar definidos en el ncleo del compilador (aunque tambin pueden estar definidos en bibliotecas externas) - Suelen representarse con tokens formados por smbolos. - Suelen utilizar notacin infija. - Pueden aplicarse a uno o varios operandos (argumentos). - Suelen devolver un valor.
Delimitador
Smbolos utilizados como separadores de las distintas construcciones de un lenguaje de programacin (esto es, los signos de puntuacin de un lenguaje de programacin. [ ] ( ) { } , ; : ... * = #
Corchetes: Se utilizan para especificar los subndices de los arrays. Parntesis: Agrupan expresiones e indican los parmetros de las funciones. Llaves: Delimitan sentencias compuestas (bloques de cdigo). Comas: Separan los elementos de una lista. Punto y coma: Indica el final de una sentencia. Dos puntos: Etiquetas. Elipsis (...): Funciones con un nmero variable de argumentos. Asteriscos (*): Punteros Inicializador (=): Separa la declaracin de la inicializacin de variables. Almohadilla (#): Directivas del preprocesador.
Introduccin a la Programacin: C - 68 -
Comentario
Aclaracin que el programador incluye en el texto del programa para mejorar su inteligibilidad. Comentarios en C: Cualquier secuencia de caracteres que comience con /*. El comentario termina cuando se encuentra el par */. No se pueden introducir comentarios dentro de otros ANSI C tambin permite comentarios en una lnea (al estilo de C++): Estos comentarios comienzan con dos barras // y terminan al final de la lnea.
Introduccin a la Programacin: C
- 69 -
Apndices
Construccin de expresiones en C
Operador de asignacin = Operadores de comparacin == != >= <= > <
Operadores aritmticos + cast-expression - cast-expression add-expression + multiplicative-expression add-expression - multiplicative-expression multiplicative-expr * cast-expr multiplicative-expr / cast-expr multiplicative-expr % cast-expr postfix-expression ++ ++ unary-expression postfix-expression --- unary-expression Operadores booleanos logical-AND-expr && inclusive-OR-expression logical-OR-expr || logical-AND-expression ! cast-expression (postincremento) (preincremento) (postdecremento) (predecremento)
Introduccin a la Programacin: C
- 70 -
Operadores a nivel de bits AND-expression & equality-expression exclusive-OR-expr ^ AND-expression inclusive-OR-expr | exclusive-OR-expression ~cast-expression shift-expression << additive-expression shift-expression >> additive-expression Operadores compuestos de asignacin *= /= %= += -= <<= >>= &= ^= |=
Operador condicional logical-OR-expr ? expr : conditional-expr Operadores para el manejo de punteros & cast-expression * cast-expression Operadores postfijos postfix-expression(<arg-expression-list>) array declaration [constant-expression] compound statement { statement list } postfix-expression . identifier postfix-expression -> identifier El operador sizeof sizeof unary-expression sizeof (type-name)
Introduccin a la Programacin: C
- 71 -
De izquierda a derecha
De derecha a izquierda
Introduccin a la Programacin: C
- 72 -
Tipos de datos en C
Tipos de datos bsicos
char int float double void Punteros Caracteres Nmeros enteros Nmeros en coma flotante (32 bits) Nmeros en coma flotante de doble precisin (64 bits) Tipo nulo Direcciones de memoria
Arrays Como en Pascal Estructuras Como los registros de Pascal. Uniones Variables que pueden contener datos de distintos tipos.
Modificadores
Tamao de la variable short long signed unsigned register auto (por defecto) static extern (int por defecto) (int por defecto)
Modo de almacenamiento
Enumeraciones
enum [<identificador>] { <nombre_constante> [= <valor>], ... } [lista de variables];
typedef unsigned char byte; typedef struct { double real, imag; } complex;
Declaracin de variables
<tipo> <identificador> [= <init>] [, ...] ;
Ejemplos: int x; int y = 4; int x = 1, y = 2; int *p; int **int_ptr; long double v; complex i; enum day hoy; char ch; unsigned char c1, c2; char *str; char str[] = "ATD1"; int int int int vector[]; vector[3]; vector[3] = {1, 2, 3}; matriz[3][4];
Estructuras de control
Programacin estructurada Estructuras condicionales La sentencia if La clusula else Encadenamiento y anidamiento El operador condicional ?: La sentencia switch Estructuras repetitivas/iterativas El bucle while El bucle for El bucle dowhile Bucles anidados Cuestiones de estilo Vectores y matrices Algoritmos de ordenacin Algoritmos de bsqueda
Programacin estructurada
IDEA CENTRAL: Las estructuras de control de un programa slo deben tener un punto de entrada y un punto de salida.
La programacin estructurada... mejora la productividad de los programadores. mejora la legibilidad del cdigo resultante.
La ejecucin de un programa estructurado progresa disciplinadamente, en vez de saltar de un sitio a otro de forma impredecible
Gracias a ello, los programas resultan ms fciles de probar se pueden depurar ms fcilmente se pueden modificar con mayor comodidad
Estructuras de control - C
-1-
Secuencia Conjunto de sentencias que se ejecutan en orden Ejemplos: Sentencias de asignacin y llamadas a rutinas.
Seleccin Elige qu sentencias se ejecutan en funcin de una condicin. Ejemplos: Estructuras de control condicional if-then-else y case/switch
Iteracin Las estructuras de control repetitivas repiten conjuntos de instrucciones. Ejemplos: Bucles while, do...while y for.
Teorema de Bhm y Jacopini (1966): Cualquier programa de ordenador puede disearse e implementarse utilizando nicamente las tres construcciones estructuradas (secuencia, seleccin e iteracin; esto es, sin sentencias goto).
Bhm, C. & Jacopini, G.: Flow diagrams, Turing machines, and languages only with two formation rules. Communications of the ACM, 1966, Vol. 9, No. 5, pp. 366-371 Dijkstra, E.W.: Goto statement considered harmful. Communications of the ACM, 1968, Vol. 11, No. 3, pp. 147-148
Estructuras de control - C -2-
El orden secuencial de ejecucin no altera el flujo de control del programa respecto al orden de escritura de las instrucciones.
Sin embargo, al describir la resolucin de un problema, es normal que tengamos que tener en cuenta condiciones que influyen sobre la secuencia de pasos que hay que dar para resolver el problema:
Segn se cumplan o no determinadas condiciones, la secuencia de pasos involucrada en la realizacin de una tarea ser diferente
Las estructuras de control condicionales o selectivas nos permiten decidir qu ejecutar y qu no en un programa.
Estructuras de control - C
-3-
Condicin_1
Cierta
Cierta
Condicin_2
Falsa
Falsa
Bloque_1
Bloque_3
Bloque_
Bloque_2
Bloque_5
SIENTONCES
SIENTONCESSINO
Sintaxis
if (condicin) sentencia;
if (condicin) { bloque }
Consideraciones acerca del uso de la sentencia if - Olvidar los parntesis al poner la condicin del if es un error sintctico (los parntesis son necesarios) - Confundir el operador de comparacin == con el operador de asignacin = puede producir errores inesperados - Los operadores de comparacin ==, !=, <= y >= han de escribirse sin espacios. - => y =< no son operadores vlidos en C. - El fragmento de cdigo afectado por la condicin del if debe sangrarse para que visualmente se interprete correctamente el mbito de la sentencia if:
if (condicin) { // Aqu se incluye el cdigo // que ha de ejecutarse slo // si se cumple la condicin del if // (sangrado para que se vea dnde // empieza y dnde acaba el if) }
Error comn:
if (condicin); sentencia;
es interpretado como
if (condicin) ; // Sentencia vaca sentencia;
#include <stdio.h> int main (int argc, char *argv[]) { int x; printf(Dme un numero); scanf(%d,&x); if (x>0) { printf(El numero %d es positivo,x); } return 0; }
Estructuras de control - C
-6-
La clusula else
Una sentencia if, cuando incluye la clusula else, permite ejecutar un bloque de cdigo si se cumple la condicin y otro bloque de cdigo diferente si la condicin no se cumple.
Condicin_1
Cierta
Cierta
Condicin_2
Falsa
Falsa
Bloque_1
Bloque_3
Bloque_4
Bloque_2
Bloque_5
SIENTONCES
SIENTONCESSINO
Sintaxis
if (condicin) sentencia1; else sentencia2;
#include <stdio.h> void main () { int x; printf(Dme un numero: ); scanf(%d,&x); if (x>=0) { printf(El numero %d es positivo, x); } else { printf(El numero %d es negativo, x); } }
Encadenamiento
Las sentencias if se suelen encadenar:
if else if
#include <stdio.h> void main () { float nota; printf(Dme una nota: ); scanf(%f,¬a); if (nota>=9) { printf(Sobresaliente); } else if (nota>=7) { printf(Notable); } else if (nota>=5) { printf(Aprobado); } else { printf(Suspenso); } }
Anidamiento
Las sentencias if tambin se pueden anidar unas dentro de otras.
El operador condicional ?:
C proporciona una forma de abreviar una sentencia if
Sintaxis
condicin? expresin1: expresin2
equivale a
if (condicin) expresin1 else expresin2
Slo se evala una de las sentencias, por lo que deberemos ser cuidadosos con los efectos colaterales.
Ejemplos
max = (x>y)? x : y; min = (x<y)? x : y; med = (x<y)? ((y<z)? y: ((z<x)? x: z)): ((x<z)? x: ((z<y)? y: z));
Estructuras de control - C
- 11 -
Se selecciona a partir de la evaluacin de una nica expresin. La expresin del switch ha de ser de tipo entero. Los valores de cada caso del switch han de ser constantes. La etiqueta default marca el bloque de cdigo que se ejecuta por defecto (cuando al evaluar la expresin se obtiene un valor no especificado por los casos del switch). En C, se ejecutan todas las sentencias incluidas a partir del caso correspondiente, salvo que explcitamente usemos break:
switch (expresin) { case expr_cte1: sentencia1; break; case expr_cte2: case expr_cte3: sentenciaN; } switch (expresin) { case expr_cte1: sentencia1; break; case expr_cte2: sentencia2; break; default: sentencia; }
- 12 -
Estructuras de control - C
Ejemplo
#include <stdio.h> void main() { int nota; printf(Calificacin: ); scanf(%d, ¬a); switch (nota) { case case case case case 0: 1: 2: 3: 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(Matrcula); break; default: printf(Error); } }
Si trabajamos con datos de tipo real, tendremos que usar sentencias if encadenadas.
Estructuras de control - 13 -
Podramos escribir un programa en el que apareciese repetido el cdigo que deseamos que se ejecute varias veces, pero Nuestro programa podra ser demasiado largo. Gran parte del cdigo del programa estara duplicado, lo que dificultara su mantenimiento en caso de que tuvisemos que hacer cualquier cambio, por trivial que fuese ste. Una vez escrito el programa para un nmero determinado de repeticiones (p.ej. sumar matrices 3x3), el mismo programa no podramos reutilizarlo si necesitsemos realizar un nmero distinto de operaciones (p.ej. matrices 4x4).
Las estructuras de control repetitivas o iterativas, tambin conocidas como bucles, nos permiten resolver de forma elegante este tipo de problemas. Algunas podemos usarlas cuando conocemos el nmero de veces que deben repetirse las operaciones. Otras nos permiten repetir un conjunto de operaciones mientras se cumpla una condicin.
El bucle while
Condicin
Bloque
S No
MUY IMPORTANTE
En el cuerpo del bucle debe existir algo que haga variar el valor asociado a la condicin que gobierna la ejecucin del bucle.
Estructuras de control - C
- 15 -
Estructuras de control - C
- 16 -
// // // //
Nmero de datos Suma de los datos Nmero ledo desde el teclado Contador
printf (Nmero total de datos: ); scanf (%d,&total); suma = 0; // Inicializacin de la suma i = 0; // Inicializacin del contador while (i<total) { printf (Dato %d: , i); scanf (%lf,&n); suma = suma + n; i++; } printf (Suma total = %lf\n, suma); }
Tal como est implementado el programa, fcilmente podramos calcular la media de los datos (suma/total). EJERCICIO Ampliar el programa anterior para que, adems de la suma y de la media, nos calcule tambin el mximo, el mnimo, la varianza y la desviacin tpica de los datos. Pista:
Estructuras de control - C
En los ejemplos anteriores se conoce de antemano el nmero de iteraciones que han de realizarse (cuntas veces se debe ejecutar el bucle): En este caso, la expresin del while se convierte en una simple comprobacin del valor de una variable contador (una variable que se incrementa o decrementa en cada iteracin y nos permite contabilizar la iteracin en la que nos encontramos). En otras ocasiones, puede que no conozcamos de antemano cuntas iteraciones se han de realizar. Ejemplo Sumar una serie de nmeros hasta que el usuario introduzca un cero
#include <stdio.h> void main() { double suma; double n;
suma = 0; // Inicializacin de la suma printf (Introduzca un nmero (0 para terminar): ); scanf (%lf, &n); while (n!=0) { suma = suma + n; printf (Introduzca un nmero (0 para terminar): ); scanf (%lf, &n); } printf (Suma total = %lf\n, suma); }
El bucle for
Se suele emplear en sustitucin del bucle while cuando se conoce el nmero de iteraciones que hay que realizar. Sintaxis
for (exp1; exp2; exp3) { bloque; }
equivale a
Estructuras de control - C
#include <stdio.h> void main() { long i, n, factorial; printf ("Introduzca un nmero: "); scanf ("%ld", &n); factorial = 1; for (i=1; i<=n; i++) { factorial *= i; } printf ("factorial(%ld) = %ld", n, factorial); }
Bucle while
#include <stdio.h> void main() { long i, n, factorial; printf ("Introduzca un nmero: "); scanf ("%ld", &n); factorial = 1; i = 1; while (i<=n) { factorial *= i; i++; } printf ("factorial(%ld) = %ld", n, factorial); }
Estructuras de control - C - 20 -
En un bucle for La primera expresin, expr1, suele contener inicializaciones de variables separadas por comas. En especial, siempre aparecer la inicializacin de la variable que hace de contador. Las instrucciones que se encuentran en esta parte del for slo se ejecutarn una vez antes de la primera ejecucin del cuerpo del bucle (bloque). La segunda expresin, expr2, es la que contiene una expresin booleana (la que aparecera en la condicin del bucle while equivalente para controlae la ejecucin del cuerpo del bucle). La tercera expresin, expr3, contiene las instrucciones, separadas por comas, que se deben ejecutar al finalizar cada iteracin del bucle (p.ej. el incremento/decremento de la variable contador). El bloque de instrucciones bloque es el mbito del bucle (el bloque de instrucciones que se ejecuta en cada iteracin).
Estructuras de control - C
- 21 -
Nmero de iteraciones N
N+1
N-k
N+1
N-k
N/k
(N-j)/k
log2 N
log2 N + 1
Si nunca deja de cumplirse la condicin del bucle, nuestro programa se quedar indefinidamente ejecutando el cuerpo del bucle, sin llegar a salir de l.
Estructuras de control - C - 22 -
El bucle do while
Tipo de bucle, similar al while, que realiza la comprobacin de la condicin despus de ejecutar el cuerpo del bucle. Sintaxis
do sentencia; while (condicin);
El bloque de instrucciones se ejecuta al menos una vez. Especialmente indicado para validar datos de entrada (comprobar que los valores obtenidos estn dentro del rango de valores esperados).
Estructuras de control - C
- 23 -
IMPORTANTE
En todos nuestros programas debemos asegurarnos de que se obtienen datos de entrada vlidos antes de realizar cualquier tipo de operacin con ellos.
Estructuras de control - C
- 24 -
#include <stdio.h> #include <math.h> void main() { // Declaracin de variables double n; double r; double prev; // Nmero real // Raz cuadrada del nmero // Aproximacin previa de la raz
// Entrada de datos do { printf("Introduzca un nmero positivo: "); scanf("%lf", &n); } while (n<0); // Clculo de la raz cuadrada r = n/2; do { prev = r; r = (r+n/r)/2; } while (fabs(r-prev) > 1e-6); // Resultado printf("La raz cuadrada de %lf es %lf", n, r); }
NOTA: La funcin abs nos da el valor absoluto de un nmeo entero. Para trabajar con reales hemos de usar fabs.
Estructuras de control - C
- 25 -
Bucles anidados
Los bucles tambin se pueden anidar:
Ejemplo
#include <stdio.h> void main () { int n,i,k; n = 0; for (i=1; i<=2; i++) { for (k=5; k>=1; k-=2) { n = n + i + k; } } printf("N vale %d", n); }
Paso N i k 1 0 ? ? 1 5 3 1 1 2 3 4 6 5 3 4 10 5 3 4 12 2 5 3 1 1 5 3 6 2 3 4 19 5 3 4 24 5 3 4 27 3 5 3 6 2 7
Estructuras de control - C
- 26 -
Cuestiones de estilo
Escribimos cdigo para que lo puedan leer otras personas, no slo para que lo traduzca el compilador.
Identificadores
q
En ocasiones, se permite el uso de nombres cortos para variables locales cuyo significado es evidente (p.ej. bucles controlados por contador)
for (elemento=0; elemento<N; elemento++ ) for (i=0; i<N; i++)
Constantes
q
Se considera una mala costumbre incluir literales de tipo numrico (nmeros mgicos) en medio del cdigo. Se prefiere la definicin de constantes simblicas (con #define o, mejor an, con enum).
for (i=0; i<79; i++) for (i=0; i<columnas-1; i++)
Estructuras de control - C
- 27 -
Expresiones
q
max = (a > b) ? a : b;
Comentarios
q
Comentarios descriptivos: Los comentarios deben comunicar algo. Jams se utilizarn para parafrasear el cdigo y repetir lo que es obvio.
i++; /* Incrementa el contador */
Estructuras de control - C
- 28 -
Estructuras de control
q
Sangras: Conviene utilizar espacios en blanco o separadores para delimitar el mbito de las estructuras de control de nuestros programas. Lneas en blanco: Para delimitar claramente los distintos bloques de cdigo en nuestros programas dejaremos lneas en blanco entre ellos. Salvo en la cabecera de los bucles for, slo incluiremos una sentencia por lnea de cdigo. Sean cuales sean las convenciones utilizadas al escribir cdigo (p.ej. uso de sangras y llaves), hay que ser consistente en su utilizacin. while () { } while () { } for (;;) { } if () { }
for (;;) { }
if () { }
El cdigo bien escrito es ms fcil de leer, entender y mantener (adems, seguramente tiene menos errores)
Estructuras de control - C
- 29 -
Metodologa de la programacin
Ciclo de vida del software Fases del ciclo de vida: Anlisis, diseo, implementacin... Programacin estructurada Cuestiones de estilo Identificadores Constantes Expresiones Declaraciones Estructuras de control Comentarios Convenciones
Bibliografa
Steve McConnell: Code Complete. Estados Unidos: Microsoft Press, 1994. ISBN 1-55615-484-4. Brian W. Kernighan & Rob Pike: La prctica de la programacin. Mxico: Pearson Educacin, 2000. ISBN 968-444-418-4. Francisco J. Cortijo, Juan Carlos Cubero & Olga Pons: Metodologa de la Programacin. Granada: Proyecto Sur, 1993. ISBN 84-604-7652-9. C Style Guide. NASA Software Engineering Laboratory, August 1994. SEL-94-003
Programacin estructurada
IDEA CENTRAL: Las estructuras de control de un programa slo deben tener un punto de entrada y un punto de salida. La programacin estructurada... mejora la productividad de los programadores. mejora la legibilidad del cdigo resultante. La ejecucin de un programa estructurado progresa disciplinadamente, en vez de saltar de un sitio a otro de forma impredecible
En programacin estructurada slo se emplean tres construcciones: Secuencia Conjunto de sentencias que se ejecutan en orden (asignaciones y llamadas a rutinas) Seleccin Estructura de control condicional (if-then-else, case/switch) Iteracin Estructura de control repetitiva (bucles: while, do...while, for)
Teorema de Bhm y Jacopini (1966) Cualquier programa de ordenador puede disearse e implementarse utilizando nicamente las tres construcciones estructuradas (secuencia, seleccin e iteracin; esto es, sin sentencias goto).
Bhm, C. & Jacopini, G.: Flow diagrams, Turing machines, and languages only with two formation rules. Communications of the ACM, 1966, Vol. 9, No. 5, pp. 366-371 Dijkstra, E.W.: Goto statement considered harmful. Communications of the ACM, 1968, Vol. 11, No. 3, pp. 147-148
Cuestiones de estilo
IDEA Escribimos cdigo para que lo puedan leer otras personas, no slo para que lo traduzca el compilador (si no fuese as, podramos seguir escribiendo nuestros programas en binario).
Identificadores
q
Seleccin de los identificadores: Los identificadores deben ser descriptivos (reflejar su significado). p, i, s... precio, izquierda, suma...
Uso de minsculas y maysculas: Generalmente, resulta ms cmodo leer texto en minsculas, por lo que usaremos siempre identificadores en minsculas, salvo: - para construir identificadores compuestos (p.ej. otraVariable) y - para definir constantes simblicas y macros (con #define). En ocasiones, se permite el uso de nombres cortos para variables locales cuyo significado es evidente (p.ej. bucles controlados por contador) for (elemento=0; elemento<N; elemento++) ... for (i=0; i<N; i++) ...
Constantes
q
Se considera una mala costumbre incluir literales de tipo numrico (nmeros mgicos) en medio del cdigo. Se prefiere la definicin de constantes simblicas (con #define o, mejor an, con enum). for (i=0; i<79; i++)... for (i=0; i<columnas-1; i++)...
Expresiones
q
Uso de parntesis: Aunque las normas de precedencia de los operadores estn definidas por el estndar de C, no abusaremos de ellas. Siempre resulta ms fcil interpretar una expresin si sta tiene los parntesis apropiados. Adems, stos eliminan cualquier tipo de ambigedad. Uso de espacios en blanco: Resulta ms fcil leer una expresin con espacios que separen los distintos operadores y operandos involucrados en la expresin. a%x*c/b-1 ( (a%x) * c ) / b - 1
Expresiones booleanas: Es aconsejable escribirlas como se diran en voz alta. if ( !(bloque<actual) ) ... if ( bloque >= actual ) ...
Expresiones complejas: Es aconsejable dividirlas para mejorar su legibilidad (p.ej. operador ?:). x += ( xp = ( 2*k < (n-m) ? c+k: d-k )); if ( 2*k < n-m ) xp = c+k; else xp = d-k; x += xp; max = (a > b) ? a : b;
Claridad: Siempre buscaremos la forma ms simple de escribir una expresin. key = key >> ( bits ((bits>>3)<<3)); key >>= bits & 0x7;
Conversiones de tipo (castings): Evitaremos las conversiones implcitas de tipo. Cuando queramos realizar una conversin de tipo, lo indicaremos explcitamente. i = (int) f;
Declaraciones
q
Usualmente, declararemos una nica variable por lnea. Nunca mezclaremos en una misma lnea la declaracin de variables que sean de distintos tipos o que se utilicen en el programa para distintos fines. int i, datos[100], v[3], ok;
Estructuras de control
q
Sangras: Conviene utilizar espacios en blanco o separadores para delimitar el mbito de las estructuras de control de nuestros programas. Lneas en blanco: Para delimitar claramente los distintos bloques de cdigo en nuestros programas dejaremos lneas en blanco entre ellos.
Comentarios
q
Comentarios descriptivos: Los comentarios deben comunicar algo. Nunca han de limitarse a decir en lenguaje natural lo que ya est escrito en el cdigo. Jams se utilizarn para parafrasear el cdigo y repetir lo que es obvio. i++; /* Incrementa el contador */
Comentarios de prlogo: Al principio de cada mdulo han de incluirse comentarios que resuman la tarea que realiza el mdulo y su interfaz (parmetros...). // // // // // Clculo del MCD utilizando el algoritmo de Euclides Parmetros: Los nmeros a y b Resultado: Mximo comn divisor de a y b
Usualmente, tambin se incluyen comentarios que aclaren los algoritmos y tcnicas utilizados en la implementacin del programa. Al comienzo de cada fichero de cdigo, se suele incluir un comentario en el que aparece el autor del mdulo y una lista de las revisiones que ha sufrido a lo largo de su vida. // // // // // // // Revisor ortogrfico Fernando Berzal, 2003 Revisiones: v2.0 Nov03 Anlisis de sufijos v1.1 Oct03 Diccionario mejorado v1.0 Oct03 Versin inicial
No comente el cdigo malo (uso de construcciones extraas, expresiones confusas, sentencias poco legibles...): Reescrbalo. No contradiga al cdigo: Los comentarios suelen coincidir con el cdigo cuando se escriben, pero a medida que se corrigen errores y el programa evoluciona, los comentarios suelen dejarse en su forma original y aparecen discrepancias. Si cambia el cdigo, asegrese de que los comentarios sigan siendo correctos. Los comentarios han de aclarar; esto es, ayudar al lector en las partes difciles (y no confundirle). Si es posible, escriba cdigo fcil de entender por s mismo: cuanto mejor lo haga, menos comentarios necesitar.
ax = 0x723;
/* RIP L.v.B. */
Convenciones
q
Siempre se han de evitar los efectos colaterales (modificaciones no deseadas que pueden afectar a la ejecucin del programa): #define MAX(a,b) (((a)>(b))?(a):(b)) ... k = MAX(i++,j++); scanf (%d %d, &pos, &v[pos]);
Salvo en la cabecera de los bucles for, slo incluiremos una sentencia por lnea de cdigo. Sean cuales sean las convenciones utilizadas al escribir cdigo (p.ej. uso de sangras y llaves), hay que ser consistente en su utilizacin.
if (...) { ... }
El cdigo bien escrito es ms fcil de leer, entender y mantener (adems, seguramente tiene menos errores)
Estructuras de control
q
Sangras: Conviene utilizar espacios en blanco o separadores para delimitar el mbito de las estructuras de control de nuestros programas. Lneas en blanco: Para delimitar claramente los distintos bloques de cdigo en nuestros programas dejaremos lneas en blanco entre ellos. Salvo en la cabecera de los bucles for, slo incluiremos una sentencia por lnea de cdigo. Sean cuales sean las convenciones utilizadas al escribir cdigo (p.ej. uso de sangras y llaves), hay que ser consistente en su utilizacin. while () { } while () { } for (;;) { } if () { }
for (;;) { }
if () { }
El cdigo bien escrito es ms fcil de leer, entender y mantener (adems, seguramente tiene menos errores)
Estructuras de control - C
- 29 -
Fernando Berzal
Expresiones
q
max = (a > b) ? a : b;
Comentarios
q
Comentarios descriptivos: Los comentarios deben comunicar algo. Jams se utilizarn para parafrasear el cdigo y repetir lo que es obvio.
i++; /* Incrementa el contador */
Estructuras de control - C
- 28 -
Fernando Berzal
Cuestiones de estilo
Escribimos cdigo para que lo puedan leer otras personas, no slo para que lo traduzca el compilador.
Identificadores
q
En ocasiones, se permite el uso de nombres cortos para variables locales cuyo significado es evidente (p.ej. bucles controlados por contador)
for (elemento=0; elemento<N; elemento++ ) for (i=0; i<N; i++)
Constantes
q
Se considera una mala costumbre incluir literales de tipo numrico (nmeros mgicos) en medio del cdigo. Se prefiere la definicin de constantes simblicas (con #define o, mejor an, con enum).
for (i=0; i<79; i++) for (i=0; i<columnas-1; i++)
Estructuras de control - C
- 27 -
Modularizacin
Uso de subprogramas Razones vlidas para crear un subprograma Cohesin y acoplamiento Pasos para escribir un subprograma El nombre y los parmetros de un subprograma Tipos de datos abstractos (TDAs)
Bibliografa
Steve McConnell: Code Complete. Estados Unidos: Microsoft Press, 1994. ISBN 1-55615-484-4.
Uso de subprogramas
Razones vlidas para crear un subprograma
q q q q q q q
Reducir la complejidad del programa (divide y vencers). Eliminar cdigo duplicado. Limitar los efectos de los cambios (aislar aspectos concretos). Ocultar detalles de implementacin (p.ej. algoritmos complejos). Promover la reutilizacin de cdigo (p.ej. familias de productos). Mejorar la legibilidad del cdigo. Facilitar la portabilidad del cdigo.
Cohesin
Medida del grado de identificacin de un mdulo con una funcin concreta. Cohesin aceptable (fuerte)
q
Cohesin funcional (un mdulo realiza una nica accin). Cohesin secuencial (un mdulo contiene acciones que han de realizarse en un orden particular sobre unos datos concretos). Cohesin de comunicacin (un mdulo contiene un conjunto de operaciones que se realizan sobre los mismos datos). Cohesin temporal (las operaciones se incluyen en un mdulo porque han de realizarse al mismo tiempo; p.ej. inicializacin).
Cohesin procedural (un mdulo contiene operaciones que se realizan en un orden concreto aunque no tengan nada que ver entre s). Cohesin lgica (cuando un mdulo contiene operaciones cuya ejecucin depende de un parmetro: el flujo de control o lgica de la rutina es lo nico que une a las operaciones que la forman). Cohesin coincidental (cuando las operaciones de una rutina no guardan ninguna relacin observable entre ellas).
Acoplamiento
Medida de la interaccin de los mdulos que constituyen un programa. Niveles de acoplamiento (de mejor a peor):
q
Acoplamiento de datos (acoplamiento normal): Todo lo que comparten dos rutinas se especifica en la lista de parmetros de la rutina llamada. Acoplamiento de control: Una rutina pasa datos que le indican a la otra rutina qu hacer (la primera rutina tiene que conocer detalles internos de la segunda). Acoplamiento externo: Cuando dos rutinas utilizan los mismos datos globales o dispositivos de E/S. Si los datos son de slo lectura, el acoplamiento se puede considerar aceptable. En general, este tipo de acoplamiento no es deseable porque la conexin existente entre los mdulos no es visible.
Acoplamiento patolgico: Cuando una rutina utiliza el cdigo de otra o altera sus datos locales (acoplamiento de contenido). La mayor parte de los lenguajes estructurados incluyen reglas para el mbito de las variables que impiden este tipo de acoplamiento.
El nombre de un subprograma q Procedimiento: Verbo seguido de un objeto. q Funcin: Descripcin del valor devuelto por la funcin. El nombre debe describir todo lo que hace el subprograma. Se deben evitar nombres genricos que no dicen nada (p.ej. calcular) Se debe ser consistente en el uso de convenciones. Los parmetros de un subprograma Orden: (por valor, por referencia) == (entrada, entrada/salida, salida) Si varias rutinas utilizan los mismos parmetros, stos han de ponerse en el mismo orden (algo que la biblioteca estndar de C no hace). De acuerdo con la primera norma, las variables de estado o error se ponen al final. No es aconsejable utilizar los parmetros de una rutina como si fuesen variables locales de la rutina. Se han de documentar las suposiciones que se hagan acerca de los posibles valores de los parmetros. Slo se deben incluir los parmetros que realmente necesite la rutina para efectuar su labor. Las dependencias existentes entre distintos mdulos han de hacerse explcitas mediante el uso de parmetros.
Se simplifican las modificaciones que tengamos que realizar. Se encapsulan detalles de implementacin (en vez de aparecer por todas partes, estos detalles slo aparecen en la declaracin del tipo). Se ampla el vocabulario que podemos utilizar en nuestro programas.
TDA Coleccin de datos y todas las operaciones que se efectan sobre esos datos Ejemplos: Una ventana, un men, un fichero, una lista, una tabla... PUNTO CLAVE: El acceso a los datos se realiza siempre a travs de las operaciones definidas en el propio TDA.
Beneficios de la utilizacin de TDAs q Se ocultan detalles de implementacin. q Se facilitan las modificaciones que puedan afectar al programa. q Es ms fcil mejorar la eficiencia del programa. q Es ms fcil verificar la correccin del programa. q La legibilidad de los programas mejora. q Se simplifican las interfaces de los mdulos del programa. q Se definen operaciones en funcin de los objetos sobre los que se efectan.
Recursividad
Una funcin que se llama a s misma se denomina recursiva
Utilidad
Cuando la solucin de un problema se puede expresar en trminos de la resolucin de un problema de la misma naturaleza, aunque de menor complejidad. Slo tenemos que conocer la solucin no recursiva para algn caso sencillo (denominado caso base) y hacer que la divisin de nuestro problema acabe recurriendo a los casos base que hayamos definido. Como en las demostraciones por induccin, podemos considerar que tenemos resuelto el problema ms simple para resolver el problema ms complejo (sin tener que definir la secuencia exacta de pasos necesarios para resolver el problema).
Funcionamiento
- Se descompone el problema en problemas de menor complejidad (algunos de ellos de la misma naturaleza que el problema original). - Se resuelve el problema para, al menos, un caso base. - Se compone la solucin final a partir de las soluciones parciales que se van obteniendo.
2. Solucin para el caso general: o Expresin de forma recursiva. o Pueden incluirse pasos adicionales (para combinar las soluciones parciales).
Siempre se debe avanzar hacia un caso base: Las llamadas recursivas simplifican el problema y, en ltima instancia, los casos base nos sirven para obtener la solucin.
int factorial (int n) { int resultado; if (n==0) // Caso base resultado = 1; else // Caso general resultado = n*factorial(n-1); return (resultado); } int potencia (int base, int exp) { if (exp==0) // Caso base return 1; else // Caso general return base * potencia(base,exp-1); }
Solucin recursiva int fibonacci (int n) { if ((n == 0) || (n == 1)) return 1; else return fibonacci(n-1) + fibonacci(n-2); }
Solucin iterativa int fibonacci (int n) { int actual, ant1, ant2; ant1 = ant2 = 1; if ((n == 0) || (n == 1)) { actual = 1; } else for (i=2; i<=n; i++) { actual = ant1 + ant2; ant2 = ant1; ant1 = actual; } } return (actual); }
Mover n discos del poste 1 al poste 3 (utilizando el poste 2 como auxiliar): hanoi (n, 1, 2, 3);
Solucin recursiva: void hanoi (int n, int inic, int tmp, int final) { if (n > 0) { // Mover n-1 discos de "inic" a "tmp". // El temporal es "final". hanoi (n-1, inic, final, tmp); // Mover el que queda en "inic" a "final" printf (Del poste %d al %d.\n, inic, final); // Mover n-1 discos de "tmp" a "final". // El temporal es "inic". hanoi (n-1, tmp, inic, final); } }
Segn la leyenda, los monjes de un templo tenan que mover una pila de 64 discos sagrados de un sitio a otro. Slo podan mover un disco al da y, en el templo, slo haba otro sitio en el que podan dejarlos, siempre ordenados de forma que los mayores quedasen en la base. El da en que los monjes realizasen el ltimo movimiento, el final del mundo habra llegado
Vectores y matrices
Declaracin
Vector (array unidimiensional): <tipo> <identificador> [<componentes>];
<tipo>
Identificador de la variable.
<componentes>
Nmero de elementos del vector. Puede ser un literal o una constante de tipo entero. Nunca ser una variable
Acceso
- En C, el ndice de la primera componente de un vector es siempre 0. - El ndice de la ltima componente es <compontentes>-1 Vector <identificador> [<ndice>] Matriz <identificador>[<ndice1>][<ndice2>]
Inicializacin
En la declaracin, podemos asignarle un valor inicial a los elementos de un vector. int vector[3] = {4, 5, 6}; int matriz[2][3] = { {1,2,3}, {4,5,6} }; El compilador puede deducir las dimensiones del array: int vector[] = {1, 2, 3, 5, 7};
No es necesario utilizar todos los elementos del vector, por lo que, en C, al trabajar con ellos, se suele utilizar una variable entera adicional que nos indique el nmero de datos utilizados. float media (float datos[], int N) { int i; float suma = 0; for (i=0; i<N; i++) suma = suma + datos[i]; return suma/N; } IMPORTANTE: Cuando se pasa un vector como parmetro, el paso de parmetros es por referencia (un vector es, en realidad, un puntero en C). Por tanto, tenemos que tener cuidado con los efectos colaterales que se producen si, dentro de un mdulo, modificamos un vector que recibimos como parmetro.
Algoritmos de ordenacin
Ordenacin por seleccin
void OrdenarSeleccion (double v[], int N) { int i, j, pos_min; double tmp; for (i=0; i<N-1; i++) { // Menor elemento del vector v[i..N-1] pos_min = i; for (j=i+1; j<N; j++) if (v[j]<v[pos_min]) pos_min = j; // Coloca el mnimo en v[i] tmp = v[i]; v[i] = v[pos_min]; v[pos_min] = tmp; = } }
En cada iteracin, se selecciona el menor elemento del subvector no ordenado y se intercambia con el primer elemento de este subvector.
void OrdenarInsercion (double v[], int N) { int i, j; double tmp; for (i=1; i<N; i++) { tmp = v[i]; for (j=i; (j>0) && (tmp<v[j-1]); j--) v[j] = v[j-1]; v[j] = tmp; } }
En cada iteracin, se inserta un elemento del subvector no ordenado en la posicin correcta dentro del subvector ordenado.
void OrdenarBurbuja (double v[], int N) { int i, j; double tmp; for (i=1; i<N; i++) for (j=N-1; j>i; j--) if (v[j] < v[j-1]) { tmp = v[j]; v[j] = v[j-1]; v[j-1] = tmp; } } En cada iteracin Estado del vector tras cada iteracin:
2. Se divide el vector de tal forma que todos los elementos a la izquierda del pivote sean menores que l, mientras que los que quedan a la derecha son mayores que l.
void quicksort (double v[], int izda, int dcha) { int pivote; // Posicin del pivote if (izda<dcha) { pivote = partir (v, izda, dcha); quicksort (v, izda, pivote-1); quicksort (v, pivote+1, dcha); } }
Mientras queden elementos mal colocados respecto al pivote: a. Se recorre el vector, de izquierda a derecha, hasta encontrar un elemento situado en una posicin i tal que v[i] > p. b. Se recorre el vector, de derecha a izquierda, hasta encontrar otro elemento situado en una posicin j tal que v[j] < p. c. Se intercambian los elementos situados en las casillas i y j (de modo que, ahora, v[i] < p < v[j]).
// Intercambio de dos valores void swap (double *a, double *b) { double tmp; tmp = *a; *a = *b; *b = tmp; }
// Divisin el vector en dos partes // - Devuelve la posicin del pivote int partir (double v[], int primero, int ultimo) { double pivote = v[primero]; // Valor del pivote int izda = primero+1; int dcha = ultimo; do { // Pivotear
while ((izda<=dcha) && (v[izda]<=pivote)) izda++; while ((izda<=dcha) && (v[dcha]>pivote)) dcha--; if (izda < dcha) { swap ( &(v[izda]), &(v[dcha]) ); dcha--; izda++; } } while (izda <= dcha); // Colocar el pivote en su sitio swap (&(v[primero]), &(v[dcha]) ); return dcha; // Posicin del pivote }
Algoritmos de bsqueda
Bsqueda lineal = Bsqueda secuencial
// Bsqueda lineal de un elemento en un vector // - Devuelve la posicin de dato en el vector // - Si dato no est en el vector, devuelve -1 int search (double vector[], int N, double dato) { int i; int pos = -1; for (i=0; i<N; i++) if (vector[i]==dato) pos = i; return pos; }
Versin mejorada // Bsqueda lineal de un elemento en un vector // - Devuelve la posicin de dato en el vector // - Si dato no est en el vector, devuelve -1 int search (double vector[], int N, double dato) { int i; int pos = -1; for (i=0; (i<N) && (pos==-1); i++) if (vector[i]==dato) pos = i; return pos; }
Bsqueda binaria
Precondicin El vector ha de estar ordenado Algoritmo Se compara el dato buscado con el elemento en el centro del vector: - Si coinciden, hemos encontrado el dato buscado. - Si el dato es mayor que el elemento central del vector, tenemos que buscar el dato en segunda mitad del vector. - Si el dato es menor que el elemento central del vector, tenemos que buscar el dato en la primera mitad del vector.
// Bsqueda binaria de un elemento en un vector // - Devuelve la posicin de dato en el vector // - Si dato no est en el vector, devuelve -1 // Implementacin recursiva // Uso: binSearch (vector, 0, N-1, dato) int binSearch ( double vector[], int izq, int der, double buscado) { int centro = (izq+der)/2; if (izq>der) return -1; else if (buscado==vector[centro]) return centro; else if (buscado<vector[centro]) return binSearch(vector, izq, centro-1, buscado); else return binSearch(vector, centro+1, der, buscado); } // Implementacin iterativa // Uso: binSearch (vector, N, dato) int binSearch (double vector[], int N, double buscado) { int izq = 0; int der = N-1; int centro = (izq+der)/2; while ((izq<=der) && (vector[centro]!=buscado)) { if (buscado<vector[centro]) der = centro 1; else izq = centro + 1; centro = (izq+der)/2; } if (izq>der) return -1; else return centro; }
Punteros
Definicin
Un puntero es un dato que contiene una direccin de memoria.
NOTA:
Existe una direccin especial que se representa por medio de la constante NULL (definida en <stdlib.h>) y se emplea cuando queremos indicar que un puntero no apunta a ninguna direccin.
Declaracin
<tipo> *<identificador>
<tipo>
Cuando se declara un puntero se reserva memoria para albergar una direccin de memoria, pero NO PARA ALMACENAR EL DATO AL QUE APUNTA EL PUNTERO. El espacio de memoria reservado para almacenar un puntero es el mismo independientemente del tipo de dato al que apunte: el espacio que ocupa una direccin de memoria.
Direccin Operador & &<id> devuelve la direccin de memoria donde comienza la variable <id>. El operador & se utiliza para asignar valores a datos de tipo puntero:
Indireccin Operador * *<ptr> devuelve el contenido del objeto referenciado por el puntero <ptr>. El operador * se usa para acceder a los objetos a los que apunta un puntero:
// Equivale a escribir: c = A
Asignacin Operador =
A un puntero se le puede asignar una direccin de memoria concreta, la direccin de una variable o el contenido de otro puntero.
Una direccin de memoria concreta: int *ptr; ... ptr = 0x1F3CE00A; ... ptr = NULL;
La direccin de una variable del tipo al que apunta el puntero: char c; char *ptr; ... ptr = &c;
Otro puntero del mismo tipo: char char char ptr1 ptr2 c; *ptr1; *ptr2; = &c; = ptr1;
Como todas las variables, los punteros tambin contienen basura cuando se declaran, por lo que es una buena costumbre inicializarlos con NULL.
Ejemplo
int main () { int y = 5; int z = 3; int *nptr; int *mptr;
nptr = &y;
z = *nptr;
*nptr = 7;
mptr = nptr;
mptr = *z;
*mptr = *nptr;
y = (*nptr) + 1; return 0; }
Errores comunes
Asignar punteros de distinto tipo int a = 10; int *ptri = NULL; double x = 5.0; double *ptrf = NULL; ... ptri = &a; ptrf = &x; ptrf = ptri; // ERROR
Asignar valores a un puntero y no a la variable a la que apunta int n; int *ptr = &n; ptr = 9; // ERROR
Intentar asignarle un valor al dato apuntado por un puntero cuando ste es NULL int *ptr = NULL; *ptr = 9; // ERROR
Punteros a punteros
Un puntero a puntero es un puntero que contiene la direccin de memoria de otro puntero-
int main () { int a = 5; int *p; // Puntero a entero int **q; // Puntero a puntero
p = &a;
q = &p; }
Para acceder al valor de la variable a podemos escribir a *p (forma habitual) (a travs del puntero p)
**q (a travs del puntero a puntero q) q contiene la direccin de p, que contiene la direccin de a
Aritmtica de punteros <tipo> *ptr; ptr + <desplazamiento> devuelve un puntero a la posicin de memoria sizeof(<tipo>)*<desplazamiento> bytes por encima de ptr. int v[]; int *ptr = v;
NOTA: La suma de punteros no tiene sentido y no est permitida. La resta slo tiene sentido cuando ambos apuntan al mismo vector y nos da la distancia entre las posiciones del vector (en nmero de elementos).
Ejemplo: Distintas formas de sumar los elementos de un vector int suma ( int v[], int N) { int i, suma; int *ptr, *ptrfin; /* Alternativa 1 */ suma = 0; for (i=0 ; i<N ; i++) suma = suma + v[i]; /* Alternativa 2 */ suma = 0; for (i=0 ; i<N ; i++) suma = suma + (*(v+i)); /* Alternativa 3 */ suma = 0; ptrfin = ptr + N-1; for (ptr=v ; ptr<=ptrfin ; ptr++) suma = suma + *ptr; return suma; } Punteros y matrices <tipo> mat [<dimF>][<dimC>];
void Cambia(int *a, int *b) { int aux; aux = *a; *a = *b; *b = aux; } int main() { int x=0, y=1; Cambia(&x,&y); return 0; }
Segmento de cdigo (cdigo del programa). Memoria esttica (variables globales y estticas). Pila (stack): Variables automticas (locales). Heap (montn): Variables dinmicas.
Reserva y liberacin de memoria Cuando se quiere utilizar el heap, primero hay que reservar la memoria que se desea ocupar: ANSI C: Funcin malloc C++: Operador new Al reservar memoria, puede que no quede espacio libre suficiente, por lo que hemos de comprobar que no se haya producido un fallo de memoria (esto es, ver si la direccin de memoria devuelta es distinta de NULL). Tras utilizar la memoria reservada dinmicamente, hay que liberar el espacio reservado: ANSI C: Funcin free C++: Operadore delete Si se nos olvida liberar la memoria, ese espacio de memoria nunca lo podremos volver a utilizar
int main(int argc, char *argv[]) { int i; int n; float *v; printf("Nmero de elementos del vector: "); scanf("%d",&n); // Creacin del vector v = malloc(n*sizeof(float)); // Manejo del vector for (i=0; i<n; i++) v[i] = i; printf("Media = %f\n", media(v,n)); // Liberacin de memoria free(v); return 0; }
Creacin del vector (constructor) Vector crearVector (void) { Vector v =(Vector) malloc ( sizeof(struct Vector) ); v->usado = 0; v->capacidad = 2; v->datos = malloc ( (v->capacidad)*sizeof(Dato) ); return vector; } Destruccin del vector (destructor) void destruirVector (Vector *v) { free ( (*v)->datos ); free ( *v ); *v = NULL; } Constructor y destructor nos permiten manejar vectores sin tener que conocer su estructura de datos interna (ni siquiera tendremos que utilizar malloc y free).
Acceso al contenido del vector Funciones que permiten ocultar los detalles de implementacin del TDA
Dato obtenerDato (Vector v, int pos) { if ((pos>=0) && (pos<elementosVector(v))) return v->datos[pos]; else return NULL; }
void guardarDato (Vector v, int pos, Dato dato) { if ((pos>=0) && (pos<elementosVector(v))) { v->datos[pos] = dato; } }
Insercin de datos void agregarDato (Vector v, Dato dato) { int i; Dato *datos; if (v->usado == v->capacidad) { // Redimensionar el vector v->capacidad *= 2; datos = malloc ( (v->capacidad)*sizeof(Dato) ); for (i=0; i < v->usado; i++) datos[i] = v->datos[i]; free(v->datos); v->datos = datos; } v->datos[v->usado] = dato; v->usado ++; } Eliminacin de datos void eliminarDato (Vector v, int pos) { int i; if ((pos>=0) && (pos<elementosVector(v))) { for (i=pos; i<elementosVector(v)-1; i++) v->datos[i] = v->datos[i+1]; v->usado --; } }
OJO!
En la implementacin mostrada no contemplamos la posibilidad de que la funcin malloc devuelva NULL (algo que siempre deberemos hacer al programar).
#include <stdio.h> #include vector.h /* Rutina auxiliar */ void mostrarVector (Vector v) { int i; printf( "Vector de tamao %d:\n", elementosVector(v) ); for (i=0; i<elementosVector(v); i++) printf("- %d\n", obtenerDato(v,i)); }
/* Programa principal */ int main () { Vector v = crearVector(); mostrarVector (v); agregarDato (v,1); agregarDato (v,2); agregarDato (v,3); mostrarVector (v); eliminarDato (v,1); mostrarVector (v); guardarDato (v, 0, obtenerDato(v,0)+2); mostrarVector (v); destruirVector(&v); return 0; }
#include <stdio.h>
E/S de caracteres
Al nivel ms bajo, las operaciones de entrada/salida se realizan con bytes, si bien resulta engorroso tener que programar a este nivel: getchar La funcin getchar devuelve el siguiente carcter ledo desde el teclado. putchar Muestra un carcter a travs del dispositivo de salida estndar (la pantalla, generalmente).
NOTA: La mayora de los sistemas operativos utilizan buffers para gestionar las operaciones de entrada/salida, por lo que no se leer un carcter hasta que el usuario introduzca un retorno de carro y, posiblemente, no se mostrar nada por pantalla hasta que se tenga una lnea completa por mostrar.
#include <stdio.h> int main () { int c = 0; while (getchar() != EOF) c ++; printf("%d\n", c); return 0; }
NOTA: Para indicar el final de un fichero cuando se estn introduciendo los datos desde el teclado hay que escribir CONTROL+Z en Windows (CONTROL+D en UNIX/Linux).
scanf Permite leer datos con formato desde el teclado. Parmetros: Cadena de formato (cmo se introducen los datos) Lista de punteros (dnde se almacenan los datos)
Cadena de formato %[flag][ancho][.prec][modificador][tipo] Tipo: %c %s %d %x %f Carcter (char) Cadena de caracteres (string) Nmero entero (decimal) Nmero entero (en hexadecimal) Nmero real (float)
Modificador:
%ld Nmero entero (long int) %lf Nmero real (double) %Lf Nmero real (long double)
[ancho] indica el nmero mnimo de caracteres que se utilizarn para visualizar el dato (el espacio sobrante se rellena con espacios o con ceros). [.prec] indica el nmero mximo de dgitos/caracteres que se mostrarn. Las cadenas de caracteres se truncan, los nmeros reales se redondean utilizando prec decimales. [flag]: Por defecto, los datos se justifican a la derecha. Poniendo -, los datos se justifican a la izquierda. Con + se indica que siempre queremos visualizar el signo de un nmero (+ -).
E/S de lneas
Si no estamos interesados en el formato de nuestros datos (o, simplemente, no podemos predecir su formato de antemano), podemos leer y escribir lneas completas de caracteres con otras dos funciones estndar: gets (cadena) Lee una lnea completa (hasta que se alcanza un retorno de carro [\n] o el final del fichero [EOF]). NOTAS: - gets devuelve NULL cuando se llega al final de la entrada. - gets no comprueba la longitud de la cadena de entrada, por lo que siempre utilizaremos la funcin fgets, que s lo hace. puts (cadena) Escribe una lnea de texto y le aade un retorno de carro al final.
Ejemplo: Doble espaciado #include <stdio.h> int main () { char line[256]; /* Suficientemente grande? */
while ( gets(line) != NULL) { puts(line); printf("\n"); } return 0; } NOTA: Se pueden mezclar libremente las operaciones de E/S con formato, E/S de caracteres y E/S de lneas.
programa <entrada.txt ejecuta el programa leyendo los datos del fichero de texto entrada.txt
programa <entrada.txt >salida.txt lee los datos de entrada.txt y guarda los resultados en salida.txt
La redireccin resulta fcil de utilizar y nos permite que un nico programa funcione leyendo datos desde el teclado o desde un fichero:
Podemos escribir los programas para que lean los datos desde el teclado y muestren los resultados por pantalla. Despus los utilizaremos con datos almacenados en ficheros (y guardar en ficheros los resultados que obtengamos).
Algunos programas necesitan acceder a distintos ficheros, para lo cual recurriremos a las funciones de manipulacin de ficheros definidas en la biblioteca estndar de C
Manipulacin de ficheros en C
La biblioteca <stdio.h> incluye un tipo de dato que nos permitir manipular ficheros mediante punteros: el tipo FILE *
Para utilizar un fichero, hemos de declararlo como una variable ms: FILE *fichero;
Antes de poder acceder a l, hay que abrir el fichero. La funcin fopen devuelve el puntero a travs del cual accederemos al fichero: fichero = fopen(salida.txt, w) Si, por cualquier motivo, el fichero no puede abrirse, la funcin fopen devuelve NULL, por lo que siempre deberemos comprobar el resultado de llamar a la funcin fopen: if (fichero == NULL) fprintf (stderr, No se pudo acceder al fichero\n);
Siempre que se abre un fichero, hay que cerrarlo despus de usarlo: fclose (fichero); Suele existir un lmite sobre el nmero de ficheros que pueden estar abiertos simultneamente, por lo que es conveniente cerrar el fichero justo despus de utilizarlo si no se va a volver a acceder a l.
Existen tres ficheros predefinidos en la biblioteca estndar de C: stdin (entrada estndar: el teclado o un fichero redirigido). stdout (salida estndar: la pantalla o un fichero al que se enva la salida). stderr (salida estndar para mensajes de error: la pantalla).
fopen Abre un fichero Parmetros: Nombre del fichero Modo de acceso r Lectura w Escritura (crear un fichero nuevo) a Escritura (aadir al final del fichero)
fclose Cierra un fichero Parmetro: Puntero al fichero (que debe estar abierto).
Operaciones de E/S con ficheros Existen funciones para trabajar con ficheros que son anlogas a las funciones de entrada/salida estndar (slo tenemos que indicar el fichero sobre el cual deseamos realizar la operacin correspondiente):
equivale a putc(c,stdout) getc(stdin) fprintf(stdout,) fscanf(stdin,) fputs(cadena,stdout) fgets(cadena,longitud,stdin) putchar(c) getchar() printf() scanf() puts(cadena) gets(cadena)
#include <string.h>
Entre las funciones ms utilizadas de esta biblioteca se encuentran las siguientes: strcpy(dest,src) copia la cadena src en dest, si bien tiene el mismo defecto que la funcin gets. strncpy(dest,n,src) copia la cadena src en dest, si bien tiene en cuenta el tamao de dest. El parmetro n debe ser igual al tamao del vector dest menos 1 (si queremos dejar espacio para el \0 final). strcmp(cad1,cad2) compara las cadenas cad1 y cad2. Devuelve 0 si las cadenas son iguales. strlen(cadena) devuelve la longitud de la cadena (el nmero de caracteres que hay hasta que nos encontramos un \0).