TEMA 2. Primeros pasos en C

Anuncio
Autor: José C. Riquelme (Universidad de Sevilla)
TEMA 2. Primeros pasos en C
1. Sintaxis básica.
De los seudocódigos del tema 1 se puede intuir que un programa en cualquier lenguaje
está constituido por un conjunto de “palabras” (entendida como un conjunto de
caracteres dígitos o alfabéticos) separadas por algunos caracteres no alfabéticos. Por
ejemplo, si repetimos el seudocódigo del cálculo del factorial de un número:
Inicio
Leer n
Hacer i igual a 1
Hacer f igual a 1
Mientras i sea menor o igual a n
Hacer f igual a f × i
Hacer i igual a i + 1
FinMientras
Escribir el factorial de n es f
Fin
Podemos ver que hay palabras como i, x o f que representan datos del programa y son
palabras que define el programador. Hay caracteres como + o × que representan
operaciones, otros como 1 representan valores numéricos y otras palabras como
Mientras, Leer o Escribir serán instrucciones del lenguaje. Cuando escribimos en
un lenguaje concreto sucede igual. Así existen seis clases de elementos sintácticos en el
vocabulario de un lenguaje de programación como el C: separadores, delimitadores,
comentarios, palabras clave, identificadores, constantes y operadores.
Separadores. En el código de un programa fuente C los separadores –uno o varios
espacios en blanco, tabuladores y caracteres de nueva línea– se emplean para separar los
demás elementos sintácticos. Los separadores son ignorados por el compilador y su
misión es hace el código más legible. El compilador procesa el código fuente
constituido entonces por una lista del resto de elementos sintácticos. Si el orden de esta
lista es adecuado, no habrá errores de compilación y se creará el código objeto.
Delimitadores. Los delimitadores son caracteres especiales que sirven para separar
trozos de código o distintos elementos en una lista. En C los principales delimitadores
son el punto y coma, las llaves { }, los paréntesis ( ) y las comas. También se usan en
determinadas partes del programa o sentencias otros como :, #, <, >, , etc.
Comentarios. Los comentarios son un tipo especial de separadores que sirven para
explicar o aclarar algunas sentencias del código por parte del programador y ayudar a su
prueba y mantenimiento. De esta forma se intenta que el código pueda ser entendido por
una persona diferente o por el propio programador algún tiempo después.
Los caracteres /* y */ se emplean para iniciar y terminar respectivamente un comentario
introducido en el código del programa. Todo el texto entre estos dos caracteres es
ignorado por el compilador:
variable_1 = variable_2; /* En esta línea se asigna a
variable_1 el valor
contenido en variable_2 */
Tema 2. Primeros pasos en C
El lenguaje ANSI C permite también otro tipo de comentarios. Todo lo que va en
cualquier línea del código detrás de la doble barra (//) y hasta el final de la línea, se
considera como un comentario. Para comentarios cortos, esta forma es más cómoda que
la anterior, pues no hay que preocuparse de cerrar el comentario (el fin de línea actúa
como cierre). Como contrapartida, si un comentario ocupa varias líneas hay que repetir
la doble barra (//) en cada una de las líneas. Con este segundo procedimiento de
introducir comentarios, el último ejemplo podría ponerse en la forma:
variable_1 = variable_2; // En esta línea se asigna a
// variable_1 el valor
// contenido en variable_2
Palabras claves. Las palabras claves o reservadas son las propias del lenguaje e indican
tipos de datos o instrucciones concretas. El lenguaje ANSI C tiene pocas palabras claves
aunque cada compilador de C añade algunas palabras reservadas. Por supuesto, no
deben usarse como identificadores por parte del programador. Las palabras reservadas
del ANSI C son las siguientes:
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
Identificadores. Un identificador es un nombre que el programador da a una función,
un tipo de dato o al contenido de una zona de la memoria (variable) o constante. En
ANSI C un identificador se forma con las siguientes reglas:
1. Es una secuencia de letras (minúsculas de la a a la z; mayúsculas de la A a la Z;
y dígitos del 0 al 9) o el carácter subrayado o guión bajo (_). No debe incluirse
la ñ.
2. Un identificador no puede contener espacios en blanco, ni otros caracteres
distintos de los citados, como por ejemplo (*,;.:-+,etc.).
3. El primer carácter de un identificador debe ser siempre una letra o un (_), es
decir, no puede ser un dígito.
4. Se hace distinción entre letras mayúsculas y minúsculas. Así, Suma es
considerado como un identificador distinto de suma y de SUMA.
Ejemplos de identificadores válidos son los siguientes:
tiempo, distancia1, caso_A, PI, velocidad_de_la_luz
Por el contrario, los siguientes nombres no son válidos (¿Por qué?)
1_valor, tiempo-total, dolares$, %final
En general es muy aconsejable elegir los nombres de los identificadores de forma que
permitan conocer a simple vista qué representan, utilizando para ello tantos caracteres
Autor: José C. Riquelme (Universidad de Sevilla)
como sean necesarios. Esto simplifica enormemente la tarea de programación y –sobre
todo– de corrección y mantenimiento de los programas. Es cierto que los nombres
largos son más laboriosos de teclear, pero en general resulta rentable tomarse esa
pequeña molestia. Unas reglas aconsejables para los identificadores son las siguientes:
1. Las variables normalmente tendrán nombres de sustantivos se escribirán con
minúsculas salvo cuando estén formadas por dos o más palabras, en cuyo caso,
el primer carácter de cada palabra se escribirá en mayúscula. Por ejemplo:
salario, salarioBase, edadJubilacion
2. Los identificadores de constantes (datos que no van a cambiar durante la
ejecución del programa) se deben escribir con todos los caracteres con
mayúsculas. Por ejemplo: PI, PRIMER_VALOR, EDADMINIMA.
3. Los identificadores de funciones normalmente deben indicar alguna acción y se
escriben normalmente en minúsculas: calcularFactorial, resolverEcuacion, etc.
4. Los identificadores de tipos de datos definidos por el programador se deben
escribir con el primer carácter en mayúsculas: TablaEnteros, TipoEmpleado, etc.
Constantes. Una constante (no confundir con identificador de una constante) es una
“palabra” que representa un único valor. En C existen distintos tipos de constantes:
1. Constantes numéricas. Son valores numéricos, enteros o reales (también
llamados de punto flotante) 1:. Por ejemplo: 123, 34, -456, 1.23, -23.45E3, …
2. Constantes carácter. Cualquier carácter individual encerrado entre simples
comillas o apóstrofes (por ejemplo: 'a', 'Y', ')', '+', etc.) es considerado por C
como una constante carácter. En realidad internamente C los representa como un
número entero (entre 0 y 255), llamado código ASCII, que establece una
equivalencia entre cada carácter y el valor numérico correspondiente.
3. Cadenas de caracteres. Un conjunto de caracteres alfanuméricos encerrados
entre comillas es también un tipo de constante del lenguaje C, como por
ejemplo: "espacio", "Esto es una cadena de caracteres", etc.
Operadores. Los operadores son signos especiales –a veces, conjuntos de dos
caracteres– que indican determinadas operaciones a realizar con las variables y/o
constantes sobre las que actúan en el programa. El lenguaje C es particularmente rico en
distintos tipos de operadores: aritméticos (+, -, *, /, %), de asignación (=, +=,
-=, *=, /=), relacionales (==, <, >, <=, >=,!=) y lógicos (&&, ||, !).
Por ejemplo, en la sentencia:
espacio = espacio_inicial + 0.5 * aceleracion * tiempo * tiempo;
aparece un operador de asignación (=) y dos operadores aritméticos (+ y *). Otros
símbolos como el punto, & ó  también son operadores.
2. Tipos de datos básicos y variables.
2.1 Tipos básicos. El C, como cualquier otro lenguaje de programación, tiene
posibilidad de trabajar con datos de distinta naturaleza: texto formado por caracteres
alfanuméricos, números enteros, números reales con parte entera y parte fraccionaria,
etc. Además, algunos de estos tipos de datos admiten distintos rango y/o precisión,
1
También es posible definir constantes en octal o hexadecimal
Tema 2. Primeros pasos en C
posibilidad de ser sólo positivos o de ser positivos y negativos, etc. Los tipos de datos
básicos del C son2:



Para datos enteros: int y long.
Para datos reales: float y double.
Para caracteres: char.
Un tipo de dato sirve para definir las variables de un programa. Según los valores que
vaya a contener la variable se deberá definir de un tipo u otro. En C es imprescindible
definir el tipo de una variable antes de usarla. Una variable no declarada produce un
mensaje de error en la compilación. Cuando una variable es declarada se le reserva
memoria de acuerdo con el tipo incluido en la declaración.
Así por ejemplo si necesitamos una variable para almacenar el año de nacimiento de una
persona, la definiremos de tipo int o long por ser un año un valor entero. La
diferencia entre los tipos int y long es el tamaño máximo que puede tomar derivado
del tamaño que define ese tipo en memoria. Así el tipo int sirve para enteros hasta
32767 (215-1 (¿averigua por qué?) y long para números enteros más grandes. Por
ejemplo para almacenar el número de habitantes de una ciudad lo habitual sería definir
la variable como long (¿cuál es el tamaño máximo de una variable long?).
Para variables reales, por ejemplo un precio en euros o la estatura de una persona se
declararán de tipo float o double. La diferencia es de nuevo el tamaño en bytes que
ocupa una variable de un tipo u otro en memoria lo que se traduce en tamaño máximo
posible y en precisión (número de cifras decimales). La mayoría de los programas
trabajan bien con tipos float, que será por tanto nuestro tipo de dato real habitual.
(Averigua la diferencia entre el tamaño máximo y la precisión de variables float o
double).
El tipo char sirve para declarar variables que almacenan un único carácter. Como se ha
señalado en el apartado anterior de constantes, C tiene una manera peculiar de
almacenar y tratar los caracteres como números enteros. Esto significa que a cada
carácter se le asigna un código numérico. El código habitual es el ASCII (American
Standard Code for Information Interchange). De esta forma, un dato de tipo char se
almacena realmente como un valor entero entre 0 y 255, representando el código ASCII
asociado al carácter. Por ejemplo,
'a': 97
'b': 98
'c': 99
...
'z': 122
'A': 65
'B': 66
'C': 67
...
'Z': 90
'0': 48
'1': 49
'2': 50
...
'9': 57
Obsérvese que no hay una relación especial entre el valor del carácter constante que
representa un dígito y el valor entero intrínseco del dígito; es decir, el valor de '3' no es
3. El hecho de que los valores de 'a', 'b', 'c', etc. sean correlativos es importante, pues
simplifica la clasificación de caracteres y palabras en orden alfabético.
2
También existe el tipo short y variantes con las palabras long, signed y unsigned que no se usarán en
esta asignatura
Autor: José C. Riquelme (Universidad de Sevilla)
Algunos caracteres no son imprimibles, y se representan de una forma especia, como
por ejemplo '\n' (nueva línea o salto de línea) o '\0' (carácter nulo).
Esta forma de representar los caracteres da lugar a cuestiones curiosas y confusiones
como que se puedan restar variables de tipo carácter o sumar un entero a una variable
char3. (¿Qué resultado darían esas operaciones?).
El ANSI C no tiene definido un tipo para las expresiones booleanas 4. Un valor booleano
es un valor de cierto o falso, y que en C se modela mediante un valor entero de 1 para
cierto y de 0 para falso. Más adelante veremos como se puede definir un tipo lógico.
Finalmente C proporciona un tipo denominado void, que representa la ausencia de tipo.
2.2 Variables. Las variables sirven para almacenar datos y valores que pueden cambiar
a lo largo de la ejecución. Variables típicas en los programas son aquellas que sirven
para guardar el valor de los datos leídos desde teclado, la variable que acumula una
suma o un contador, etc. Para declarar variables en C se debe primero escribir el tipo y
después la lista de identificadores de las variables que se quieran definir de ese tipo
separados por comas y terminados en un punto y coma. Todas las variables deben
declararse antes de ser utilizadas y en general, las variables en C no se inicializan a
ningún valor, por tanto, es conveniente y muy recomendable inicializarlas cuando se
declaran. La declaración se usa para asociar un tipo de dato a un identificador. El tipo de
dato representa el intervalo de valores (dominio) que puede tomar la variable y el
conjunto de operaciones definidas sobre la misma. Así pues, la información elemental
de una variable se compone de:
·
·
·
Un tipo, que define un conjunto de valores posibles del dominio donde puede
tomar valor la variable.
Un valor, que es el elemento del dominio especificado por el tipo que tiene la
variable en un momento dado.
Un nombre o identificador.
Serían declaraciones válidas:
int contador=0,m;
long numhab;
float sumaTotal=0.0, precio=9.99;
Las declaraciones de variables en C no pueden hacerse en cualquier parte del código y
en función del lugar donde se declaren se establece un determinado ámbito de uso. Esta
cuestión se estudiará con profundidad más adelante.
2.3 Conversiones de tipo. Cuando en una expresión se mezclan variables de distintos
tipos, por ejemplo, si se suman dos variables una int y otra float, ¿Cuál es el tipo del
resultado final? En C las operaciones se realizan en el tipo de mayor rango, es decir, en
3
En esta asignatura no se tendrá en cuenta esta característica y el tipo char sólo se usará para
operaciones propias de caracteres.
4
En algunos compiladores existe el tipo bool heredado del C++.
Tema 2. Primeros pasos en C
este caso la variable int se convierte a float antes de realizar la operación. Esta
conversión es automática e implícita (el programador no necesita intervenir, aunque sí
conocer sus reglas). Así pues, cuando dos tipos diferentes de constantes y/o variables
aparecen en una misma expresión relacionadas por un operador, el compilador convierte
los dos operandos al mismo tipo de acuerdo con los rangos, que de mayor a menor se
ordenan del siguiente modo:
double > float > long > int > char
Otra clase de conversión implícita5: tiene lugar cuando el resultado de una expresión es
asignado a una variable, pues dicho resultado se convierte al tipo de la variable. En este
caso, ésta puede ser de menor rango que la expresión, por lo que esta conversión puede
perder información. Por ejemplo, la secuencia de código:
int i;
float x=4.8;
i = x/2; // i valdrá 2
La conversión entre los tipos int y char viene dada por la característica anteriormente
señalada de que C almacena los valores char como un int correspondiente a su código
ASCII6.
3. Funciones.
Como se ha señalado en el Tema 1 la modularización del código se implementa en C
mediante el concepto de función. Una función está asociada con un identificador o
nombre, que se utiliza para referirse a ella desde el resto del programa. Toda función en
C debe estar declarada mediante su prototipo, definida mediante el código de la
función e invocada desde la función principal o desde otra función.
3.1 Declaración de una función. La declaración de una función consiste en definir cuál
va a ser su nombre, qué tipos de datos tiene como entrada (argumentos) y que tipo de
dato devuelve. En una primera aproximación a las funciones en C vamos a estudiar sólo
las funciones que devuelven un único valor de salida. Más adelante estudiaremos las
funciones que pueden devolver más de un valor.
Para explicar estos conceptos hay que introducir los conceptos de valor de retorno y de
argumentos. Toda función bien definida debe recibir uno o varios valores a partir de los
cuales calculará un valor de salida. El ejemplo más cercano son las funciones
matemáticas como potencia, que puede recibir dos argumentos, uno real (base) y otro
entero (exponente) y devuelve un real con el resultado de la base elevada al exponente.
Por tanto, los argumentos son base y exponente y el resultado o valor de retorno la
potencia. Para declarar una función basta con darle un nombre y declarar los tipos de los
argumentos y del valor de retorno de esta manera7:
5
En C se pueden realizar también conversiones explícitas mediante el uso de casting. No será materia de
esta asignatura.
6
Como se ha dicho anteriormente en esta asignatura no se usará esa conversión aunque el alumno
interesado puede busca fácilmente información sobre esta característica (obsoleta) del C.
7
También se puede incluir en el prototipo el nombre de la variable argumento, nosotros sin embargo no
lo haremos.
Autor: José C. Riquelme (Universidad de Sevilla)
Tipo_retorno nombre_funcion (tipo_arg1, tipo_arg2,…,tipo argn);
Esto es lo que se llama prototipo de una función y es equivalente a su declaración. Por
ejemplo:
float potencia (float,int);
int factorial(int);
char aMayuscula(char);
int mcd(int,int);
Nótese que un prototipo siempre termina en el separador ; y que los tipos de los
argumentos están entre paréntesis y separados por comas.
3.2 Llamada a una función. Las funciones son llamadas o invocadas desde otras
funciones. La sintaxis de una invocación típica de una función en C es:
variable=nombre_funcion (val_arg1, val_arg2,… ,val_argn);
donde variable ha de ser (con algunos matices que veremos más adelante) del tipo
que devuelve la función y los elementos val_argi serán variables o constantes de los
tipos de los argumentos en el mismo número y orden. Así serían posibles llamadas:
pot
pot
f =
c =
p =
= potencia (3.4,2); // pot de tipo float
= potencia(x,n); // x debe ser float y n int
factorial(m); // m de tipo int
aMayuscula(‘e’); // c de tipo char
mcd(i,j); // p, i y j de tipo int
En una invocación el nombre de la función (con la lista de argumentos) es un valor del
tipo devuelto y, por tanto, también puede intervenir en cualquier tipo de expresiones de
acuerdo con el tipo devuelto. Así también son posibles invocaciones:
pot = potencia (3.4,mcd(3,p)); // pot de tipo float y p int
f = (3*a)/factorial(m); // a, m de tipo int
p = mcd(i,j)+mcd(a,b); // p, i, j, a, b de tipo int
printf(“el valor es %c”,aMayuscula(g)); con g de tipo char
Los valores que figuran en la invocación se llaman argumentos reales o actuales.
3.3 Definición de una función. La definición de una función es el conjunto de
sentencias o instrucciones necesarias para que la función pueda realizar su tarea cuando
sea llamada. En otras palabras, la definición es el código correspondiente a la función.
Además del código, la definición de la función debe incluir una primera línea que es una
cabecera similar a la declaración o prototipo que hemos visto. Esta cabecera debe incluir
de forma obligatoria los nombres de las variables que van a ser los argumentos de
entrada. Estas variables se llaman argumentos formales a diferencia de los argumentos
que están en la invocación que ya hemos señalado se llaman argumentos reales.
Veamos un ejemplo con la función potencia:
Declaración o prototipo: float potencia (float, int);
Tema 2. Primeros pasos en C
Cabecera de la definición: float potencia (float base, int exponente)
Las variables base y exponente son los argumentos formales, y a su vez son
variables locales en el código de la función. Aunque no entendamos todavía el código,
vamos a exponer cuál sería la definición completa de la función potencia.
float potencia (float base, int exponente){
float resultado=1.0;
int i=1;
while(i<=exponente){
resultado = base * resultado;
i=i+1;
}
return resultado;
}
Sin tener en cuenta de momento qué hace esta función, sí podemos entender qué
significan los parámetros formales. Las variables base y exponente sirven de
comunicación entre la invocación y el código de la función, de esta manera la
invocación:
pot = potencia (3.4,2);
hace que la variable base tome el valor 3.4 y exponente el valor 2, que son
denominados parámetros reales. Si la invocación se hiciera en vez de con constantes con
valores de variables, por ejemplo:
pot = potencia (a,b); // a de tipo float y b int
Los parámetros reales serían a y b y cuando se invoca la función potencia el valor de a
se transfiere a base y el de b a exponente. La función potencia realiza una serie de
cálculos con los valores recibidos de base y exponente y calcula un valor que se
guarda en la variable local resultado. Esta variable es “devuelta” en la última
sentencia de la función y su valor se transfiere a la invocación de la función y asignada
a su vez a la variable pot.
Es importante repetir que los parámetros formales en la cabecera de la función son
variables locales a la función, es decir, sólo tienen sentido dentro del código de la
función, y es un error muy común querer definirlos otra vez dentro de la función. Las
variables i y resultado también son variables locales de la función potencia.
Si una función no devuelva ningún valor su tipo de retorno será void8.
3.4 La función main. Todo programa en C debe tener una función principal que debe
denominarse main. Aunque puede tener distintos formatos de cabecera lo usual es void
8
Por razones históricas estas funciones suelen llamarse procedimientos. Por ejemplo, se usan
habitualmente para imprimir resultados en pantalla, ya que son funciones que estructuran bien el
código y son reutilizables pero no devuelven ningún valor.
Autor: José C. Riquelme (Universidad de Sevilla)
main(void)9.
A continuación entre llaves estará el código que resuelve el problema
para el que se crea el programa. Lo usual es que la mayoría del código de la función
main sea invocaciones a las funciones en las que se habrá dividido el problema.
3.5 Ámbito de las variables. Como hemos visto en C las variables se declaran en dos
sitios: después de la cabecera de la función principal10 y después de las cabeceras de las
funciones11. Estas variables tienen como ámbito de visibilidad sólo la función en la que
se han declarado. Por tanto, distintas funciones (incluyendo la principal) pueden tener el
mismo identificador de variable sin problemas ya que se estarán refiriendo a zonas de
memoria diferente.
4. Estructura de un programa en C
La estructura de un programa en C no es única, hay cierta libertad, sin embargo en esta
asignatura vamos a dar una única estructura posible. El código se puede (y más adelante
será obligatorio) estructurar en más de un fichero. De momento, vamos a dar la
estructura de un programa en C en un único fichero fuente, que recordamos tendrá la
extensión .c. El orden de los elementos adecuado es:
1.
2.
3.
4.
5.
6.
declaración de importaciones
declaración de constantes
declaración de tipos
declaración de funciones
función principal
definición de funciones
4.1 Declaración de importaciones. En C es habitual usar un conjunto de funciones ya
predefinidas por el compilador y situadas en librerias. Estas funciones están declaradas
en ficheros que tienen la extensión .h (de head o ficheros cabecera). En la declaración
de importaciones el programador indica al compilador que librerías va a necesitar. Hay
numerosas librerías de funciones y además cada IDE puede añadir funciones propias,
sin embargo tres son habituales: stdio.h, math.h y string.h.
La librería stdio.h (standard input/output) es la que sirve para las funciones de lectura
tanto desde teclado como desde fichero y de escritura tanto en pantalla como en fichero,
y por tanto, siempre está presente en un programa en C. La librería math.h contiene las
funciones matemáticas (raíz cuadrada, potencia, trigonométricas, etc.) y string.h las
funciones para tratamiento de cadenas de caracteres.
Cada declaración de importación debe ir en una sola línea con un formato como el
siguiente:
9
El C permite que la función principal tenga argumentos de entrada, que pueden ser dados como
entrada al programa ejecutable si éste es invocado desde la línea de comando. No será materia de este
curso.
10
Realmente el C permite también declarar variables “globales” (fuera del main y de las funciones) y que
tendrían visibilidad en todo el ámbito del programa. Se consideran un muy mal hábito de programación
y por tanto no se considerarán en este manual.
11
Dependiendo del compilador de C ó C++ que se use, también es posible declarar variables en ámbitos
más reducidos, por ejemplo dentro de un bucle. En este manual no usaremos esta posibilidad.
Tema 2. Primeros pasos en C
#include <stdio.h>
#include <math.h>
4.2 Declaración de constantes. Una constante es un identificador que se asocia a un
valor que no cambia durante toda la ejecución del programa. Habitualmente se usa para
una mejor documentación del programa o para hacer más fácil su mantenimiento y
cambio. La forma habitual de declarar una constante es la siguiente:
#define identificador valor
Por ejemplo
#define PI 3.1415
#define NUMMAXIMO 100
#define ERROR “Terminación anormal del programa”
Nótese que entre el identificador y el valor NO HAY carácter =, que la sentencia NO
termina en punto y coma y que la constante no necesita declararse de un determinado
tipo, sino que el valor determina el tipo12.
4.3 Declaración de tipos. El C proporciona un conjunto de tipos básicos ya definidos
(int, float, char, etc.) y también permite que el programador defina sus propios tipos.
Los tipos más habituales que se definen en C son los tipos enumerados, los tipos tabla o
array y los tipos registros o struct. Los estudiaremos más adelante.
4.4 Declaración de funciones. Como se ha señalado en la sección 3.1 las funciones en
C deben declararse mediante su prototipo. Éste debe escribirse antes de su invocación
por el programa principal.
4.5 Función principal. La función main es por donde empieza a ejecutarse todo
programa en C. El código de la función principal consiste habitualmente en la definición
de variables locales, la lectura (por teclado o de ficheros) de una serie de datos de
entrada que se almacenarán en las variables definidas. Estas variables serán parámetros
reales o argumentos de entrada para la invocación de las funciones que resuelven el
problema. Finalmente el programa suele terminar mediante la escritura (en pantalla o en
fichero) de los resultados obtenidos. El código irá encerrado entre los caracteres { } que
delimitan su ámbito.
4.6 Definición de funciones. Finalmente el fichero fuente en C termina con la
definición de las funciones que se usan en el programa, bien invocadas desde el main o
bien desde otra función. Las funciones se definen una a continuación de otra. Cada
definición como se ha señalado en la sección 3.3 de este tema, tiene su cabecera con el
tipo que devuelve, nombre de la función, y entre paréntesis y separados por comas los
tipos y nombres argumentos formales. Después entre llaves va el código en C de la
función, que posiblemente defina algunas variables locales a la función (los argumentos
12
También se pueden definir constantes anteponiendo la palabra const delante de la declaración e
inicialización de una variable:
const int VALMAX=100;
Nótese que este tipo de constantes sí llevan declaración de tipo, signo = y punto y coma al final.
Autor: José C. Riquelme (Universidad de Sevilla)
ya están definidos en la cabecera). Si la función devuelve un valor de retorno, entonces
la definición termina con un return13.
4.7 Organización del código. Cuando un programa en C tiene pocas funciones (tres o
cuatro) suele ponerse todo el código en un solo fichero .c. Sin embargo, cuando el
programa se hace más complejo, suele organizarse el código en varios ficheros. La
organización mínima es un fichero de cabecera o .h que normalmente tiene todas las
declaraciones de constantes, tipo y funciones. Un fichero .c con únicamente el programa
principal y otro fichero .c con la definición o código de las funciones. Dependiendo de
la complejidad del problema y de las relaciones entre funciones, se puede organizar el
código con varios ficheros .h y varios .c con las funciones agrupadas por su
funcionalidad.
Los ficheros .h deben ser incluidos en los ficheros .c mediante una declaración de
importación similar a la definida en la sección 4.1 pero en vez de poner el nombre de la
librería .h entre < > se indicaría el nombre del fichero cabecera entre “ ” (dobles
comillas):
#include “tipos_hospital.h”
5. Expresiones.
Una expresión es la formulación de una operación matemática formada por constantes,
variables, operadores y llamadas a funciones. El resultado de una expresión puede ser
un valor numérico y entonces estaríamos ante una expresión aritmética o un valor
booleano y sería una expresión lógica.
5.1 Operadores. Un operador es un carácter o grupo de caracteres que actúa sobre una,
dos o más variables para realizar una determinada operación con un determinado
resultado. Ejemplos típicos de operadores son la suma (+), el producto (*), menor o
igual (<=), etc.
5.1.1 Operadores Aritméticos. Sirven para operar entre valores numéricos. En C se
utilizan los seis operadores siguientes:
– Suma: +
– Resta: – Multiplicación: *
– División: /
– Resto: %
- Cambio de signo: Todos estos operadores se pueden aplicar a constantes, variables y expresiones. El
resultado es el que se obtiene de aplicar la operación correspondiente entre los dos
operandos. El único operador que requiere una explicación adicional es el operador
resto %. En realidad su nombre completo es resto de la división entera. Este operador
13
Realmente una función puede tener varias sentencias return¸ aunque es una buena práctica de
programación que sólo haya un return en cada función.
Tema 2. Primeros pasos en C
se aplica solamente a constantes, variables o expresiones de tipo int. Por ejemplo,
17%3 es 2, puesto que el resto de dividir 17 por 3 es 2. Por tanto, si a%b es cero, a es
múltiplo de b.
Un ejemplo de expresión en la que intervienen operadores aritméticos es el siguiente
polinomio de grado 2 en la variable x:
5.0 + 3.0*x - x*x/2.0
Las expresiones pueden contener paréntesis (...) que agrupan a algunos de sus términos.
Puede haber paréntesis contenidos dentro de otros paréntesis. El significado de los
paréntesis coincide con el habitual en las expresiones matemáticas. Es habitual la
inclusión de espacios en blanco para mejorar la legibilidad de las expresiones.
5.1.2 Operadores de Asignación. Los operadores de asignación sirven para dar valor a
una variable –es decir, asignan a la zona de memoria correspondiente a dicha variable
un valor concreto– el resultado de una expresión o el valor de otra variable (en realidad,
una variable es un caso particular de una expresión).
El operador de asignación más utilizado es el símbolo =14. Su forma general es:
nombre_de_variable = expresion;
La semántica de esta expresión es la siguiente: en primer lugar se evalúa la expresion,
y en segundo lugar se almacena el valor obtenido en la posición de memoria
correspondiente a la variable cuyo identificador aparece a la izquierda del símbolo igual
(realizándose la correspondiente conversión de tipo si es necesario). Por ejemplo, dadas
dos variables x e y, donde x vale 7 e y vale 3
x
7
y
3
después de la asignación
y = x + 1;
el contenido de ambas variables será
x
7
y
8
Como se ve, el efecto de la asignación es destructivo: cuando se asigna un nuevo valor a
una variable se pierde el valor anterior de la variable.
14
No debe ser confundido con la igualdad matemática
Autor: José C. Riquelme (Universidad de Sevilla)
Hay dos errores relacionados y que son típicos en programadores principiantes. Uno es
intentar poner a la izquierda del = una expresión en vez de una variable15, y el segundo
es no entender bien una asignación cuando intervienen sólo dos variables, por ejemplo
x = y;
En este caso, el valor que tuviera y se “almacena” en la dirección de memoria de x,
haciendo que el anterior valor de x “desaparezca”. Por supuesto, la variable y no sufre
ninguna modificación.
Una posible utilización de este operador es como sigue:
variable = variable + 1;
variable = variable - 1;
que incrementa o decrementa el valor de variable en uno. Para estas operaciones que
son habituales, el C proporciona dos operadores que simplifican este tipo de expresiones
escribiendo una única vez el nombre de la variable. Estos operadores son ++ y --. Por
ejemplo, las dos expresiones de arriba son equivalentes a
variable++;
variable--;
Estos dos operadores tienen distinto significado según aparezcan antes o después del
nombre de la variable y además pueden aparecer dentro de expresiones más complejas.
En esta asignatura sólo usaremos los operadores ++ y -- en expresiones simples como
las de arriba.
Existen otros cuatro operadores de asignación (+=, -=, *= y /=) formados por los
cuatro operadores aritméticos seguidos por la asignación. Estos operadores simplifican
algunas operaciones recurrentes sobre una misma variable. Su forma general es:
variable op= expresion;
donde op representa cualquiera de los operadores (+ - * /). La expresión anterior es
equivalente a:
variable = variable op expresion;
Por ejemplo, las dos asignaciones siguientes son equivalentes:
suma += valor;
suma = suma + valor;
5.1.3 Operadores Relacionales. Los operadores relacionales sirven para comparar dos
expresiones aritméticas. Los operadores relacionales de C son los siguientes:
– Igual que: ==
– Menor que: <
– Mayor que: >
15
En este caso el compilador nos avisará del error sintáctico
Tema 2. Primeros pasos en C
– Distinto que: !=
– Menor o igual que: <=
– Mayor o igual que: >=
Su forma general de uso es la siguiente:
expresion1 op expresion2
donde op es uno de los operadores (==, <, >, <=, >=, !=). El funcionamiento
de estos operadores es el siguiente: se evalúan expresion1 y expresion2, y se
comparan los valores resultantes. El resultado de la comparación es un valor de falso o
cierto, lo que en programación se conoce como booleano. Como se ha dicho
anteriormente el ANSI C no tiene un tipo lógico o booleano definido, sino que usa un
tipo int para simular los valores de falso (0) o cierto (1) 16.
Otro error típico entre programadores de C es usar el operador de asignación = como
operador de comparación.
5.1.4 Operadores Lógicos. Los operadores lógicos son operadores que permiten
combinar los resultados de los operadores relacionales, comprobando que se cumplen
simultáneamente varias condiciones, que se cumple una u otra, etc. El lenguaje C tiene
tres operadores lógicos: el operador Y de conjunción lógica (&&), el operador O de
disyunción (||) y el operador NO de negación (!) Su forma general de uso es el
siguiente:
expresion1 || expresion2
expresion1 && expresion2
! expresion
El operador && devuelve un 1 si expresion1 y expresion2 son verdaderas (o
distintas de 0), y 0 en caso contrario, es decir si una de las dos expresiones o las dos son
falsas (iguales a 0).
Por otra parte, el operador || devuelve 1 si al menos una de las expresiones es cierta.
Finalmente, el operador ! cambia el valor de expresion de cierto a falso o viceversa.
En resumen la tabla de verdad de estas operaciones es la siguiente:
a
b
a || b
a && b
!a
falso
falso
falso
falso
cierto
falso
cierto
cierto
falso
cierto
cierto
falso
cierto
falso
falso
cierto
cierto
cierto
cierto
falso
Además de los operadores vistos hasta ahora, el lenguaje C dispone de otros operadores
que veremos más adelante, en especial los operadores que trabajan con direcciones de
memoria.
16
En realidad cualquier valor distinto de 0 es interpretado por el C como cierto.
Autor: José C. Riquelme (Universidad de Sevilla)
5.2 Precedencia y asociatividad. El resultado de una expresión depende del orden en que
se ejecutan las operaciones. Por ejemplo, la expresión 3 + 4 * 2, si se realiza primero
la suma (3+4) y después el producto (7*2), el resultado es 14; si se realiza primero el
producto (4*2) y luego la suma (3+8), el resultado es 11. Para saber en qué orden se
realizan las operaciones es necesario definir unas reglas de precedencia y asociatividad.
La tabla siguiente resume las reglas de precedencia y asociatividad de los principales
operadores en el lenguaje C. Los operadores que están en la misma línea tienen la
misma precedencia, y las filas están en orden de precedencia decreciente.
Operador
Asociatividad
! ++ -- - (cambio de signo)
derecha a izquierda
* / %
izquierda a derecha
+ - (diferencia)
izquierda a derecha
< <= > >=
izquierda a derecha
== !=
izquierda a derecha
&&
izquierda a derecha
||
izquierda a derecha
Por supuesto, el orden de evaluación puede modificarse por medio de paréntesis, pues
siempre se realizan primero las operaciones encerradas en los paréntesis más interiores.
En general, es recomendable el uso de los paréntesis para remarcar y documentar el
orden de las operaciones.
5.3 Funciones matemáticas. Como ya se ha se comentado, en una expresión también
pueden intervenir funciones tanto las definidas por el programador como las que
proporciona el compilador. Las funciones matemáticas más comunes que proporciona el
C incluidas en la librería math.h son:
sin (x)
cos (x)
tan (x)
exp (x)
log (x)
pow (x, y)
sqrt (x)
fabs (x)
seno de x
coseno de x
tangente de x
función exponencial ex
logaritmo natural ln(x), x>0
potencia de x elevado a y
raíz cuadrada de x
valor absoluto de x
En todas estas funciones, tanto los valores de x e y como los resultados son de tipo
double. Los ángulos para las funciones trigonométricas deben estar expresados en
radianes.
Tema 2. Primeros pasos en C
6. Entrada y salida
No hay palabras reservadas del lenguaje que realicen tareas de lectura y escritura, sino
que todas estas operaciones están suministradas por la biblioteca stdio.h, que contiene
un conjunto de funciones de entrada/salida.
6.1 Entrada y salida de caracteres17. La función getchar lee un carácter del teclado y
devuelve su valor cuando se pulsa la tecla de retorno de carro. La función putchar
escribe un carácter en la pantalla. Por ejemplo, siendo ch una variable de tipo char, el
siguiente fragmento de código
ch = getchar ();
putchar (ch);
lee un carácter de la entrada estándar y lo asigna a la variable ch. Después escribe el
mismo carácter en la salida estándar.
6.2 Entrada y salida con formato.
6.2.1 La función printf. La función printf permite escribir una lista de datos de
acuerdo con un formato prestablecido. Acepta diferentes tipos de argumentos: carácter,
valor numérico entero o real, o una cadena de caracteres, y los escribe según un formato
especificado sobre la salida estándar. La forma de la función printf es
printf ("formato", arg1, arg2, ..., argn);
donde los argi pueden ser constantes, variables o expresiones en general, y formato es
una serie de caracteres en la cual se pueden encontrar dos clases de datos: un mensaje o
texto a escribir literalmente, y los símbolos especificadores del formato con el cual se
van a escribir las variables dadas como argumentos. Por ejemplo,
printf ("Esto es un mensaje\n");
Escribe la cadena Esto es un mensaje seguida de un retorno de línea (debido al
'\n'). Los especificadores de formato deben ir precedidos del carácter %. Algunos de
ellos son:
%c
%d
%ld
%f
%lf
%s
17
carácter (char)
número entero (int)
número entero largo (long)
número real (float)
número real (double)
cadena de caracteres
Se refiere a la lectura y escritura de variables de tipo char (un único carácter). La lectura y escritura de
cadenas de caracteres se explicarán cuando se definan.
Autor: José C. Riquelme (Universidad de Sevilla)
Por cada argumento a imprimir debe existir un especificador de formato, que indica el
formato en el cual se va a mostrar el dato. Por ejemplo, siendo letra una variable de tipo
char con el valor 'A', la instrucción
printf ("El código ASCII de %c es %d", letra, letra);
escribiría
El código ASCII de A es 65
mostrándose el mismo dato con dos formatos distintos: como carácter (%c) y como
entero (%d). Obsérvese que hay dos especificadores de formato y dos argumentos
(aunque en este caso sean el mismo).
Otros ejemplos:
printf ("\nEl cuadrado de %f vale %f", x, x*x);
printf ("\nLa edad de %s es %d años", "Juan", edad);
printf ("\nSeno(%lf) = %lf\n", x, sin(x));
La función printf puede emplearse sin argumentos, en cuyo caso sólo se imprimen los
caracteres presentes en la cadena de formato. Entre el símbolo % y el carácter que
especifica la notación a emplear se pueden insertar ciertos caracteres opcionales. Son
los siguientes:



El signo menos (-) para que el dato se ajuste por la izquierda, en lugar de hacerlo
por la derecha, que es lo establecido a falta de especificación explícita.
Un número que indica la longitud mínima en caracteres que tiene el campo
donde se imprimirá el dato correspondiente. Los espacios juegan el papel de
caracteres de relleno.
Un punto decimal (.) seguido de una cifra que indica el número de dígitos
después del punto decimal de un dato flotante, o el número mínimo de dígitos
para un entero, o el número máximo de caracteres de una cadena que serán
impresos.
Por ejemplo:



%6d imprime un número entero (int) alineado por la derecha y en un campo de
al menos seis caracteres.
%-10s imprime una serie de caracteres alineada por la izquierda y asegurando
una longitud mínima de 10 caracteres.
%.4f imprime un número real (float) en coma flotante con un máximo de 4
cifras significativas en la parte fraccionaria.
Tema 2. Primeros pasos en C
6.2.2 La función scanf. La función scanf permite leer valores desde la entrada
estándar (teclado) y almacenarlos en las variables que se especifican como argumentos.
Éstas deben ir normalmente precedidas por el símbolo &18. La sintaxis de scanf es
scanf ("formato", arg1, arg2, ..., argn);
donde debe haber tantos especificadores en la cadena de formato como variables en la
lista de argumentos. Por ejemplo,
scanf ("%d%lf", &n, &x);
para leer un valor n de tipo int y un valor x de tipo double. Estos valores se
introducirán desde la entrada estándar separándolos por espacios o retornos de carro.
En la cadena de formato aparecen especificadores de formato, que son los mismos que
se han visto para printf pero, a diferencia de lo que ocurre con éste, nunca deben
aparecer caracteres que no sean formatos.
6.3 Entrada y salida de C++. En esta subsección se introducen los mecanismos de
lectura y escritura del C++. Tienen la ventaja de ser más fáciles de usar que los del
ANSI C, ya que no exigen especificar el tipo de la variable mediante un formato y
muchos compiladores de C actuales permiten su uso19.
Los objetos de flujo de entrada y salida son cin y cout. El primero cin seguido del
operador >> y una variable, lee lo que se introduce desde la entrada estándar (teclado) y
queda almacenado en dicha variable, por ejemplo:
int numero;
cin >> numero;
El complementario es el operador cout, equivalente a la función printf, pero sin
indicarle el tipo de la variable que queremos imprimir, por ejemplo:
cout << "Vamos a imprimir un numero entero: ";
cout << numero;
Para poder utilizar estos comandos debe poner como cabecera del fichero principal las
siguientes importaciones:
#include <iostream>
using namespace std;
18
La razón para este símbolo se estudiará más adelante.
El compilador Visual C permite usar esta lectura, para ello el código fuente debe tener la extensión
.cpp
19
Autor: José C. Riquelme (Universidad de Sevilla)
7. Ejercicios
1. Indique cuáles de los siguientes identificadores no son válidos y por qué.
a)
b)
c)
X_max
5down
SumaTotal
d)
e)
f)
_total
si_o_no
contador2
g)
h)
i)
si*no
longitud
long
2. Defina las siguientes constantes:
a) una constante entera EOF con valor -1.
b) una constante entera MAXIMO con valor 999.
c) dos constantes enteras CIERTO y FALSO con valores 1 y 0,
respectivamente.
d) una constante carácter ULTIMA_LETRA con valor 'Z'.
e) una constante real PI con valor 3.14159.
f) una constante real EPSILON con valor 0.0001 (utilice la notación
científica).
g) una cadena constante MENSAJE con valor "Error en la entrada de datos".
3. Dadas las siguientes definiciones de constantes
#define
#define
#define
#define
#define
MINIMO 1
MAXIMO 5
VALOR1 7
VALOR2 9
VALOR3 -1
y la siguiente declaración de variable
int numero;
Escriba expresiones lógicas que sean verdaderas si
a) El valor de numero se encuentra en el
las constantes MINIMO y MAXIMO.
b) El valor de numero es uno de los tres
VALOR1, VALOR2 o VALOR3.
c) El valor de numero se encuentra en el
las constantes MINIMO y MAXIMO, o bien
constante VALOR1.
rango definido por
valores constantes
rango definido por
es igual al valor
4. Dadas las siguientes expresiones matemáticas, escriba las correspondientes expresiones
en lenguaje C.
a)
b)
c)
d)
e)
f)
Tema 2. Primeros pasos en C
a x2+bx + c a + b - b + b2 - 4ac
a* b
2a
3
1
1+
a-
1
1+
1+
5
a
a
+
6 120
2
2
sin (x + 1) + cos (x + 1) - 1
1
x
5. Dada la declaración de variables
int a=1, b=5, c=2;
indique el valor de la siguiente expresión lógica:
(((a < b) || (c == 1)) && !(b <= (a - c)))
6. Dadas las variables
int i = 5, j = 7, edad = 15;
double suma = 12.559;
char vocal = 'a';
indique el resultado impreso por las siguientes instrucciones:
a)
b)
c)
d)
e)
f)
g)
h)
printf
printf
printf
printf
printf
printf
printf
printf
("El cuadrado de %d vale %d", i, i*i);
("%3d x %3d = %3d", i, j, i*j);
("%3d x %3d = %10.5f", i, j, i*j);
("La suma es: %.2lf", suma);
("La edad de %s es %d años", "Rosario", edad);
("Nombre
Edad\n%s%4d", "Rosario", edad);
("Nombre
Edad\n%10s%4d", "Rosario", edad);
("Nombre
Edad\n%-10s%4d", "Rosario", edad);
7. El siguiente programa calcula el área de un rectángulo cuyos datos se leen de la entrada
estándar. ¿Qué errores encuentra en el mismo?
include <stdio.h>
void main (void)
{
int base, altura;
printf ("\nCálculo del área de un rectángulo");
printf ("\nPor favor, introduzca base y altura: ");
/* Leer base y altura */
scanf ("%c%c", &base, &altura);
/* Calcular e imprimir área
area = base*altura;
printf ("\n\nEl área del rectángulo es: %d\n", area);
}
Autor: José C. Riquelme (Universidad de Sevilla)
8. Escriba un programa para convertir de grados Fahrenheit a Celsius. La fórmula de
conversión es la siguiente:
5
C = *( F - 32)
9
9. Escriba un programa que lea un instante de tiempo expresado en horas, minutos y
segundos y calcule el número de segundos transcurridos desde las cero horas hasta
dicho instante de tiempo. Utilice la fórmula
segundos_transcurridos = horas * 3600 + minutos * 60 + segundos
10. En los programas anteriores que necesiten leer desde teclado o imprimir en pantalla,
cambie las sentencias scanf y printf por sus equivalentes en C++ con cin y cout.
Descargar