Está en la página 1de 40

I.E.S.

Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación


__________________________________________________________________________________________________________

FUNDAMENTOS DE PROGRAMACIÓN

Tema 3

El C como lenguaje estructurado

1º Administración de Sistemas Informáticos


I.E.S. Francisco Romero Vargas
Departamento de Informática

__________________________________________________________________________________________________________
El C como lenguaje estructurado 0
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

1. HISTORIA DEL C.

Antecedentes del lenguaje C.

 FORTRAN.
A principios de la década de los 50 la mayoría de los programas informáticos
todavía se escribían en ensamblador, con los inconvenientes que ello suponía en cuanto
al esfuerzo a realizar, el tiempo a invertir, etc.. Evidentemente, esa forma de trabajar de
los programadores repercutía negativamente en la economía de las empresas que los
empleaban. Por este motivo, es decir, fundamentalmente por razones de carácter
económico, a finales de 1953 un empleado de IBM propuso la idea de desarrollar un
lenguaje de alto nivel, que se llamaría FORTRAN, de forma que se facilitaría el trabajo
de los programadores y se incrementaría su productividad.
Así pues, a principios de 1955, un grupo de trabajo se dedicó a diseñar e
implementar un compilador de FORTRAN y lo terminó en 1957. Pretendía ser un
lenguaje que se pudiera traducir eficazmente a lenguaje máquina y, además, fácil de
usar. Su notación era similar a la empleada en matemáticas. Su potencia en los cálculos
matemáticos era significativa. Este lenguaje serviría principalmente para desarrollar
aplicaciones técnicas y científicas.
La versión FORTRAN-66 consiguió ser independiente de la máquina, lo que
hizo a este lenguaje más portable. La versión FORTRAN-77 le añade instrucciones para
posibilitar la programación estructurada, el manejo de archivos y el tratamiento de
cadenas de caracteres. La última versión FORTRAN-90 incluye características como
recursividad, manejo de memoria dinámica, etc.
En resumen, podemos considerar al FORTRAN como el más antiguo de los
lenguajes de alto nivel.

 ALGOL
El ALGOL (Algorithmic Languaje -lenguaje algorítmico-) se desarrolló entre
1957 y 1962 con la idea de ser un “lenguaje de programación universal”, de propósito
más general que el FORTRAN y de ser independiente de la máquina. Fue auspiciado
por la americana Association for Computing Machinery (ACM) y por su equivalente
europea, la GAMM. Con el tiempo fue adquiriendo una tendencia algebraica,
orientándose hacia las aplicaciones científicas y de ingeniería. Es un lenguaje de
estructura clara que ha tenido gran influencia en el desarrollo de otros lenguajes de alto
nivel (Pascal y ADA) y en la arquitectura de muchos ordenadores.

El lenguaje C.

Basándose en el lenguaje Algol, en 1967, Martin Richards inventó un nuevo


lenguaje llamado BCPL.
Por otro lado, el M.I.T. (Instituto de Tecnología de Massachussets) y las
compañías AT&T y General Electrics estaban desarrollando lo que pretendían que fuera
un sistema operativo multiusuario capaz de dar servicio a una ciudad con un solo
ordenador (!?). Cuando vieron que el proyecto era demasiado ambicioso dos de ellas
abandonaron, y sólo en el M.I.T. siguieron trabajando en el proyecto. Al final
consiguieron construir el sistema operativo, pero más modesto que el que en un
principio pretendían. Se llamó MULTICS (MULTiplexed Information Computing
System).
__________________________________________________________________________________________________________
El C como lenguaje estructurado 1
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

Uno de los que trabajaron en el proyecto, Ken Thompson, de los Laboratorios


Bell de AT&T, cogió un viejo mini-ordenador DEC PDP-7 que no se utilizaba y, con el
propósito de construir un juego espacial, se fabricó una versión de MULTICS para un
solo usuario. La escribió en ensamblador y, bromeando, le pusieron de nombre UNICS,
por contraposición a MULTICS.
Otros colegas se sumaron a la idea de Thompson. Éste, ya en 1970, modificó el
BCPL con la idea de volver a escribir UNICS en un lenguaje de más alto nivel. El
nuevo lenguaje, por ser un «hijo» del BCPL, se llamó con su inicial: B.
Con la excusa de construir un procesador de texto convencieron a su compañía
de la compra de una DEC PDP-11 y Thompson escribió mientras tanto un compilador
de FORTRAN en B; sin embargo, no pudo rescribir el UNICS en B. Entonces, su
colega Dennis Ritchie lo modificó añadiéndole tipos de datos y otras herramientas de
las que adolecía el lenguaje, y tras otro intento más, consiguieron escribir el sistema
UNICS, que ya se llamó UNIX y además, era multitarea. Como era una derivación del
B, le llamaron con la siguiente letra, tanto del alfabeto como del antecesor BCPL, es
decir: C.

Resumen cronológico
Año Autor Desarrollo
1962 Jonh Backus, ALGOL
Peter Naur,...
1967 Martin Richards Lenguaje BCPL
1970 Ken Thompson Escribe versión de MULTICS en ensamblador
 UNICS
modifica BCPL  lenguaje B
(no consigue escribir UNICS en lenguaje B)
1971 Dennis Ritchie Amplía y modifica el B  lenguaje C
Escribe el UNICS en C  UNIX
1972 Ken Thompson
Dennis Ritchie 1º versión definitiva de C
Brian Kernighan
1984 Bjarne Stroustrup Lenguaje C++
1989 Estándar ANSI C y el ISO C

En 1972, el lenguaje C modificado un poco más por Ritchie, Thompson y


Brian Kernighan, ya era lo suficientemente estable y maduro como para que pudiera
distribuirse junto con el sistema operativo UNIX.
En 1973 la versión 5 se distribuyó gratuitamente por las universidades
americanas, y no es de extrañar el éxito que obtuvo, pues incluía un compilador de C, el
código fuente, el procesador de texto de alta calidad (troff) y muchos programas de
utilidad.

A partir de ahí, la prosperidad del lenguaje C corrió paralela al del UNIX. En


1978 Kernighan y Ritchie escribieron el libro "The C Programming Language", que se
convirtió en el documento de referencia del lenguaje. Tras una serie de añadidos
__________________________________________________________________________________________________________
El C como lenguaje estructurado 2
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

finales al lenguaje ese mismo año, que se recogieron en un anexo del libro, el C se fue
haciendo famoso día a día. Se escribieron compiladores para prácticamente todas las
plataformas.
Con el tiempo, los fabricantes de compiladores empezaron a crear extensiones
del lenguaje, y algunos programadores empezaron a crear variantes, es decir,
lenguajes nuevos aplicados a un propósito específico pero basados en el C. El más
famoso de todos fue, y sigue siendo sin duda, el que Bjarne Stroustrup inventó en
1984, llamado C++.

Estandarización del lenguaje C.

En 1985 se vio claro que había que unificar criterios. Por eso el organismo
americano de estándares (ANSI) creó un comité llamado X3PJ11 para normalizar el
lenguaje. En 1989 el trabajo ya estaba hecho. No obstante, el organismo internacional
de normalización ISO también quiso darle carácter mundial al lenguaje C y creó otro
comité. Ya que el estudio estaba casi hecho no era cuestión de acabar teniendo dos
estándares. Simplemente, el organismo ISO copió la norma elaborada por ANSI, pero se
quejaron de que era demasiado «americano» (evidente, puesto que ANSI es American
National Standards Institute) y entonces empezaron a trabajar en la internacionalización
del lenguaje. Se dice que el C es el último lenguaje de programación sin
internacionalizar (se refieren al tradicional pre-ANSI) y también el primero que se
internacionalizó.
El mismo año 1989 ANSI acabó el trabajo; al año siguiente ISO acabó de
redactar su documento. Los dos son iguales; sólo varía el estilo de la redacción. Así,
podemos hablar de C ANSI o de C ISO indistintamente. El libro de Kernighan y Ritchie
[Kern87] fue revisado y salió una segunda edición un poco antes del estándar definitivo
que recoge casi todas las novedades y cambios del lenguaje.
Sea como fuere, se hizo un buen trabajo. No sólo se normalizó y reguló el
lenguaje sino también una biblioteca auxiliar de funciones que le proporcionan al C
todo lo que de por sí le falta. Entre estas funciones están las de internacionalización.
Mediante ellas es posible que un programa se comporte de forma diferente según el
entorno cultural donde se ejecute. Por ejemplo, mientras que en España o en México
una función que devolviera el nombre del día de la semana daría Domingo, en Gran
Bretaña o EE.UU. daría Sunday; en cambio, un número real se imprimiría en España
como 12,34 mientras que en México lo haría como 12.34.
En septiembre de 1994 se introdujo un anexo que incluía algunas ampliaciones
al sistema de internacionalización: algunas macros y funciones adicionales, y los
ficheros de cabecera <iso646.h>, <wctype.h> y <wchar.h>.
Uno de los puntos de la norma dice que cada cinco años el comité debe volver a
reunirse para revisarla; en efecto, en 1995 se empezó a trabajar en una posible revisión o
modificación y se hicieron algunas propuestas.

2. VENTAJAS DEL C.

Enorme flexibilidad y adaptabilidad.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 3
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

El lenguaje es en sí muy pequeño y versátil, sólo tiene 32 palabras reservadas;


gracias a funciones externas, agrupadas en forma de bibliotecas, se puede adaptar a casi
cualquier tarea.

Compiladores pequeños y fáciles de transportar.

En efecto, al ser el lenguaje muy pequeño y conciso, el compilador también lo


era. Además los primeros compiladores estaban pensados para trabajar muy
rápidamente; no hacían ningún tipo de comprobación sobre el código fuente, dejándole
toda la responsabilidad al programador. Además es fácil escribir en C programas
transportables, y esto incluye al propio compilador.

Concisión en la sintaxis.

A veces se abusa de ello y se llega a perder claridad. C permite poner en un par


de líneas lo que en otros lenguajes parecidos se pondría en una docena.

Hecho por y para programadores.

Como ya se ha dicho el propósito de C fue construir el sistema operativo UNIX


y sus utilidades. Fue hecho por un pequeño número de personas casi por afición, no por
una compañía comercial con cientos de programadores. Las personas que lo hicieron
tenían las ideas muy claras.

Éxito de UNIX, distribución gratuita en ambientes universitarios.

Como también se ha dicho, AT&T tuvo la brillante idea de distribuir


gratuitamente en universidades el UNIX incluyendo todo el código fuente y el
compilador de C (aún hoy con cada sistema UNIX se suele incluir un compilador de C
gratis). Como UNIX estaba escrito en C, quien quería modificar el sistema tenía que
aprender C. Además las universidades son un buen caldo de cultivo, pues los
profesionales que salen de ellas quieren seguir trabajando en entornos que les son
familiares.

Eficiencia en la producción de código objeto.

Muchas veces no merece la pena escribir algo en ensamblador pudiendo hacerse


en C. Tradicionalmente el ensamblador generado por el compilador de C ha sido casi
tan bueno como el que se pudiera escribir directamente, y por supuesto se gana siempre
en claridad, lo que es muy importante a la hora de hacer modificaciones posteriores.

Amplio juego de operadores.

El lenguaje C tiene más operadores que la mayoría de lenguajes comparables, y


son operadores útiles y concisos.

Auge de los PCs y compiladores para DOS y Windows.

El auge de la microinformática ha hecho que la producción de programas para


entornos ofimáticos y caseros aumente extraordinariamente. Esto ha hecho que muchas
__________________________________________________________________________________________________________
El C como lenguaje estructurado 4
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

compañías vendieran compiladores de C que, además, incluían un atractivo entorno de


desarrollo integrado.

3. DESVENTAJAS DEL C.

No se comprueban los límites de los vectores.

La implementación de los vectores es a bajo nivel, como otros aspectos, y el C


no comprueba en absoluto si se sobrepasan los límites en tiempo de ejecución, por lo
que un programa puede referenciar una zona que no tiene reservada, sin que el
compilador proteste. Normalmente esto provocará un error y el programa no funcionará,
pero dependiendo del sistema concreto con el que se trabaje puede que a veces si
funcione, lo cual puede ser peor. La no comprobación de límites era antes una virtud,
pues se buscaba que el compilador fuera sencillo de construir y rápido al trabajar, y se
dejaba la responsabilidad a los programadores de C que se suponía serían expertos y
profesionales. Hoy día las máquinas son mucho más rápidas que en aquella época.

La precedencia de los operadores no es totalmente intuitiva.

En caso de duda, consulte la tabla de precedencia de operadores; si no la tiene a


mano, ponga paréntesis.

La sintaxis puede llegar a ser demasiado concisa.

Enseñarle el listado de un programa medianamente complejo a un profano es


desilusionarlo: sólo verá símbolos extraños. Sin embargo, si el programa está bien
escrito, cualquiera con experiencia lo entenderá todo perfectamente; pero es posible
abusar de la concisión que nos proporciona y dejar el programa completamente ilegible.
Incluso, existe un programa que sirve para ofuscar código fuente en C; esto es oscurecer
o liar el código de tal forma que no se entienda nada pero compile perfectamente. Se
emplea en los casos en que haya que distribuir el código fuente de un programa sin
compilar para que el usuario pueda cambiar ciertos parámetros antes, pero sin que pueda
modificar dicho código o apropiarse de algún algoritmo.
Por otra parte, existen concursos de C ofuscado donde se premia el código
fuente más original, sin que importe mucho lo que haga el programa. Existen algunos
que se listan a sí mismos, uno que calcula el número PI con muchos decimales y ocupa
dos líneas, etc. También se dan premios al programa más feo, o al menos estructurado
(con más gotos), o al que se presenta formando un dibujo, etc

4. CARACTERÍSTICAS DEL C.

El C es un lenguaje de nivel medio.

Esto no significa que sea menos potente, más difícil de utilizar o menos
desarrollado que un lenguaje de alto nivel como puede ser BASIC o Pascal; tampoco
implica que C sea parecido al lenguaje ensamblador y por tanto presente sus problemas
asociados. Por el contrario, manifiesta que el C combina elementos de los lenguajes de
alto nivel con la funcionalidad del lenguaje ensamblador; por ejemplo, permite la
__________________________________________________________________________________________________________
El C como lenguaje estructurado 5
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

manipulación de bits, bytes y direcciones (elementos básicos con los que opera la
computadora). Esto hace que se adapte al desarrollo de software base (programación del
sistema), donde estas operaciones son habituales.

El código C es muy portable.

Portabilidad significa que es posible adaptar el software escrito para un tipo de


computadora a otra. Como muestra, si un programa escrito para un Apple Macintosh se
puede trasladar fácilmente a un IBM PC, se considera portable.

No es un lenguaje de tipos fuertes.

Todos los lenguajes de programación de alto nivel soportan el concepto de tipos


de datos. Un tipo de datos define un conjunto de valores que puede almacenar una
variable junto con un conjunto de operaciones que se pueden realizar sobre esta
variable. Aunque C incorpora cinco tipos de datos básicos (entero, real -simple y doble
precisión-, carácter y vacío), no se trata de un lenguaje de tipos fuertes (como Pascal
o Ada) en los que los datos utilizados deben tener sus tipos declarados explícitamente y
el lenguaje limita la mezcla de tipos en las expresiones. La ventaja de los lenguajes de
tipos fuertes es que se gasta menos esfuerzo en la depuración del programa, ya que el
compilador detecta muchos de los errores causados por la utilización indebida de los
tipos de datos. Así pues, C permitirá casi todas las mezclas de tipos. Por ejemplo, los
tipos entero y carácter se pueden entremezclar libremente en la mayoría de las
expresiones.

El C tiene pocas palabras reservadas.

Sólo tiene 32 palabras reservadas (27 por parte del estándar de Kemighan y
Ritchie y 5 incorporadas por el comité de estandarización ANSI), que son las órdenes
que constituyen el lenguaje C. Los lenguajes de alto nivel normalmente incluyen
algunas más.

El C es un lenguaje estructurado.

Aunque el término lenguaje estructurado en bloques no es aplicable


estrictamente al lenguaje C, normalmente se considera un lenguaje estructurado por las
similitudes en su estructura con ALGOL, Pascal y Modula-2. Técnicamente, un
lenguaje estructurado en bloques permite que los procedimientos y funciones se
declaren dentro de otros procedimientos o funciones. De esta forma, los conceptos de
«global» y «local» se extienden mediante la utilización de reglas de ámbito adicionales,
que establecen la «visibilidad» de una variable o procedimiento. C no se puede
considerar realmente estructurado en bloques, puesto que no permite la creación de
funciones dentro de funciones.
La característica que distingue a un lenguaje estructurado es la
compartimentalización del código y los datos, o sea, la capacidad de un lenguaje de
dividir y ocultar del resto del programa toda la información e instrucciones necesarias
para llevar a cabo una determinada tarea. Una forma de llevarla a cabo es utilizar
subrutinas que empleen variables locales (temporales), mediante las cuales el
programador puede conseguir que los eventos que se producen dentro de las mismas no
causen efectos colaterales en otras partes del programa. Esta capacidad hace que sea
__________________________________________________________________________________________________________
El C como lenguaje estructurado 6
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

muy fácil que programas en C compartan secciones de código. Si se desarrollan


funciones compartimentalizadas, sólo se necesitará conocer qué es lo que hace una
función y no cómo lo hace. Recuérdese que el uso excesivo de variables globales
(variables con ámbito en todo el programa) puede hacer que los errores proliferen en el
programa, al permitir los efectos colaterales no deseados.

Un lenguaje estructurado permite muchas posibilidades en programación:


Soporta directamente distintas construcciones de bucles, como pueden ser while, do-
while y for; la utilización de goto está totalmente prohibida o desaprobada; permite
sangrar instrucciones, etc. Los lenguajes estructurados son más recientes que los no
estructurados (COBOL, BASIC, etc.). Hoy en día se ha aceptado ampliamente que la
claridad de los lenguajes estructurados facilita la programación y el mantenimiento.
Realmente, muy pocos programadores podrían considerar seriamente la posibilidad de
utilizar un lenguaje no estructurado para nuevos desarrollos de software.
El componente principal de la estructura de C es la función (una subrutina
independiente de C). En C las funciones son bloques constituyentes en donde tiene
lugar toda la actividad del programa. Permiten que tareas distintas de un programa se
definan y se codifiquen de forma separada, permitiendo así la modularidad de los
programas. Después de crear una función, se puede utilizar de forma apropiada en
varias situaciones, evitando la creación de efectos colaterales en otras partes del
programa. El hecho de que se puedan crear funciones independientes es
extremadamente crítico en grandes proyectos donde el código de un programador no
debe afectar accidentalmente al de otro.
Otra forma de estructurar y compartimentalizar código en C es utilizar bloques
de código. Un bloque de código es un grupo de instrucciones de programa conectadas
lógicamente que es tratado como una unidad. En C, un bloque de código se crea
colocando una secuencia de instrucciones entre llaves. En este ejemplo,

if (x<10)
{
printf(“Demasiado pequeño, inténtelo de nuevo.\n”);
restablecer_contador(-1);
}
}
las dos instrucciones que aparecen entre llaves tras el if se ejecutarán si x es menor que
10. Estas dos instrucciones, junto con las llaves, constituyen un bloque de código. Se
trata de una unidad lógica: una de las instrucciones no se puede ejecutar sin la otra. Los
bloques de código no solamente permiten implementar muchos algoritmos con claridad,
elegancia y eficiencia sino que también ayudan al programador a asimilar la verdadera
naturaleza de la rutina.

El C es un lenguaje para programadores.

Todos los lenguajes de programación no están hechos para los programadores.


Por ejemplo, COBOL se diseñó para permitir a los no programadores comprender los
programas de gestión (aplicaciones comerciales, orientadas a negocios); BASIC se creó
esencialmente para introducir a los estudiantes en la programación; PASCAL se diseño
para enseñar computación a los estudiantes universitarios; etc. Por contra, C fue creado,
influenciado y probado por programadores profesionales. El resultado final es que C
ofrece al programador lo que éste quiere: pocas restricciones, pocas pegas, estructuras
__________________________________________________________________________________________________________
El C como lenguaje estructurado 7
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

de bloques, funciones independientes y un conjunto compacto de palabras reservadas.


Es muy interesante que mediante la utilización de C, un programador pueda alcanzar
casi la eficiencia del código ensamblador, combinada con la estructura de ALGOL o
Modula-2. Por tanto no es de extrañar que C sea uno de los lenguajes más populares
entre los programadores profesionales de élite.

Ventajas respecto al lenguaje ensamblador.

El hecho de que C se utilice a menudo en lugar del lenguaje ensamblador


contribuye mucho a su popularidad entre los programadores. El lenguaje ensamblador
utiliza una representación simbólica del código binario real que la computadora ejecuta.
Cada operación en lenguaje ensamblador se corresponde con una tarea básica que la
computadora ejecuta. Aunque el lenguaje ensamblador ofrece a los programadores la
potencia de realizar las tareas con la mayor flexibilidad y eficiencia, es notoriamente
difícil trabajar con él en el desarrollo y depuración de un programa. Más aún, como el
lenguaje ensamblador no es estructurado, el programa final tiende a ser código
«espagueti» (un complejo desorden de saltos, llamadas e indexaciones). Esta falta de
estructuración provoca que los programas en lenguaje ensamblador sean difíciles de
leer, mejorar y mantener. Quizás lo más importante sea que las rutinas del lenguaje
ensamblador no son portables entre máquinas con unidades de procesamiento central
diferentes.
Inicialmente, C se utilizó para la programación de sistemas. Un programa de
sistemas forma parte de una amplia clase de programas que constituyen el software base
de una computadora o de sus utilidades de soporte. Por ejemplo, los siguientes se
denominan normalmente programas de sistemas: Sistemas operativos, Intérpretes,
Editores, Programas específicos, Compiladores, Administradores de bases de datos, etc.

Portabilidad del C.

Conforme C crecía en popularidad, muchos programadores comenzaban a


utilizarlo para programar todas las tareas debido a su portabilidad y eficiencia. Dado que
existen compiladores de C para la mayoría de las computadoras, es posible utilizar el
código escrito para una máquina, y compilarlo y ejecutarlo en otra con pocos o ningún
cambio. Esta portabilidad ahorra tanto tiempo como dinero. Además, los compiladores
de C tienden a generar código objeto más compacto y rápido que la mayoría de los otros
tipos de compiladores.

Eficiencia del C.

Quizás la razón más significativa por la que C se utiliza para todo tipo de tareas
de programación es que a los programadores ¡les gusta!. C ofrece la velocidad del
lenguaje ensamblador y la extensibilidad de FORTH, aunque tiene algunas de las
restricciones de Pascal o Modula-2. Cada programador de C puede crear y mantener una
biblioteca única de funciones que se ajuste a su personalidad y que puede utilizar en
diferentes programas. Puesto que C permite (de hecho fomenta) la compilación
separada, ofrece a los programadores poder gestionar proyectos con facilidad y
minimizar la duplicidad de esfuerzos. Y, por supuesto, es el lenguaje sobre el que está
desarrollado C++.

Compiladores frente a intérpretes.


__________________________________________________________________________________________________________
El C como lenguaje estructurado 8
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

Los términos compilador e intérprete se refieren a la forma de ejecutar un


programa. En teoría, cualquier lenguaje de programación puede ser compilado o
interpretado, pero algunos se suelen ejecutar en una forma o en otra. Por ejemplo,
normalmente, BASIC es interpretado y C es compilado. La forma de ejecutar un
programa no viene definida por el lenguaje en el que se haya escrito. Los intérpretes y
compiladores son simplemente programas sofisticados que trabajan sobre el código
fuente del programa.
Un intérprete lee el código fuente del programa línea a línea, realiza las
instrucciones específicas contenidas en esa línea y, a continuación, pasa a la siguiente
línea. Un compilador lee el programa entero y lo convierte en código objeto, que es una
traducción del código fuente del programa a un formato que puede ejecutar
directamente la computadora. El código objeto también se denomina código binario y
código máquina. Una vez compilado un programa, una línea de código fuente deja de
tener significado en la ejecución del programa.
Cuando se utiliza un intérprete, el código fuente debería estar presente cada vez
que se quiere ejecutar el programa. Por ejemplo, en BASIC tradicional se tiene que
ejecutar primero el intérprete de BASIC y, a continuación, cargar el programa y escribir
RUN cada vez que se desea utilizarlo. Luego, el intérprete de BASIC examina el
programa línea a línea, para ver si es correcta, y a continuación la ejecuta. Este lento
proceso se realiza cada vez que se ejecuta el programa. Por contra, un compilador
convierte un programa a código objeto que puede ejecutar directamente la computadora.
Debido a que el compilador traduce el programa una sola vez, lo único que hay que
hacer es ejecutarlo directamente, normalmente mediante el simple proceso de escribir su
nombre. Por tanto, la compilación sólo se realiza una sola vez, mientras que el código
interpretado conlleva un costo de tiempo cada vez que se ejecuta el programa.
Dos términos que aparecerán con frecuencia son tiempo de compilación, que se
refiere a los eventos que ocurren durante el proceso de compilación, y tiempo de
ejecución, que se refiere a los eventos que ocurren mientras se ejecuta el programa.
Normalmente, estos términos se verán en las discusiones de errores, como pueden ser en
las frases «errores en tiempo de compilación» y «errores en tiempo de ejecución».

5. FORMATO DE UN PROGRAMA EN C.

Palabras reservadas.

La siguiente tabla muestra las 32 palabras reservadas que, junto con la sintaxis
formal de C, constituyen el lenguaje de programación C.

auto extern sizeof


break float static
case for struct
char goto switch
const if typedef
continue int union
default long unsigned
do register void
double return volatile
else short while
enum signed
__________________________________________________________________________________________________________
El C como lenguaje estructurado 9
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

Todas las palabras reservadas de C están en minúsculas. En C, las mayúsculas y


minúsculas tienen un tratamiento diferente: else es una palabra reservada; ELSE no lo
es. Una palabra reservada no se puede utilizar para cualquier otro propósito en un
programa en C (es decir, no se puede utilizar como nombre de variable o de función).

Funciones.

Todos los programas en C están constituidos por una o más funciones, las cuales
son los módulos básicos del programa y, al menos, una de ellas debe llamarse main() -
que significa "principal"-. Es decir, todo programa debe tener, al menos, una función
denominada main(), y se trata de la primera que se llama cuando comienza la ejecución
del programa. En un código C escrito correctamente, main() engloba el esbozo o
esqueleto de lo que realiza el programa; dicho esqueleto está compuesto por las
llamadas a las funciones. En definitiva, un programa en C siempre comienza
ejecutándose por la función main(); las demás funciones son llamadas desde main(), y
por tanto, se puede considerar que ésta es, por sí misma, el programa.
Aunque técnicamente main() no forma parte del lenguaje C, se debe tratar como
si lo fuera. Por ejemplo, no intente utilizar main como nombre de una variable.
El formato general de un programa en C se muestra en la siguiente figura, donde
f1() a fN() representan funciones definidas por el usuario y una de ellas debe ser main().

declaraciones globales
tipo_devuelto main(lista de parámetros)
{
secuencia de instrucciones
}
tipo_devuelto f1 (lista de parámetros)
{
secuencia de instrucciones
}
tipo_devuelto f2 (lista de parámetros)
{
secuencia de instrucciones
}
......................
tipo_devuelto fN (lista de parámetros)
{
secuencia de instrucciones
}

Ejemplo:
..............
void main(void)
{
int operando1, operando2;
int resultado_suma, resultado_producto;
..........
resultado_suma = suma(operando1, operando2);
resultado_producto = producto(operando1, operando2);
..............
}
int suma (int op1, int op2)
{
return op1 + op2;
}
int producto (int op1, int op2)
__________________________________________________________________________________________________________
El C como lenguaje estructurado 10
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

{
return op1 * op2;
}

El nombre de una función va seguido de unos paréntesis entre los cuales puede ir
o no uno o más argumentos. Una función consta de un encabezamiento (en el que va
incluido su nombre) y de un cuerpo, que está delimitado por llaves: { y } . El cuerpo
consiste en una serie de sentencias, cada una de las cuales termina en punto y coma.
Se hablará detenidamente de las funciones en el tema siguiente.

Directivas del preprocesador.

En el encabezamiento de los programas encontraremos instrucciones para el


compilador de las que hablaremos ampliamente más adelante. Por ahora, nos fijaremos
sólo en la directiva #include. Por ejemplo, la línea

#include <stdio.h>

le indica al compilador que incluya en el programa datos del fichero stdio.h el cual se
suministra como parte del compilador y aporta información sobre aspectos
relacionados con la E/S de datos : funciones como printf(), scanf(), getchar(), ... Es
conveniente añadir siempre dicha línea pues no hay regla segura de cuando se necesitará
esa información; además, el compilador sólo tomará del mencionado fichero la
información que necesite y cualquier otra que no sea de utilidad no formará parte del
programa y, por tanto, no hará que sea más largo innecesariamente.

Sentencias.

Las sentencias que componen una función no van numeradas y se ejecutan


secuencialmente, de arriba a abajo, unas a continuación de otras, sin saltos hacia atrás.
Para una buena legibilidad del programa conviene escribir cada sentencia en una línea.
El símbolo punto y coma (;) del final de cada línea identifica a ésta como una sentencia
C o instrucción. Hay que tener por ello en cuenta que el punto y coma es parte de la
sentencia y no es un separador de sentencias, como ocurre en el lenguaje Pascal.
No obstante, en cada línea se puede escribir más de una sentencia, o bien, se
puede espaciar una sentencia en más de una línea (no se debe partir en mitad del texto
entrecomillado); y será el compilador el que averigüe dónde termina una sentencia y
comienza la siguiente por medio de los puntos y comas introducidos.

Comentarios.

Es interesante usar comentarios para hacer más comprensibles los programas. Se


utilizan los símbolos /* y */ para delimitarlos, y todo el texto encerrado entre ellos
será ignorado por el compilador. Ello posibilita cualquier disposición de los
comentarios en el programa: por ejemplo, al final de una sentencia, o bien, ocupando
más de una línea. Los comentarios no pueden anidarse.
Un comentario estilo C++ comienza con los caracteres // y termina al final de la
línea, es decir: estos comentarios no pueden ocupar más de una línea.
En general, el estilo C se utiliza para comentarios de más de una línea, y el estilo
C++, para comentarios de una sola línea.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 11
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

6.TIPOS DE DATOS.
Existen cinco tipos de datos básicos en C: caracteres (char), enteros (int), punto
flotante (float), doble punto flotante (double) y sin valor (void).

- Los valores del tipo char se utilizan para almacenar caracteres ASCII o
cualquier cantidad de 8 bits.
- Las variables del tipo int se utilizan para almacenar cantidades enteras.
- Las variables del tipo float y double almacenan números reales.
- El tipo void se utiliza en tres casos:

1º. Para declarar explícitamente el tipo de una función que no


devuelve ningún valor.
2º. Para declarar explícitamente una función que no tiene
parámetros.
3º. Para crear punteros genéricos.

C soporta otros tipos distintos, incluyendo estructuras, uniones, campos de bits,


enumeraciones y tipos definidos por el usuario que se explicarán más adelante.

Modificadores de tipo.

A excepción del tipo void, pueden añadirse distintos modificadores precediendo


a los tipos de datos básicos. Un modificador se utiliza para alterar el significado del tipo
básico para que se ajuste de manera más precisa a las necesidades de cada situación.
Tales modificadores son: signed, unsigned, long y short.

- Todos ellos se pueden aplicar a los tipos enteros base.


- Se puede aplicar unsigned y signed a los caracteres.
- Se puede aplicar long al tipo double.
- La utilización de signed sobre enteros es redundante (pero permitida) debido a
que la declaración por omisión del entero asume un número con signo. Lo
mismo ocurre cuando se aplica al tipo char.

La tabla siguiente muestra todas las combinaciones permitidas que se ajustan al


estándar ANSI de C para tamaños de palabra de 32 bits, junto con sus rangos y
longitudes en bits, tal como se implementan en Borland C++. (Para tamaños de palabra
de 16 bits, sólo cambia * de 32 a 16 bits).

Tamaño en bits Tipo Rango


8 char = signed char -128 a 127
unsigned char 0 a 255
16 short int = signed short int -32768 a 32767
unsigned short int 0 a 65535
32(*) int = signed int -2147483648 a 2147483647
unsigned int 0 a 4294967295
32 long int = signed long int -2147483648 a 2147483647
unsigned long int 0 a 4294967295
32 float 3.4E-38 a 3.4E+38
64 double 1.7E-308 a 1.7E+308
80 long double 3.4E-4932 a 1.1E+4932

__________________________________________________________________________________________________________
El C como lenguaje estructurado 12
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

7. DECLARACIÓN DE VARIABLES.
La declaración de variables consiste en asociar un tipo de datos determinado a
una variable. Todas las variables a usar en un programa se deben declarar antes de
utilizarlas. A continuación, se muestra el formato general de una declaración:

tipo lista_variables;

Aquí, tipo debe ser un tipo de dato válido en C y lista_variables puede estar
constituida por uno o más nombres de identificadores separados por comas.

unsigned int anio_nacimiento, numero_socios;


float importe, total_compra;
double distancia_sol, peso;
char letra, digito ;

Es posible inicializar una variable (asignarle un valor inicial) en el momento de


su declaración: para ello basta con poner un signo igual (=) a continuación del nombre
de la misma, seguido de la constante correspondiente al tipo adecuado de ésta.

int dia = 15; // declaración e inicialización


short int coord_x =10, coord_y =12 ;
char caracter = ‘z’;
int blancos=11, negros=15, verdes=30;

No conviene mezclar, en una misma línea, variables que sólo se declaran con
otras que se inicializan.

8. CONSTANTES.
Las constantes en C se refieren a valores fijos que no puede modificar el
programa.

Las constantes literales representan valores fijos que pueden ser de cualquier
tipo de dato, como se muestra en la siguiente tabla.

Tipo de dato Ejemplos


char ‘a’ ‘\n’ ‘9’
int 974 21000 -345
long int 20000L -15000L
short int -100 120
unsigned int 20000U 50000U
float 475.231F 9.87e2
double 987.654 -0.00345

C soporta, además de las constantes correspondientes a los tipos de datos


predefinidos, las constantes de tipo cadena que se encierran entre comillas dobles. No se
deben confundir las cadenas de caracteres con las constantes de tipo carácter que se

__________________________________________________________________________________________________________
El C como lenguaje estructurado 13
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

encierran entre comillas simples (apóstrofos). Debido a que las cadenas son
simplemente vectores de caracteres, se tratarán más adelante.
Encerrar todas las constantes de carácter entre apóstrofos funciona para la
mayoría de los caracteres de impresión, pero algunos, como el retorno de carro, son
imposibles de introducir desde el teclado. Por esta razón, C utiliza las constantes de
carácter especiales de barra invertida -mostradas en la siguiente tabla- cada uno de las
cuales equivale a un carácter único.
Se puede utilizar un código de barra invertida exactamente de la misma forma
que se haría con cualquier otro carácter; por ejemplo, se puede asignar a una variable de
tipo char.

Código Significado
\n nueva línea
\t tabulador horizontal
\v tabulador vertical
\b Retroceso
\’ Apóstrofo
\r retorno de carro
\” Comillas
\f salto de página
\0 carácter nulo
\a Alarma
\ooo constante octal (ooo = valor octal)
\xhh constante hexadecimal (hh = valor hexadecimal)
\\ barra atrás

Las constantes con nombre se pueden declarar en C de dos maneras:

- Usando la directiva del preprocesador #define.

Ej. #define PI 3.141592

En cuyo caso se estará indicando al compilador que antes de realizar la


compilación sustituya dentro del programa fuente todas las apariciones
de PI por el valor 3.141592

- Anteponiendo la palabra reservada const delante de la declaración del


objeto.

Ej. const int PI=3.141592;

En cuyo caso se indicará al compilador que PI es un objeto cuyo valor no


puede ser modificado durante el programa. Cualquier intento de
modificación del valor de PI provocaría un error de compilación.

Es costumbre entre los programadores de C declarar las constantes con nombre


en mayúsculas.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 14
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

9. OPERADORES.
Una característica del lenguaje C es la cantidad de variedad de operadores que
tiene, es decir, símbolos que operan sobre operandos (objetos) para producir los valores
deseados. Cualquier combinación válida de operadores con los operandos necesarios
constituye una expresión; una expresión completa que finaliza en un punto y coma es
una sentencia y una serie de sentencias componen un programa. La importancia de
operadores y expresiones es pues evidente; se encuentran entre las unidades de
construcción fundamentales de un programa en C.

Operadores aritméticos.

En la siguiente tabla se muestra una lista de los operadores aritméticos


permitidos en C.

Operador Acción
- Resta, también signo menos unario.
+ Suma.
* Multiplicación
/ División
% Módulo de la división.
-- Decremento.
++ Incremento.

- Los operadores +, -, * y / funcionan de la misma forma en C que en la mayoría


de los lenguajes de programación. Estos se pueden aplicar a casi cualquier tipo
de dato predefinido de los que permite C.
- El menos unario, en realidad, multiplica su único operando por -1. Esto es,
cualquier número precedido por un signo menos cambia su signo.
- Cuando se aplica / a un entero o a un carácter, se trunca el resto de la división, es
decir, se obtiene la división entera; por ejemplo, la división entera de 10/3 es
igual a 3.
- El operador módulo de la división % también funciona en C de la forma en que
lo hace en otros lenguajes: la operación módulo de la división calcula el resto de
una división entera. Sin embargo, % no se puede utilizar sobre los tipos float
o double.

El siguiente fragmento de código ilustra su uso:

int x=10, y=3;


printf(“%d %d \n”, x/y, x%y ); // mostrará 3 y 1
x=1;
y=2;
printf(“%d %d \n”, x/y, x%y ) ; // mostrará 0 y 1

- C permite dos operadores muy útiles que, generalmente, no se encuentran en


otros lenguajes de programación. Estos son los operadores de incremento (++) y
decremento (--). El operador ++ suma 1 a su operando, y el operador -- le
resta 1. Por tanto, las siguientes operaciones son equivalentes:

variable = variable + 1; es equivalente a ++variable;

__________________________________________________________________________________________________________
El C como lenguaje estructurado 15
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

variable = variable - 1; es equivalente a –-variable;

Los operadores de incremento y decremento pueden preceder (modalidad


prefijo) o suceder (modalidad sufijo) al operando.

Modalidad sufijo: variable++ variable--


Modalidad prefijo: ++variable --variable

Es indiferente escoger una modalidad u otra cuando la variable afectada de este


operador va sola en una sentencia.
...
variable1 = variable2 = 0;
variable1++;
++variable2;
printf("%d %d",variable1,variable2); // Salida: 1 1
...

Sin embargo, cuando el operador y su operando forman parte de una expresión


mayor (por ejemplo, van en sentencias de asignación o en sentencias de salida por
pantalla) existe una diferencia en utilizar la modalidad prefijo o la modalidad sufijo, que
radica en el momento en que se realiza la operación de incremento o de decremento:

- En el modo sufijo, primero se utiliza la variable afectada por el operador de


incremento o decremento, y luego se incrementa o decrementa en 1 el valor de la
variable. Ejemplo: la sentencia...

q = 2 * a++;

multiplica «a» por 2, asigna el resultado a «q» y luego incrementa «a»

- En el modo prefijo, primero se incrementa o decrementa la variable afectada


por el operador y luego se opera con ella. Ejemplo: la sentencia...

q = 2 * ++a;

incrementa «a» en 1, después multiplica su valor por 2 y luego asigna el resultado a


«q».

#include <stdio.h>
/#include <conio.h>
void main(void)
{
int a=1, b=1;
int a_mas, mas_b;
a_mas = a++;
mas_b = ++b;
printf(" a a_mas b mas_b\n");
printf("%5d%5d%5d%5d\n", a, a_mas, b, mas_b); //Salida: 2 1 2 2
getch();
}

- C tiene una taquigrafía especial que simplifica la codificación de un cierto tipo


de instrucciones de asignación. En general,

__________________________________________________________________________________________________________
El C como lenguaje estructurado 16
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

variable = variable + expresion;

se puede escribir, en taquigrafía de C, como:

variable += expresion;

Esta taquigrafía funciona para todos los operadores binarios de C.

Operadores relacionales y lógicos.

A diferencia de otros lenguajes, una expresión de relación o una expresión


lógica, si es cierta toma el valor 1, y si es falsa toma el valor 0. Por ejemplo, la
expresión
var_entera = ( 'b' > 'a' );

le está asignando 1 a la variable var_entera.


La clave de los conceptos de operadores relacionales y lógicos es la idea de
verdadero y falso. En C, verdadero es cualquier valor distinto de 0. Falso es 0. Las
expresiones que utilizan los operadores relacionales y lógicos devolverán 0 para falso y
1 para verdadero.

Operadores relacionales

Operador Acción

> Mayor que


>= Mayor o igual que.
< Menor que.
<= Menor o igual que.
== Igual.
!= Distinto.
Operadores lógicos

Operador Acción

&& AND (Y)


|| OR (O)
! NOT (NO)

Operadores a nivel de bit.

Puesto que C se diseñó para sustituir al lenguaje ensamblador en la mayoría de


las tareas de programación, soporta un completo complemento de operadores a nivel de
bit. Estos son la comprobación, configuración o desplazamiento de los bits actuales de
un byte o una palabra, que se corresponden con los tipos de datos char e int (NUNCA
con los tipos float, double, long double y void).

Operadores a nivel de bit


Operador Acción

__________________________________________________________________________________________________________
El C como lenguaje estructurado 17
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

& Y
| O
^ O exclusivo (XOR)
˜ Complemento a uno
>> Desplazamiento a la derecha (divide por 2)
<< Desplazamiento a la izquierda (multiplica por 2)

Ejemplos:
x << 2;
z=x & y;
z=120^127;

El operador en tiempo de compilación sizeof.

sizeof es un operador unario en tiempo de compilación que devuelve la longitud,


en bytes, de la variable o el especificador de tipo encerrado entre paréntesis al que
precede. Por ejemplo:

float f;
printf(“%f”, sizeof f); // 4
printf(“%d”, sizeof(int));// 4 (suponiendo enteros de 32 bits)

La utilidad principal de sizeof es ayudara generar código portable cuando dicho


código depende del tamaño de los tipos de datos incluidos en C.

En C existen, además, otros operadores que iremos estudiando en apartados


posteriores como ? y : (condicional), & y * (punteros) y -> y . (elementos de estructuras
y uniones).

Precedencia de los operadores.

El compilador evalúa de izquierda a derecha los operadores con el mismo nivel


de precedencia. Por supuesto, se pueden utilizar paréntesis para modificar el orden de
evaluación. La precedencia de operadores usada en C atiende a la siguiente tabla.

Denominación Operadores Función


Expresión () Paréntesis
[] Corchetes de indexación
. Operador de estructura
-> Operador de puntero a estructura
Unitarios - Cambio de signo
˜ NOT binario
! NOT lógico
* Contenido de la dirección de un puntero
& Dirección de memoria de una variable
++ Incremento
-- Decremento
sizeof(tipo) Tamaño en tiempo de ejecución
Multiplicativos * Multiplicación
/ División
% Resto de la división
Aditivos + Suma
__________________________________________________________________________________________________________
El C como lenguaje estructurado 18
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

- Resta
De movimiento de bits >> Desplazmiento de bits a la derecha
<< Desplazamiento de bits a la izquierda
Relacionales > Mayor que
>= Mayor o igual que
< Menor que
<= Menor o igual que
== Igual que
!= Distinto de
Binarios & AND binario
| OR binario
^ XOR binario
Lógicos && AND lógico
|| OR lógico
Condicionales ?: if..else abreviado
Asignaciones abreviadas =
*=
/=
%=
+=
-=
<<=
>>=
&=
|=
^=
Otros , Operador coma

- Los operadores relacionales y lógicos tienen menor precedencia que los


operadores aritméticos. Este significa que una expresión como 10 > 1+12 se evalúa
igual que si se hubiera escrito 10 > (1+12) . El resultado es, por supuesto, falso.
Se pueden combinar varias operaciones en una expresión, como se muestra a
continuación:

10>5&&!(10<9)113<=4

cuya evaluación será verdadera.

- Como sucede con las expresiones aritméticas, se puede hacer uso de los
paréntesis para modificar el orden natural de evaluación de una expresión relacional o
lógica. Por ejemplo: !1&&0 será falso puesto que primero se evalúa ! (NOT) y, a
continuación, se evalúa && (AND). Sin embargo, cuando se utilizan paréntesis en la
misma expresión: !(1&&0) , el resultado es verdadero.

- Recuérdese que todas las expresiones relacionales y lógicas generan un resultado


de 0 ó 1. Por tanto, el siguiente fragmento de programa es totalmente correcto

int x;
x = 100;
printf(“%d”, x>10); // muestra 1

- Una ventaja del operador incremento es que genera un código compilado


ligeramente más eficiente, ya que su estructura se asemeja más al código máquina real.
Además, hay que tener en cuenta que x*y++ significa x*(y++) y no (x*y)++ lo
cual carece de sentido.
__________________________________________________________________________________________________________
El C como lenguaje estructurado 19
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

- No se deben utilizar operadores de incremento o decremento en variables que se


emplean más de una vez como argumento de una función o más de una vez en una
misma expresión ya que el resultado depende de qué argumento (o término) evalúe
primero el sistema.

#include <conio.h>
int num, a, b, c;
void main(void)
{ // Expresiones no aconsejables:
num = 5;
printf ("%10d %10d\n", num, num*num++); // 6 30
num = 5;
a = num/2 + 5*(1 + num++);
printf ("%10d %10d\n", num, a); // 6 32
a=8;
b=5;
c = a * b / 5 + ( a * b++);
printf ("%10d %10d %10d\n", c, b, a); // 48 6 8
a=8;
b=5;
c = (a * b++) + a * b / 5;
printf ("%10d %10d %10d\n", c, b, a); // 48 6 8
a=8;
b=5;
c = a * b++ + ( a * b / 5);
printf ("%10d %10d %10d\n", c, b, a); // 48 6 8
getch();
}

10. CADENAS DE CARACTERES.


Una cadena de caracteres (string) consiste simplemente en una serie de uno o
más caracteres. Ejemplos: "Esto es una tira" ,"x" , etc. Las comillas no forman parte de
la cadena, sino que sirven para especificar su comienzo y su final. Las cadenas se
declaran igual que los arrays unidimensionales (un array es una secuencia ordenada de
datos de un determinado tipo):

char nombre_cadena [longitud];

En C no existe el tipo cadena y por ello hay que declararla como un array de tipo
char. Ello permite imaginar los caracteres de la cadena (mejor dicho, sus códigos)
almacenados en posiciones de memoria adyacentes, cada una de las cuales puede
almacenar un valor de tipo char. Ocupando la última posición del array el compilador
del C (o el programador) coloca el carácter nulo \0 (código ASCII = 0) para indicar el
final de la cadena de caracteres. Por esta razón, para declarar arrays de caracteres es
necesario que la longitud del array tenga un carácter más que la cadena más larga que
pueda almacenar.
Hay que destacar que no es lo mismo, por ejemplo, el carácter 'x' que la cadena
"x", puesto que el primero pertenece a un tipo básico char mientras que el segundo es un
tipo derivado: un array de char y, además, contiene dos caracteres: 'x' y \0 .
Para manejar tanto la entrada -scanf()- como la salida -prinft()- de la cadena se
usa el especificador %s .
La función strlen() nos informa de la longitud de una tira en caracteres, y si es
un variable, deja de contar al llegar al carácter nulo, no importando si se ha declarado
una longitud mayor.
__________________________________________________________________________________________________________
El C como lenguaje estructurado 20
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

Por su parte, el operador sizeof nos facilitará la longitud del array, o sea, el
valor indicado en su declaración, o bien, en caso de definir una cadena (constante) en el
encabezamiento, contará su longitud, incluyendo el carácter nulo.
Las cadenas de caracteres se estudiarán a fondo en el tema “Estructuras
estáticas”.

11. INSTRUCCIONES DE ASIGNACIÓN.


Se utilizan las sentencias de asignación para dar un valor a las variables ya
declaradas; posteriormente se les podrá dar, si es necesario, un valor diferente. El
formato general de la instrucción de asignación es:

nombre_variable = expresión;

donde la expresión puede ser tan sencilla como una única constante o tan compleja
como una combinación de variables, operadores y constantes. El C utiliza un único
signo igual para indicar una asignación (a diferencia de Pascal o Modula-2, que utilizan
el constructor :=). El destino, o la parte izquierda, de la asignación debe ser una
variable, no una función o una constante.
Además de mediante instrucciones de asignación, también se puede asignar un
valor a una variable a través de las funciones de entrada de datos -por ejemplo, scanf()-
que permite introducir datos a través del teclado.

Asignaciones múltiples.

C permite asignar el mismo valor a varias variables utilizando asignaciones


múltiples en una única instrucción. Por ejemplo, este fragmento de programa asigna a
las variables coordx, coordy y coordz el valor 0:

coordx = coordy = coordz = 0;

En los programas profesionales, a las variables se les asignan frecuentemente


valores comunes utilizando este método.

Conversión de tipo en asignaciones.

La conversión de tipo se refiere a la situación en la que variables de un tipo se


mezclan con variables de otro tipo (véase el APÉNDICE de este capítulo). Cuando
ocurre esto en una instrucción de asignación, la regla de conversión de tipos es muy
sencilla:

El valor de la parte derecha (expresión) de la asignación se convierte al tipo de


la parte izquierda (variable destino)

El siguiente ejemplo ilustra lo anterior:

.........
int i;
char c;
float f;
void main (void)
__________________________________________________________________________________________________________
El C como lenguaje estructurado 21
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

{
c = i;
i = f;
f = c;
f = i,
}
..........

- En la línea 1ª, los bits de orden superior situados a la izquierda de la


variable entera i se recortan, dejando c con los 8 bits menos
significativos. Si i valía inicialmente entre 0 y 256, entonces i y c
deberían tener valores idénticos. En otro caso, el valor de c debería
reflejar sólo los bits menos significativos de i .
- En la línea 2ª, i recibe la parte no fraccionaría de f .
- En la línea 3ª, f recibe el valor entero de 8 bits almacenado en c,
convertido en formato de coma flotante.
- En la línea 4ª, f recibe el valor del entero i convertido en formato de
coma flotante.

A continuación, varios ejemplos de todo lo visto hasta ahora.

#include <stdio.h>
void main(void)
{
long importe = 35000L; // Sentencia de declaracion e inicialización
double veces = 1000e300;
printf ("¡Atencion!: El valor del entero largo de este");
printf ("\nprograma es %ld, pero puede ser cambiado", importe);
importe = -1000000000; // menos 100 millones
printf (" %.0e veces.\nPor ejemplo, ahora vale %ld.", veces, importe);
getchar();
}

¡Atencion!: El valor del entero largo de este


programa es 35000, pero puede ser cambiado 1e+303 veces.
Por ejemplo, ahora vale -1000000000.

#include <stdio.h>
void main(void)
{
unsigned short int ovejas, patas;
ovejas = 15000;
patas = 4 * ovejas;
printf ("En un rebaño de %u ovejas hay %hu ", ovejas, patas);
printf ("patas,\nsuponiendo que ninguna es coja.");
getchar();
}

En un reba±o de 15000 ovejas hay 60000 patas,


suponiendo que ninguna es coja.

#include <stdio.h>
void main(void)
{
__________________________________________________________________________________________________________
El C como lenguaje estructurado 22
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

unsigned short int patas, patos, cojos;


patos=25;
cojos=3;
patas = 2 * patos;
printf("En un lago hay %u patos con %u ", patos, patas-cojos);
printf("patas,\nsuponiendo que %u son cojos.\n", cojos);
getchar();
}

En un lago hay 25 patos con 47 patas,


suponiendo que 3 son cojos.

#include <stdio.h>
void main(void)
{
unsigned long int inicial=10000L, gana=3000L, pierde=2000L;
printf("Carolina entro en el casino con %lu dolares, ", inicial);
gana = gana * 3;
printf("gano %lu y \nperdio ", gana);
printf("%lu. Aun puede perder %lu mas.",2*pierde,inicial+gana-
2*pierde);
getchar();
}

Carolina entro en el casino con 10000 dolares, gano 9000 y


perdio 4000. Aun puede perder 15000 mas.

void main(void)
{
char comillas = '"'; // char comillas = 34 ;
char barraatras = '\\'; // char barraatras = 92 ;
short int i = 32767;
double a,b;
float c,d;
b = 2.0e10 + 1.0;
a = b-2.0e10;
printf("%lf \n", a); //Resulta 1.000000 => Si tiene bastante precisión
d = 2.0e10 + 1.0;
c = d-2.0e10;
printf("%f\n",c); //Resulta 0.000000 => No tiene suficiente precisión
printf("Se imprime una constante de caracter: %c\n", 'R');
printf("Juan dijo:\"%c es una barra invertida y su codigo es %d.%c.\n",
barraatras, barraatras, comillas);
printf("%hd %hd %hd \n", i, i+1, i+2);
getchar(); //Se desborda
}

1.000000
0.000000
Se imprime una constante de caracter: R
Juan dijo:"\ es una barra invertida y su codigo es 92.".
32767 -32768 -32767

12. SALIDA FORMATEADA POR PANTALLA: printf()


La siguiente función sirve para escribir información en la pantalla.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 23
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

printf(cadena_formato , item1 , item2, ... );

El prototipo de la función printf() se encuentra en stdio.h.

#include <stdio.h>
void main(void)
{
printf("Un proverbio chino dice:\n" );
printf("Si no dominal infolmatica, ");
printf("infolmatica dominal a ti.\n");
printf(" Filmado: Pon te Yang \n");
getchar(); //El programa espera que se pulse INTRO.
}

Un proverbio chino dice:


Si no dominal infolmatica, infolmatica dominal a ti.
Filmado: Pon te Yang
_

- El cuadro superior contiene el código fuente del programa y el inferior el


resultado que se puede observar en pantalla al ejecutarlo.
- Nótese que la combinación de caracteres \n dentro del entrecomillado
genera un retorno de carro en esa posición.
- Obsérvese también como el cursor queda a principio de la 4ª línea.
- Por último, todas las sentencias printf contienen el parámetro
cadena_formato, pero ninguna contiene items.

cadena_formato es una tira de caracteres que contiene aquellos que se han de


imprimir tal como aparecen en el entrecomillado y/o los
especificadores de formato (se distinguen por el símbolo % ).

item1, item2,.. son las distintas variables, constantes o expresiones, cuyo valor se
quiere imprimir. No tienen que aparecer obligatoriamente.

De este modo, la función printf() describe la manera en que han de imprimirse


los items en caso de que existan. Debe aparecer una especificación de conversión
por cada item. Es decir, debe haber exactamente el mismo número de argumentos que
de especificadores de formato y ambos deben coincidir en orden de izquierda a derecha.

#include <stdio.h>
void main(void)
{
printf("Mas vale pajaro en mano ");
printf("que %d volando. No hay %u sin %u.\n La", 100, 2, 3);
printf(" letra %c es la %s del alfabeto.\n", 'z', "ultima" );
printf("%8.5s pesa %9.4f kilos y esa roca %.15g .\n",
“Mariano”, 75.687, 1234567890.1230e12);
printf("Gana %ld pesetas con %hu apuestas.\n", 35000000L, 100 );
printf ("ASCII 65 = \x41, ASCII 69 = \105 "); getchar();
}

Mas vale pajaro en mano que 100 volando. No hay 2 sin 3.


La letra z es la ultima del alfabeto.
Maria pesa 75.6870 kilos y esa roca 1.234567890123e+21 .
Gana 35000000 pesetas con 100 apuestas.
__________________________________________________________________________________________________________
El C como lenguaje estructurado 24
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

ASCII 65 = A, ASCII 69 = E

- En la primera sentencia printf no hay ningún "item", en la segunda


aparecen tres, etc.
- En la 2ª sentencia el símbolo % indica que se va a imprimir una variable
en esa posición y el especificador de formato d informa que la variable a
imprimir es un número entero.....

Especificadores de formato de printf().

Código Formato Código Formato


%c Carácter %o Octal sin signo
%d Enteros decimales con signo %s Cadenas de caracteres
%i Enteros decimales con signo %u Enteros decimales sin signo
%e Notación científica (e min.) %x Hexadecimales sin signo (min.)
%E Notación científica (E may.) %X Hexadecimales sin signo (may.)
%f Coma flotante %p Puntero
%g El más corto entre %e y %f %n Argumento asociado es un ptro.
%G El más corto entre %E y %f %% Imprime símbolo %

Modificadores.

Los modificadores son apéndices que se agregan a los especificadores de


conversión básicos para modificar la salida. Se colocan entre el símbolo % y el
carácter que define el tipo de conversión:

% [-] [X] [.Y] [longitud] conversión

- Indica que el item comience a escribirse empezando por la


izquierda del campo que tenga asignado.

X Anchura mínima del campo; si no es suficiente se usa uno mayor.

.Y Número de decimales o máximo número de caracteres a imprimir.


(El valor por defecto en los formatos en punto flotante son 6
decimales).

longitud Si la conversión es un nº entero :


h trata al argumento como short
l trata al argumento como long
Si la conversión es un nº real:
L trata al argumento como long double

Consejos.

Para imprimir columnas de datos se puede conseguir una salida nítida utilizando
campos de anchura fija lo suficientemente grandes.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 25
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

Cuando un número está destinado a aparecer dentro de una frase es a menudo


conveniente especificar un campo igual o menor que el esperado, para evitar que
aparezcan blancos suplementarios que afeen el texto.

13. ENTRADA FORMATEADA POR TECLADO: scanf()


La rutina de entrada por teclado de propósito general es scanf(). Permite leer
todos los tipos de datos predefinidos y convierte los números automáticamente al
formato interno apropiado. Se trata de la rutina inversa a printf(). El prototipo de la
función scanf() se encuentra en stdio.h. El formato general de scanf() es:

int scanf(const char *cadena-formato, lista de argumentos);

La cadena-formato determina cómo se deben leer los valores y cómo se


almacenan en la variables apuntadas por los argumentos de la lista. La cadena de
formato está constituida por tres clases de caracteres:

Especificadores de formato.
Caracteres de espacio en blanco.
Caracteres distintos del espacio en blanco.

La función scanf() devuelve el número de campos que constituyen la entrada.

Especificadores de formato.

Los especificadores de formato de entrada van precedidos por un signo de


porcentaje (%) e indican a scanf() el tipo de dato que se va a leer a continuación. Los
especificadores de formato se asocian en orden, de izquierda a derecha, con los
argumentos que aparecen en la lista de argumentos. Estos códigos aparecen en la
siguiente tabla:

Código Significado
%c Leer un único carácter.
%d Leer un entero decimal.
%i Leer un entero decimal.
%e Leer un número en coma flotante.
%f Leer un número en coma flotante.
%g Leer un número en coma flotante.
%o Leer un número octal.
%s Leer una cadena.
%x Leer un número hexadecimal.
%p Leer un puntero.
%n Recibe un valor entero igual al número de caracteres leídos.
%u Leer un entero sin signo.
%[ ] Examinar un conjunto de caracteres.

#include <stdio.h>
#include <conio.h>
void main(void)
__________________________________________________________________________________________________________
El C como lenguaje estructurado 26
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

{
unsigned char ch=65; // es equivalente ->char ch='A';
printf("Inicialmente la variable ch vale %c.\n", ch);
ch = 129; // si ch fuera char, su código = -127
printf("Luego, ch vale %c y su codigo %d.\n", ch, ch);
printf ("Caracter (1 solo): ");
scanf("%c", &ch ); // &ch significa dirección de ch
printf("Ahora, ch vale %c cuyo codigo es %d.\n", ch, ch);
getch();
}

Inicialmente la variable ch vale A.


Luego, ch vale ü y su codigo 129.
Caracter (1 solo): ñ
Ahora, ch vale ñ cuyo codigo es 164.

Lectura de números.

Para leer un número decimal se utilizan los especificadores %d o %i (se


incluyen ambos especificadores, que realizan lo mismo, por razones históricas). Para
leer un entero sin signo, se utiliza el especificador de formato %u.
Los especificadores %e, %f o %g se utilizan para leer un número en coma
flotante tanto en notación estándar como científica (de nuevo se incluyen estos
especificadores, que realizan lo mismo, por razones históricas).
Se puede utilizar scanf() para leer enteros tanto en formato octal como en
formato hexadecimal utilizando las órdenes de formato %o y %x, respectivamente. El
especificador %x puede utilizarse tanto en mayúsculas como en minúsculas. Se
pueden introducir las letras de la A a la F en mayúsculas o en minúsculas al escribir los
números hexadecimales.
La función scanf() detiene la lectura de un número en el momento en el que se
encuentra con un carácter no numérico.

Lectura de caracteres individuales.

Se pueden leer caracteres individuales utilizando getchar() o una función


alternativa. También, se puede utilizar scanf() para llevar a cabo este propósito mediante
la utilización del especificador de formato %c.
Cuando se leen, además de caracteres, otros tipos de datos, se utilizan los
espacios en blanco, tabuladores y caracteres de nueva línea como separadores de
campo; sin embargo, cuando se lee un único carácter, los caracteres de espacio en
blanco se leen como cualquier otro carácter. Por ejemplo, con un flujo de entrada

«x y»

, el siguiente fragmento de código

scanf (“%c%c%c”, &a, &b, &c);

asigna el carácter x a a, un espacio a b y el carácter y a c.

Lectura de cadenas.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 27
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

La función scanf() se puede utilizar para leer una cadena desde el flujo de
entrada utilizando el especificador de formato %s. Este especificador le indica a scanf()
que lea caracteres hasta que encuentre un carácter de espacio en blanco. Los caracteres
que se leen se van introduciendo en el array de caracteres apuntado por el argumento
correspondiente y se añade un terminador nulo al resultado. En lo que se refiere a
scanf(), un carácter de espacio en blanco se corresponde con un espacio, un carácter de
nueva línea, un tabulador, un tabulador vertical o un salto de línea. A diferencia de
gets(), que lee una cadena hasta que se introduce un retorno de carro, scanf() lee una
cadena hasta que se introduce el primer carácter de espacio en blanco. Esto significa que
no se puede utilizar scanf() para leer una cadena del tipo «Esto es un prueba» debido a
que el primer espacio provoca la finalización del proceso de lectura.

#include <stdio.h>
#include <conio.h>
main()
{
int edad;
float peso, altura, valor;
char nombre[15], ape1[20];
printf ("Nombre: ");
scanf("%s", nombre);
printf ("Primer Apellido: ");
scanf("%s", ape1);
printf ("Edad: ");
scanf ("%d", &edad );
printf ("Peso (kilos): ");
scanf ("%f", &peso );
printf ("Altura (cm.): ");
scanf ("%f", &altura );
printf ("%s %s, su edad es %d, pesa %.2f kilos y mide %.2f
metros.\n",
nombre, ape1, edad, peso, altura/100);
//Se supone que 1 onza equivale a 32.1512 kg., luego en onzas:
valor = peso / 32.1512;
//Se supone cotización oro=400$ la onza.
valor = valor * 400.0;
printf ("Su peso en oro es $%.2f\n", valor);
getch(); //Lee un carácter del teclado, sin dar "eco" en la
pantalla
}

Nombre: María
Primer Apellido: García
Edad: 30
Peso (kilos): 60
Altura (cm.): 176
María García, su edad es 30, pesa 60.00 kilos y mide 1.76 metros.
Su peso en oro es $746.47

14. INSTRUCCIONES DE CONTROL DE FLUJO DEL


PROGRAMA.
C define tres categorías específicas de instrucciones de control de flujo de
programa: selección (if y switch), iteración (while, for y do/while) y salto (break,

__________________________________________________________________________________________________________
El C como lenguaje estructurado 28
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

continue y goto). Además, hay que considerar instrucciones de salto a la instrucción


return y a la función exit() ya que afectan al control del programa.

15. INSTRUCCIONES DE CONTROL SELECTIVAS.

if

Ya hemos comentado en este mismo tema que una expresión de relación o una
expresión lógica, si es cierta toma el valor 1, y si es falsa toma el valor 0.
Por otra parte, una expresión cualquiera (combinación de operadores, constantes
y/o variables) se considera cierta si tiene un valor distinto de 0, y se considera falsa sólo
si toma el valor 0.
La sintaxis de la sentencia if es

if (expresión) sentencia

La expresión podrá ser:


ƒ de relación: if ( x > y )...
ƒ lógica: if (sw)...
ƒ aritmética if ( x + y )...
En caso de que la expresión sea verdadera (en general, si es distinta de 0) se
ejecuta la sentencia; en caso contrario, se pasa a ejecutar la siguiente sentencia a if.
La sentencia o instrucción puede ser simple o compuesta. Si es simple, consistirá
en una sola sentencia terminada en punto y coma. Si es compuesta, contendrá varias
sentencias terminadas en punto y coma que están delimitadas por llaves, lo que se
conoce como bloque.
De una forma más general, la sintaxis de la sentencia if es:

if (expresion)
sentencia_1
else
sentencia_2

donde la cláusula else es opcional.

En esta sintaxis, si expresion es distinta de 0 (cierta), se ejecuta sentencia_1;


pero si es 0 (falsa), se ejecuta sentencia_2. Análogamente, sentencia_1 y sentencia_2
pueden ser simples o compuestas. Recuérdese que sólo se ejecuta el código asociado
con if o el código asociado con else, pero nunca ambos.
El formato general de la sentencia if con bloques de instrucciones es:

if (expresion)
{ secuencia de sentencias_1 }
else
{ secuencia de sentencias_2 }

#include <stdio.h>
#include <conio.h>
int main(void)
{
__________________________________________________________________________________________________________
El C como lenguaje estructurado 29
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

int clave = 4300 + 'A' , adivina;


printf("*** BANCO BBUVA de LAS VIÑAS ***\n");
printf("Su clave secreta: ");
scanf("%d",&adivina);
if (clave == adivina)
{
printf("Su clave es correcta, pero mejor, vaya al otro ");
printf("cajero de la esquina porque me queda poco dinero.\n");
}
else
printf("Clave no válida.\n");
getch();
}

Ifs anidados.

Un if anidado es una instrucción if que forma parte del cuerpo de un if o un else.


La razón de que los ifs anidados sean tan problemáticos es que puede resultar difícil
saber con qué if se asocia cada else. Afortunadamente, C proporciona una regla muy
simple: cada else está asociado con el if precedente más cercano (en el mismo nivel de
ámbito) que no tenga ya asociado una instrucción else.
Para anidar sentencias if hay que tener en cuenta: La sentencia if...else cuenta
como una única sentencia, y por tanto, no es necesario encerrarla entre llaves.

PSEUDOCODIGO LENGUAJE C
si a > 0 entonces if (a>0)
si a > 1000 entonces if (a>1000)
Escribir("a positivo grande") printf("a positivo grande”);
sino else
Escribir("a positivo pequeño") printf("a positivo pequeño”);
finsi else
sino if (a < -1000)
si a < -1000 entonces printf("a muy negativo”);
Escribir("a muy negativo”) else
sino printf("a poco negativo”);
Escribir("a poco negativo”)
finsi
finsi

Cada else va asociado al if anterior más próximo, a no ser que se incluyan


llaves que indiquen lo contrario. Ejemplos:

if (n > 6)
{
if ( n<12 )
printf ("%d está comprendido entre 6 y 12.",n);
}
else
printf ("%d es menor o igual que 6.",n);
if (n > 6)
if ( n < 12 )
printf ("%d está comprendido entre 6 y 12.", n);
else
printf ("%d es mayor o igual que 12.", n);
// Aunque la sangría confunda el else depende del segundo if

#include <stdio.h>
#include <conio.h>
#define CLAVE 4444
void main(void)
{
printf("%d",CLAVE);
__________________________________________________________________________________________________________
El C como lenguaje estructurado 30
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

int adivina, decenas;


printf("*** BANCO BBMOSTO de LAS VIDES ***\n\n");
printf("Su clave secreta: ");
scanf("%d",&adivina);
if (CLAVE == adivina)
{
printf("Clave correcta... pero por razones técnicas transitorias,");
printf(" momentáneas y pasajeras, no podemos atenderle.\n");
}
else
{
printf("Clave no válida... Pero creo que esa es la clave de ");
if (adivina < CLAVE)
{
printf("su cuñada, que es mas baja.\n");
decenas =(CLAVE-adivina)/10 ;
if (decenas)
printf("Suba %d decena\s.\n", decenas);
}
else
{
printf("su vecina, que es mas alta.\n");
decenas = (adivina-CLAVE)+/10 ;
if (decenas)
printf("Baje %d decena\s.\n", decenas);
}
}
getch();
}

El operador condicional ?

El operador ? recibe el nombre de ternario porque requiere tres operandos.

condicion ? expresion_1 : expresion_2

Se puede utilizar para reemplazar a las instrucciones if/else que contengan sólo
sentencias simples.
Si la condición es cierta, la expresión condicional (todo el conjunto) toma el
valor de expresión_1; si es falsa (o sea, 0), toma el valor de expresión_2.

Ejemplos: A > B ? mayor = A : mayor = B ;


mayor = A > B ? A : B ;
x = x>0 ? x : -x ; // halla valor absoluto

#include <stdio.h>
#include <conio.h>
#define CLAVE 15*433
void main(void)
{
int adivina;
printf("*** BANCO BBH2O del GUADALETE ***\n");
printf("Su clave secreta: ");
scanf("%d",&adivina);
if (CLAVE == adivina)
printf("Clave correcta, pero vuelva mañana que ya estaba cerrando.");
else
{
printf("Clave no válida. El número introducido ");
adivina<CLAVE?printf("es bajo.\n"):printf("es alto.\n");
}
getch();
__________________________________________________________________________________________________________
El C como lenguaje estructurado 31
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

switch

Aunque el if-else-if escalonado puede realizar evaluaciones múltiples, no es


excesivamente elegante. El código puede ser difícil de seguir y puede incluso confundir
a su autor pasado un tiempo. Por estas razones, C incorpora una instrucción de
decisión de bifurcación múltiple llamada switch, que compara sucesivamente un
valor entero frente a una lista de constantes enteras o de carácter; cuando se encuentra
una coincidencia, se ejecuta la instrucción o instrucciones asociadas con ese valor. El
formato general de la instrucción switch es

switch (expresión_entera)
{
case cte_1: sentencias;
[ break ];
case cte_2: sentencias;
[ break ];
......
[ default : sentencias ; ]
}

El funcionamiento es como sigue:

-Se evalúa la expresión entera y se rastrea la lista de constante o etiquetas


hasta encontrar un valor de una constante con el que coincida.
- Si se encuentra dicho valor, se ejecutan las sentencias que haya desde
esa etiqueta hasta el primer break. Tales sentencias no hay que escribirlas
encerradas entre llaves, es decir, las sentencias asociadas a cada etiqueta no son
bloques sino secuencias de instrucciones. De todos modos, es posible utilizar un
bloque como una sentencia de la secuencia, e incluso, declarar una o más
variables dentro de él.
- Si no coincide el valor de la expresión entera con ninguna de las
constantes de las etiquetas no se ejecuta ninguna acción, excepto si existe la
etiqueta default (es opcional incluirla o no) en cuyo caso se ejecutan las
sentencias asociadas a ella.
- La sentencia break es opcional. Si no se coloca ninguna, una vez que la
sentencia switch bifurque a una etiqueta, se ejecutarán todas las sentencias que
haya desde dicha etiqueta hasta el final del switch.
- Las etiquetas del switch deben ser constantes de tipo entero (incluyendo
el tipo char). En ningún caso se pueden emplear variables en las etiquetas, ni
tampoco colocar comparaciones.
- Si queremos que dos etiquetas distintas den el mismo resultado se
pueden poner juntas:

case x:
case y: <instrucciones> ;

- Dos constantes case del mismo switch no pueden tener los mismos
valores.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 32
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

- Si se utilizan constantes de carácter en el switch, éstas se convierten


automáticamente en sus valores enteros.

#include <stdio.h>
#include <conio.h>
void main(void)
{
unsigned short nota;
printf("Su nota: ");
scanf("%d", &nota);
switch (nota)
{
case 0: printf("No apareció.\n");
break;
case 1:
case 2: printf("Estudio muchísimo...una lección que no entraba.\n");
break;
case 3:
case 4: printf("Estudio toda la noche...y se durmió en el examen.\n");
break;
case 5: printf("Se le perdió una de las dos \"chuletas\".\n");
break;
case 6: printf("Usted va como España.\n");
printf("Si la gira 180 grados, ira sobresaliente.\n");
break;
case 7:
case 8: printf("Esa es una nota ble");
break;
case 9: printf("Si hace el pino, sólo verá Bien");
break;
case 10: printf("Le he pedido una nota, no dos.... ¡ah, bien!... \n");
printf("...Perdone, es la falta de costumbre.\n");
break;
default: printf("Desafina.");
}
getch();
}

- Es posible incluir un switch como parte de una secuencia de


instrucciones de switch más externo. En este caso es posible que las etiquetas de
los switch internos coincidan con algunas de los switch externos.

16. INSTRUCCIONES DE CONTROL REPETITIVAS.

while

La sintaxis es:

while (condición)
sentencia

Un bucle es un conjunto de sentencias que se repetirán cíclicamente al ejecutar


el programa. En el lenguaje C, dentro del bucle se acepta una sentencia simple, una
sentencia compuesta o una sentencia vacía:

- Si es una sentencia compuesta estará delimitada por llaves.

- Cuando la sentencia es simple no son necesarias las llaves.


__________________________________________________________________________________________________________
El C como lenguaje estructurado 33
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

- Cuando el programa llegue por primera vez a la sentencia while , comprueba si


la condición expresada entre paréntesis se cumple o no; en caso afirmativo (en general,
si toma un valor distinto de 0) se ejecutan las sentencias del bucle y se vuelve a
comprobar la condición. Así sucesivamente, hasta que la condición se vuelva falsa (o
toma el valor 0), y entonces el programa prosigue su tarea ejecutando la sentencia
siguiente al bucle (si el cuerpo del bucle era una sentencia compuesta, se ejecutará la
que está a continuación de la llave de cierre).

#include <stdio.h>
#include <conio.h>
#define FIJO_CENT_FAHR 32.00
#define ESCALA 1.8
void main(void) // Grados centígrados a Fahrenheit desde -10 a 50
{
float cent, fahr ;
char tecla;
printf ("Conversión de Grados centígrados a Grados Fahrenheit\n\n");
cent = -10.0;
while (cent < 51.0)
{
fahr = ESCALA * cent + FIJO_CENT_FAHR ;
printf("%8.1f C = %5.1f F", cent, fahr);
// 8 5 5 2 = 20 caracteres cada vez
cent++;
}
printf ("\n\n Quiere calentarse más? (N/N) .\n");
while ( (tecla = getch()) != 'N' ) ; // sentencia vacía
}

Es posible incluir los operadores de incremento y de decremento en la condición


de la sentencia while, de modo que se combinen el proceso de incremento del índice y
la parte comparativa del bucle. De este modo se obtiene una representación más
compacta y se consigue ubicar en un lugar los dos procesos que controlan el bucle.

#include <stdio.h>
#include <conio.h> // Mejora el ejemplo anterior
#define FIJO_CENT_FAHR 32.00
#define ESCALA 1.8
void main(void) // Grados centígrados a Fahrenheit desde -10 a 50
{
float cent, fahr;
char tecla;
printf ("Conversión de Grados centígrados a Grados Fahrenheit\n\n");
cent = -11.0; // cent = -10.0;
while (++cent < 51.0)
{
fahr = ESCALA * cent + FIJO_CENT_FAHR;
printf("%8.1f C = %5.1f F", cent, fahr);
}
printf ("\n\n Quiere calentarse más? (N/N) .\n");
while ( (tecla = getch()) != 'N' ) ; // sentencia vacía
}

do while

La sintaxis es:

do
sentencia
__________________________________________________________________________________________________________
El C como lenguaje estructurado 34
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

while (expresion);

La sentencia se ejecuta al menos una vez, aunque ya en ese momento la


expresión fuera falsa (o cero). Cada vez que se ejecuta la sentencia se evalúa la
expresión y si es cierta (distinta de cero) vuelve a ejecutarse otra vez la sentencia. Es
decir, la sentencia se ejecuta MIENTRAS la expresión sea distinta de 0 o cierta.
Dicho de otra forma, la sentencia se ejecuta hasta que la expresión sea falsa o 0.

La sintaxis para una sentencia compuesta sería la siguiente:

do
{
sentencia_A;
sentencia_B;
...........
}
while (expresion);

Nótese cómo las llaves sólo son necesarias cuando la sentencia es compuesta. De
todos modos, las llaves se pueden utilizar siempre para mejorar la legibilidad. Es
frecuente usar esta estructura cuando, por ejemplo, se pide un dato por teclado o una
opción válida de un menú, ya que el bucle se ejecutará al menos una vez y si los datos
introducidos no son correctos, se volverán a pedir.

#include <stdio.h>
#include <conio.h>
#include <math.h> //necesario por las funciones fabs() y sqrt()
void main(void)
{
// Estando plácidamente sentado bajo una haya, acomodado entre
// sus raíces, y a raíz de no tener nada mejor que hacer (si no
// hago esto no me hallo) y queriendo evitar echar raíces intentando
// el cálculo manual de raíces cuadradas, diseñé este programa que
// las halla, lindo donde los haya.
double num, raiz , mem_raiz , error;
printf("CALCULO RAICES CUADRADAS.\n" "Numero=0 --> Fin del programa.\n\n");
do
{
do
{
printf("Numero: ");
scanf("%lf",&num);
if (num<0.0)
printf("Numero no válido\n");
}
while (num < 0.0);
if (num > 0.0)
{
do
{
printf("Margen error (>0 y <0.01) : ");
scanf("%lf",&error);
if (error<=0.0 || error>=0.01)
printf("Valor del margen de error no válido\n");
}
while (error <= 0.0 || error >= 0.01);
raiz = num / 2;
printf("Aproximaciones: \n");
do
{
__________________________________________________________________________________________________________
El C como lenguaje estructurado 35
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

mem_raiz = raiz;
raiz = ( num / raiz + raiz ) / 2 ;
printf("%20.8lf",raiz);
}
while (fabs ( raiz - mem_raiz ) >= error );
printf("\n\nRaiz cuadrada de %.3lf = %.8f\n\n", num, raiz);
printf("Calculado directamente: %.8lf\n\n\n", sqrt(num) );
}
}
while(num > 0.0);
}

for

for (expresion_1 ; expresion_2 ; expresion_ 3)


sentencia

- expresion_1 se realiza una sola vez, al comenzar el bucle for. Suele ser
una inicialización.

- expresion_2 es una condición que se evalúa antes de cada ejecución


potencial del bucle; si es cierta (distinta de cero) se ejecuta una vez el bucle completo.

- expresion_3 se evalúa al final de cada bucle; suele ser la actualización


de las variables implicadas en la condición.

#include <stdio.h>
#include <conio.h>
void main(void)
{
int num, x;
printf(" N N al cubo\n"); //Tabla con 10 números y sus cubos
for (num=1; num<=10; num++)
printf("%5d %5d\n", num, num*num*num);
printf("\n\n");
getch(); //Del 100 al 1
num=100;
for (;num>=1;)
printf("%5d",num--);
printf("\n\n");
getch();
// De 0 a 50, con incrementos de 5, y
// de 50 a 100, con incrementos de 10.
for (num=0, x=5 ; num<=100; num+=x )
{
printf("%5d",num);
(num>=50)? x=10 : 1 ;// Hay que poner algún valor
} // detrás de los dos puntos, aunque no se
utilice
getch();
}

- La sentencia que se ejecuta puede ser simple (terminada en punto y coma) o


compuesta (conjunto de sentencias simples delimitadas por llaves).
- Una o más expresiones se pueden dejar en blanco, por ejemplo:

1) La expresion_1, si la variable que controla el bucle ya viene inicializada.


2) Si la expresion_2 no existe dará lugar a un bucle infinito puesto que un
test vacío se considera cierto.
__________________________________________________________________________________________________________
El C como lenguaje estructurado 36
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

3) La expresion_3 no hace falta si la actualización de la variable que


controla el bucle se produce dentro del cuerpo del bucle.

En todo caso, aunque una expresión se deje en blanco siempre hay que colocar
los dos punto y coma.
- Los parámetros de las expresiones 2 y 3 se pueden alterar dentro del cuerpo del
bucle.
- Se puede utilizar el operador coma (,) que enlaza las expresiones, por ejemplo,
para realizar más de una inicialización o más de una actualización. No tiene sentido
utilizarlo en la expresion_2, pues no equivale ni al operador && (and) ni al operador ||
(or) .
El operador coma evalúa las expresiones de izquierda a derecha.

- El operador coma no está renstringido al bucle for, pero es donde se utiliza con
mayor frecuencia. Por otra parte, no hay que confundirlo con el “separador coma” que
se usa por ejemplo en sentencias printf para distinguir argumentos.
- Si la condición es inicialmente falsa, no se ejecutará nunca el cuerpo del bucle.
- El bucle for se puede utilizar para generar un retardo; por ejemplo:

for (cont=1; cont<10000; cont++) ;

Como se puede apreciar la sentencia está vacía.

break

Se usa en la sentencia switch, y en los bucles for , while y do while para


salir de dicho bucle y ejecutar la siguiente sentencia. Cuando se encuentra en una
estructura anidada, la liberación afecta a la estructura más interna que la contenga.

#include <stdio.h>
#include <conio.h>
int main(void)
{
const int VALOR_BUSCADO=789;
const int REPETICIONES=15;

int t, visualizado, salir, count;


for(t=0; t<100; t++) // se sale cuando t vale 10
{
printf("%3d ", t);
if(t==10)
break;
}
printf("\n\n");
getch();
printf("Puedes esperar a visualizar %d " "o bien, pulsar una tecla para
salir.\n\n", VALOR_BUSCADO);
t = 0;
salir = 0;
visualizado = 0;
do
{
for ( ; t < 1000 ; t++ )
{
printf("%d\r", t);
if (!visualizado)
visualizado = t == VALOR_BUSCADO ? 1 : 0 ;
if(kbhit())

__________________________________________________________________________________________________________
El C como lenguaje estructurado 37
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

{ //KBHIT() devuelve 0 si no se ha pulsado una tecla


salir = 1;
break;
}
}
}
while (!visualizado && !salir ) ;
if (visualizado)
printf("Valor visualizado.\n");
printf("\n\n");
getch();
printf ("Ahora, %d veces los NUEVE primeros numeros.\n", REPETICIONES);
for(t=0; t< REPETICIONES; ++t)
{
count = 1;
for(;;) // BUCLE INFINITO
{
printf("%4d", count);
count++;
if(count==10) break;
}
printf("\n");
}
getch();
}

continue

Es utilizable en todos los bucles y no se pude usar en switch.


Interrumpe el flujo del programa, evitando el resto de la iteración, y se dirige de
nuevo a evaluar la expresión que condiciona la ejecución del bucle; si ésta es cierta
comienza una nueva iteración.
Ejemplo:

for (i=0;i<4;++i)
{
printf(“%d\n”,I);
if (i==2)
continue;
printf(“La variable es distinta de 2);
}

APÉNDICE. Conversión de tipos.


En general, en una sentencia o expresión se emplean variables y constantes de un solo tipo. Sin
embargo, si en un momento dado se mezclan dichos tipos, el C no se molesta en seguir la pista del
eventual error. En su lugar, utiliza una serie de reglas para efectuar automáticamente conversiones de
tipo:
__________________________________________________________________________________________________________
El C como lenguaje estructurado 38
I.E.S. Francisco Romero Vargas –Departamento de Informática - Fundamentos de Programación
__________________________________________________________________________________________________________

1º. En cualquier operación en que aparezcan dos tipos diferentes se eleva la "categoría" del
operando que la tiene menor para igualarla a la del mayor. Proceso conocido como "promoción".

2º. El rango o categoría de los tipos, de menor a mayor, es: char, short, int, long, float, double.
Los tipos unsigned tienen el mismo rango que el tipo a que están referidos.

3º. En una sentencia de asignación, el resultado final de los cálculos se reconvierte al tipo de la
variable a que están siendo asignados. Así pues, el proceso puede ser una "promoción" o una "pérdida de
rango", según que la variable a asignar sea de categoría superior o inferior.

Con el fin de conservar al máximo la precisión numérica, todas las variables y constantes float se
convierten en double cuando se realizan cálculos aritméticos con ellas. Así se reduce enormemente el
error de redondeo. Por supuesto, la respuesta final se reconvierte a float, si ese es el tipo declarado.
Cuando se convierte de enteros a caracteres, de enteros largos (long) a enteros y de enteros a enteros
cortos (short), la regla básica consiste en eliminar la cantidad apropiada de bits más significativos.
Cuando se utilizan enteros de 16 bits, significa que ...
- se perderán 8 bits cuando se convierta de entero a carácter
- se perderán 16 bits cuando se convierta de entero largo (long) a entero.

La siguiente tabla muestra estas conversiones de tipo en asignaciones:


Tipo del destino Tipo de expresión Posible pérdida

signed char unsigned char Si valor > 127 => destino negativo.
char short int Los 8 bits de mayor orden.
char int (16 bits) Los 8 bits de mayor orden.
char int (32 bits) Los 24 bits de mayor orden.
short int int (16 bits) Ninguna.
short int int (32 bits) Los 16 bits de mayor orden.
int (16 bits) long int Los 16 bits de mayor orden.
int (32 bits) long int Ninguna.
float double Precisión. Resultado redondeado.
double long double Precisión. Resultado redondeado.

Se deben recordar dos puntos importantes que pueden afectar a la portabilidad del código que se
escriba:
- Las conversiones de un int en un float o de un tipo float en un double, etcétera, no aumentarán
ninguna precisión ni exactitud. Estos tipos de conversiones sólo modificarán el formato en que se
representa el valor.
- Algunos compiladores (y procesadores) de C siempre tratarán una variable char como positiva, sin
importar el valor que tiene cuando se convierte en un entero o en un float. Otros compiladores pueden
tratar los valores de una variable char superiores a 127 como números negativos cuando se
convierten (como lo hace Borland C++). Así pues, en general se utilizarán variables char para caracteres
y, para evitar un posible problema de portabilidad en esta área, se debería utilizar en cada caso el tipo
adecuado: int, short int, signed char, unsigned char, etc.

Para utilizar la tabla anterior y realizar una conversión no mostrada directamente, simplemente se
convierte de tipo en tipo hasta alcanzar el tipo destino. Por ejemplo, para convertir un double en un int,
primero se convierte de double a float y, a continuación, de float a int.
Si se ha utilizado un lenguaje de programación como Pascal, que prohíbe esta conversión de tipo
automática, se puede pensar que C es muy relajado. Sin embargo, recuérdese que C se diseñó para
facilitar el trabajo del programador permitiendo realizar el trabajo en C en lugar de en ensamblador. Para
conseguir esto, C tiene que permitir estas conversiones de tipo.

__________________________________________________________________________________________________________
El C como lenguaje estructurado 39

También podría gustarte