Sei sulla pagina 1di 90

UT4 - PROGRAMACIÓN EN LENGUAJE C

ÍNDICE:

4.01.- Introducción al lenguaje C. ........................................................................................... 2


4.01.1.- Símbolos normalizados para la realización de ordinogramas. ............................... 3
4.01.2.- Identificadores y palabras claves. .............................................................................. 5
4.01.3.- Estructura de un programa. Include y Define. ......................................................... 5
4.02.- Entorno gráfico del CVI. ............................................................................................... 8
4.03.- Variables y tipos de datos. ........................................................................................... 12
4.04.- Cadena de caracteres. .................................................................................................. 14
4.05.- Arrays, conceptos básicos. ........................................................................................... 15
4.06.- Operadores aritméticos y lógicos. ............................................................................... 17
4.07.- El operador condicional. .............................................................................................. 20
4.08.- Las funciones getchar( ) putchar( ) gets( ) y puts( ). ................................................. 20
4.09.- La función scanf() y printf(). ....................................................................................... 21
4.10.- Funciones matemáticas. ............................................................................................... 25
4.11.- Ejercicios básicos. ......................................................................................................... 29
4.12.- Sentencias de control. ................................................................................................... 36
4.13.- Funciones....................................................................................................................... 42
4.14.- Recursividad. ................................................................................................................ 45
4.15.- Ampliación sobre arrays. ............................................................................................. 46
4.16.- Punteros......................................................................................................................... 54
4.17.- Tipos de almacenamientos de variables. .................................................................... 62
4.18.- Programación a bajo nivel. .......................................................................................... 65
4.19.- Estructuras y uniones................................................................................................... 69
4.20.- Archivos......................................................................................................................... 76
4.21.- Ejercicios. ...................................................................................................................... 80

1
4.01.- Introducción al lenguaje C.

El lenguaje C fue desarrollado por Dennis Ritchie a principios de la década de los setenta (1972) en
los laboratorios Bell Telephone. Es el resultado de dos lenguajes anteriores, el B creado por Ken
Thompson en el mismo laboratorio y basado a su vez en el BCPL creado por Martin Richard en la
universidad de Cambridge. Debido a su popularidad, los compiladores de este lenguaje (programas
que convierten el lenguaje C en código máquina) difieren levemente de la definición original. Por ello
el Instituto Nacional Americano de Stándares ANSI con el objetivo de poner orden y proporcionar un
lenguaje aceptados por todos, establece las normas ANSI para C. Aun así, los distintos compiladores,
pueden ofrecer características propias añadidas a este estándar.

En principio el C se utilizó fundamentalmente para realización de programas de sistemas. Esto


consiste en programas del tipo de:
- Sistemas operativos.
- Ensambladores.
- Compiladores.
- Intérpretes de lenguajes (QBASIC por ejemplo).
- Programas de modems.
- Controladores de red.
- Utilidades del sistema operativo.

Esto es debido a que este lenguaje está pensado para ello. La manipulación de bits, bytes,
direcciones, archivos, creación de rutinas adaptadas a cada tipo de ordenador denominadas funciones
...etc.
Derivado de esta última propiedad, los programas fuentes escritos en C tienen una gran
portabilidad (en este caso podemos definirlo como propiedad de compilar un programa fuente en
equipos distintos) ya que deja en manos de las funciones de biblioteca la mayoría de las características
que dependen de la computadora.
Los intérpretes y compiladores son programas que ejecutan códigos o programas fuentes
escritos en un lenguaje determinado. Es decir si por ejemplo escribimos un programa fuente en Basic o
en C este programa puede ser ejecutado en nuestro PC bien por un programa compilador o bien por un
programa intérprete.
Un programa intérprete lee línea a línea el código fuente y lleva a cabo las instrucciones
específicas en ellas contenidas. Luego para ejecutar nuestro código fuente tendremos por fuerza que
estar dentro del programa intérprete.
Por contra un programa compilador, coge este código fuente y lo traduce por completo a
código máquina, dando como resultado un programa ejecutable con extensión exe y por lo tanto
pudiéndose ejecutar sin necesidad ya del compilador.
Por último podemos decir que durante la realización de un programa extenso, es más cómodo
el trabajar con un intérprete, pero una vez obtenido el texto fuente ya depurado y funcionando
correctamente, necesitaremos de un programa compilador que nos lo traduzca a código máquina por
entero obteniendo ya el programa ejecutable.

2
Linkado: Si el código fuente utiliza, como es corriente en C, funciones de biblioteca, (estas son
pequeños programas ya compilados que realizan una acción concreta, suministradas estas funciones
por los distintos programas compiladores) después del proceso de compilado se realiza el linkado
donde el programa traducido se ensambla con las distintas funciones utilizadas en él. El programa
traducido a código máquina sin ensamblar toma la extensión obj y después de linkarse, la extensión
exe.

4.01.1.- Símbolos normalizados para la realización de ordinogramas.

La especificación de forma gráfica de la secuencia de operaciones a ejecutar por un programa,


presenta la ventaja de su claridad y fácil interpretación. Estos símbolos que vamos a utilizar, son los
normalizados para el diseño de sistemas procesadores, es por lo que en algún momento lo adaptaremos
a nuestras necesidades del lenguaje C.

A) Operación interna aritmética o lógica:

Se representará de esta forma cualquier operación


interna con las distintas variables.

OPERACIÓN
P
B) Operaciones de transferencia entrada/salida:

Para cualquier entrada de datos, normalmente por


teclado, y para cualquier tipo de salida, normalmente en
pantalla.

ENTRADA/SALIDA

3
C) Símbolo de toma de decisión:

Cuando el programa se bifulca en dos o más caminos.

NO ¿CONDICIÓN
CUMPLIDA?

SI

D) Operaciones de salto a subrutinas (funciones):

Representaremos de esta forma las llamadas NOMBRE


FUNCIÓN
a cualquier función del programa.

E) Símbolo de conexión:
Muchas veces un ordinograma no cabe en una
sola hoja. Por ello, es necesario utilizar este símbolo
para conexión de ordinogramas parciales. En el 3
interior del círculo se indica el mismo número para
indicar que estos puntos están unidos.

INI
F) Símbolo de comienzo o de fin de proceso:

Para representar esta acción se utiliza el símbolo representado, tanto en el


programa principal, como en las distintas funciones (salvo main()).
En las funciones, se indica en el primer símbolo el nombre de la función, y en el
último, el retorno a la función principal o

FIN

4
4.01.2. Identificadores y palabras claves.

Denominamos identificadores a los nombre asignados a datos, variables, cadenas de


caracteres, funciones, arrays (agrupación de datos o de cadenas)...etc.
Estos nombres deben cumplir una serie de normas:
- Pueden estar compuestos por letras o números indistintamente hasta 31 caracteres. Se puede utilizar
algunos signos, siendo el de subrayado de mayor uso (ejemplo: respuesta_1).
- Deben empezar siempre por una letra.
- Una letra mayúscula no equivale a misma letra minúscula.
- Estos identificadores no aceptan acentos.
- No se puede utilizar el signo menos, comillas o espacios en blanco.
- No se puede emplear para este fin palabras claves de C, ya que estas tienen un propósito definido.

Todos los programas escritos en C se estructuran en distintas funciones, una de las cuales ha de
llamarse de manera obligada main(), si el programa sólo consta de una función, esta deberá llamarse
así.
Toda función debe tener un nombre (que debe cumplir la regla de los identificadores), unos
argumentos encerrados entre paréntesis y si no tiene argumentos estos paréntesis deben de aparecer de
una manera obligada y a continuación aparecerá lo que es el cuerpo de la función encerrado este entre
llaves.

4.01.3.- Estructura de un programa. Include y Define.

Al principio de los programas escritos en C y antes de definir la función o funciones de que


consta, es necesario ordenar al compilador que incluya algunos archivos de cabecera correspondientes
a la funciones a utilizar. Estos archivos tienen la extensión h (correspondiente a hearder=cabeza) y
en ellos aparecen sólo las declaraciones y tipos de argumentos de una serie de funciones de biblioteca
(las definiciones propias de cada función estarán incluidas en otros archivos de librería con extensión
lib).
Esta orden se puede realiza de la siguiente forma:
#include"stdio.h"
#include<stdio.h>

En la primera, ordenamos al compilador que compile antes de nuestro archivo fuente, el archivo
stdio.h correspondiente a una serie de funciones estandares de entrada/salida de datos en pantalla y
teclado(Standard Input/Ouput) y que se utilizarán en el programa. Las dos líneas indican lo mismo con
la salvedad de que en la primera línea se indica mediante las dobles comillas que el archivo de
cabecera está en el mismo subdirector de trabajo, mientras que en la segunda línea se indica mediante
los símbolos < y > que el archivo en cuestión se halla dentro del subdirector especificado en el
compilador, denominado normalmente include.
Esta orden servirá por lo tanto para compilar dos archivos fuente cualesquiera, es decir si
tuviésemos dos archivos fuentes, por ejemplo arc1.c y arc2.c si incluyésemos en el archivo segundo la

5
orden #include"arc1.c" y compilásemos el segundo archivo, se habría compilado el primero y a
continuación el segundo dando como resultado un único archivo de salida denominado arc2.exe.
Es de señalar que esta orden debe de empezar obligatoriamente con el símbolo de almohadilla
# y al contrario de casi todas las ordenes o declaraciones no termina en punto y coma.
Cada archivo de cabecera tiene asociada una serie de funciones de biblioteca, si se utiliza en el
programa alguna de ellas, este archivo deberá incluirse de la forma ya vista. Por ejemplo, en el
ejemplo siguiente se utilizan las funciones printf() y scanf() siendo necesario incluir el archivo de
cabecera stdio.h.

/* PROGRAMA DE EJEMPLO
*************************** */

#include<stdio.h>

int main(void) //void indica vacía, es decir, función que no acepta ningún valor
{
float a,r; //declaración de variable
printf("escribe un nº positivo menor de 1000\n"); //llamada a la función de escritura en pantalla

scanf("%f",&a); //captura el valor escrito y lo asigna a a


if(a>0&&a<1000){ //mientras a sea mayor de cero ejecuta el bloque siguiente
r=sqrt(a); //llamada a la función raíz cuadrada
printf("la raíz es=%f", r);//imprime en pantalla el valor de la variable r
}

fflush(stdin);//limpia el teclado
getchar(): //espera la pulsación de un intro
return 0; //devuelve el valor cero al sistema indicando que se ha cerrado correctamente
}

La orden define también irá precedida de la almohadilla y no acabará en punto y coma. Su


utilidad es la de asociar a un identificador un dato, carácter o cadena de caracteres. Ejemplo:

#define NOMBRE "Marta"


#define INTERES 0.35
#define PI 3.141593
#define LIMITE 1000
#define LETRA "s"
#define FDA ‘*’

El compilador donde encuentre el identificador lo cambiará por el dato, carácter o cadena


asociado a él.

/* PROGRAMA DE EJEMPLO
*************************** */

#include<stdio.h>//librería necesaria para utilizar las funciones printf() y scanf()

#include<dos.h> //librería necesaria para utilizar la función Delay()

#define PI 3.141593
int main(void) //void indica vacía, es decir, función que no acepta ningún valor
{

6
float long, r; //declaración de variable
printf("Introduce el radio de la circunferencia=");
scanf("%f",&r); //captura el valor escrito y lo asigna a r
long=2*PI*r;
printf("\n La longitud de la circunferencia es=%f",longr);//imprime en pantalla el valor de long
printf("\n-------Fin ----------“);// el símbolo \n realiza un salto de línea en la pantalla
Delay(1);//espera 1 segundo
return 0; //devuelve el valor cero al sistema indicando que se ha cerrado correctamente
}

En primer lugar, todo lo encerrado entre /* y */ el compilador lo ignorará. De igual forma,


toda la línea posterior a una doble barra // también será ignorada. Esto será útil para realizar
comentarios a lo largo del programa fuente.
Las tabulaciones son opcionales y atienden a una forma más comprensiva del programa.
En este programa podemos ver claramente que la función main() es la función principal y
única y la definición de esta función va encerrada entre llaves. La palabra void que la antecede, indica
que la función no devuelve valor (de tipo int, float ...etc) alguno. Más adelante se verá en el capítulo 6,
que las funciones pueden devolver valores al ser ejecutadas.
Dentro de estas llaves, como ya hemos dicho, se lleva a cabo la definición de dicha función,
que son el conjunto de declaraciones acabadas en punto y coma. Primeramente declarando las
variables a utilizar y a continuación una serie de sentencias acabadas. Vemos como también en la
definición de esta función main() se realizan también llamadas a otras funciones con argumentos
encerrados entre paréntesis. Por ejemplo la función printf(), scanf() sí llevan argumentos aunque no es
aquí donde corresponde hablar de ellos (en los compiladores se da una información sobre todas las
funciones de biblioteca que se incluyen en el compilador).

7
4.02.- Entorno gráfico del CVI.
LabWindows/CVI es un entorno de desarrollo integrado para programadores en lenguaje C. Se
basa fundamentalmente en un entorno interactivo para desarrollo de programas y una librerías de
funciones para crear aplicaciones de adquisición de datos y control de instrumentos.
LabWindows/CVI contiene además un conjunto de herramientas software para la adquisición, análisis
y presentación.
Para utilizar LabWindows/CVI, el programador no necesita ser un experto conocedor de técnicas
avanzadas de programación ni de los detalles internos del sistema operativo Windows.
Como ventajas a versiones anteriores, decir, que LabWindows/CVI contiene la especificación del
lenguaje ANSI C, lo que proporciona máxima flexibilidad a la hora de desarrollar aplicaciones.
Las herramientas que básicamente forman este entorno de desarrollo y que iremos describiendo a lo
largo de este tema son las siguientes:

• Un editor de interfaces gráficas de usuario (GUI).

• Una ventana para editar el código fuente de nuestros programas ANSI C.

• Paneles de funciones para la ejecución interactiva y generación de código de forma automática.

• Compilador y Depurador integrados para el desarrollo y mantenimiento de proyectos.

La clave de la potencia de LabWindows/CVI está en sus librerías que proporcionan funciones para
todas las fases del desarrollo de una aplicación de adquisición de datos o de control de
instrumentación. Así tenemos:

1. Cinco librerías para adquisición de datos: Instrument library, GPIB/GPIB 488.2 library,
Data Acquisition library, RS232 library y VXI library.

2. Dos librerías para análisis de datos: Formatting and I/O library y Advanced Analysis
library.

3. Una librería para presentación de datos: User Interface library.

4. Una librería de utilidades: Utility library.

5. Dos librerías para redes y comunicación entre procesos: Dinamic Data Exchange (DDE)
library y Transmission Control Protocol (TCP) library.

Además, tal y como se comentó anteriormente, la librería completa ANSI C también está integrada en
el entorno de desarrollo de LabWindows/CVI.

8
En el entorno de LabWindows/CVI se trabaja por proyectos, para ello es conveniente crear una carpeta
donde guardar dicho proyecto:
En la pantalla de bienvenida, podemos
abrir un proyecto o crear uno nuevo,
aparte podemos ver algunos ejemplos o
consultar información acerca del
programa.

Primero: crearemos una carpeta, p.e. en mis documentos a la que llamaremos EJEMPLO 1 y en la
pantalla de bienvenida elegiremos New Proyect (nuevo proyecto)

Segundo: Salvaremos el proyecto en la carpeta creada anteriormente con


un nombre, p.e. ejemplo1

Tercero: Crearemos un archivo nuevo fuente


(File/New/Source(*.c))

CUARTO: Lo guardaremos (por defecto se guardarán todos los archivos


que creemos en la carpeta del proyecto) dándole un nombre, p.e. ejemplo1

QUINTO: Nos debe aparecer el entorno de la siguiente manera:

9
Nuestra aplicación estará formada por varios archivos, uno de ellos será el que contiene el código
fuente de la aplicación (*.c), otro será el que contiene la información sobre las funciones gráficas
utilizadas (*.uir), y otro archivo que contiene información sobre el espacio de trabajo y archivos que
componen el proyecto (*.cws). El
archivo que relaciona a todos será
(*.prj).

Situados en la ventana de edición de código fuente


insertaremos el código básico de un programa
escrito en C como es la función main mediante:
Edit/Insert Construct/Main

10
Insertándose en el editor las siguientes
líneas:

Ahora lo modificaremos dejándolo de la siguiente forma:

#include <cvirte.h>
int main ()
{
int cont;
char a;
printf(“HOLA MUNDO”);

while(getchar()!='\n');//vaciado del buffer del teclado


fflush(stdin);// otro vaciado del buffer del teclado
getchar();//espera la pulsación de un intro
return 0;//devuelve el valor cero al sistema indicando que se ha cerrado correctamente
}

El siguiente paso será ejecutar dicho programa, para ello pulsaremos Run/Debug Ejercicio1dbg.exe
O pulsando el icono

SI NO HUBIERAMOS SALVADO ANTES EL PROYECTO CON UN NOMBRE, NOS


PREGUNTARÍA EL NOMBRE DEL ARCHIVO.C Y EL DEL PROYECTO.

El programa nos indica que se van añadir los archivos generados


al proyecto (entre ellos el ejecutable *.exe) a lo que respoderemos
afirmativamente.

El programa nos indicará que será necesario incluir el archivo de


cabecera ansi_c.h (h->header o cabeza) a lo que responderemos
afirmativamente, incluyéndose al principio del archivo fuente o
archivo.c la siguiente línea:

#include <ansi_c.h>

Este ejercicio simple, nos muestra en pantalla el código ASCII mediante el cual, se almacenan en
formato binario los caracteres alfabéticos de los distintos idiomas más extendidos.

Para ello hemos utilizado un bucle for y la función printf( ) reconocidos por el estándar ANSI

11
4.03.- Variables y tipos de datos.
Los diferentes variables a utilizar en un programa escrito en C, se declaran al principio del
mismo, acabándose siempre en punto y coma, por ejemplo:
char a;
Esta declaración significa que a será una variable que almacenará un dato tipo char.
Los tipos de datos se diferencian en el número de bytes que reservarán para su
almacenamiento, es decir un tipo de datos por ejemplo char se almacena en un byte (8 bits) y sólo
podrá contener 256 números distintos (2 elevado a 8) comprendidos entre 0 y 255, pensado este tipo
para almacenar números correspondientes a caracteres alfanuméricos, de control o símbolos gráficos.
Esta correspondencia la establece la tabla de codificación que nuestro ordenador utilice siendo la más
usual en PC la tabla ASCII. Es decir si queremos almacenar el carácter a en una posición determinada
de memoria, se almacenará el número ASCII correspondiente que en el caso del carácter a
corresponde al 97 evidentemente escrito en binario (1100001).

A continuación se muestra la tabla ASCII

12
Como ya hemos mencionado, una variable de tipo char se almacena en un byte (8 bits) y sólo
se puede almacenar 256 números distintos en un byte, comprendidos entre 0 (0000 0000) y 255 (1111
1111), pudiendo así contener cualquier número asignado por la tabla ASCII a cada carácter, símbolos
o códigos de control.

Los tipos de datos pueden ser:

Tipo: Bytes reservados: Utilidad:


char -----> 1 Byte ----> nºenteros pequeños o caracteres
int -----> 2 Bytes ----> nºenteros desde -32768 a +32767
long int -----> 4 Bytes ----> nºent.del orden de mil millones
float -----> 4 Bytes ----> nºdecimales 3.4e-38 a 3.4e38
double -----> 8 Bytes ----> nºdecimales de doble precisión (11 dígitos de precisión)
long double -> 10 Bytes ----> nºdecimales aun mayores

(Estos nº de bytes pueden no ser idénticos en todos los compiladores)


Los números podemos escribirlos además de decimal, en base octal o base hexadecimal,
anteponiendo para ello el cero 0 o el 0x respectivamente a dicho número.
En el siguiente ejemplo las asignaciones (valor que tomará la variable a) serán idénticas:
char a= 27; //base 10
char a= 033; //base 8 octal
char a=0x1b; //base 16 hexadecimal

En los tres casos se almacenará en el espacio reservado de memoria ------->00011011 que


corresponde a 27 unidades en binario, ya que en una memoria sabemos que sólo pueden almacenarse
ceros o unos.
ejemplos de declaración de variables:
int a,b,c; //tres variables de tipo entero
int costo,cuenta=100,d;
unsigned float d,e=0.023;
long int x=34566,y=939999;
char numero=13;
char t=’5’,u=5;//dos variables de tipo char una almacenará el carácter
5 y la otra el número 5
char respuesta_primera=’s’;

Como vemos en estos ejemplos, al igual que se definen las variables a utilizar en el programa,
podemos darles inicialmente algún valor si ello nos interesa.
En las variables de tipo char (carácter) podemos almacenar números desde -128 a 127, pero si
lo que queremos es guardar un carácter, tendremos que poner este entre comillas simples, que es la
forma de decirle al compilador que debe transformar este carácter el su código ASCII correspondiente
Es decir si escribimos char t=’5’; se guardará en el cajón denominado t el valor del código
ASCII correspondiente a 5 que es el número 53 (00110101 en binario).
Por contra, si escribimos char=5; se guardará en t el numero 5 (000000101 en binario).

4-13
4.04.- Cadena de caracteres.

Constan de cualquier nº de caracteres (incluido los espacios en blanco) encerrados entre


comillas.
ejemplo de cadena de caracteres:
"La respuesta correcta número 33 es:"
"El profesor dijo \"no\""
"Línea 1ª\nLínea 2ª\nLínea 3ª"

Dos consideraciones importantes:

Primero: si estas cadenas se tuviesen que escribir en la pantalla, las secuencias de escape( \n \t \” \xa7
etc ) se ejecutan pero no se escriben (con algunas excepciones, por ejemplo si quisiéramos utilizar
dobles comillas, estas se escribirán como secuencia de escape para no ser confundidas por el
compilador como apertura y cierre de una cadena)

Veamos algunas secuencias de escape interesantes:


á \xa0
é \x82
í \xa1
ó \xa2
ú \xa3
Á \xb5
É \x90
Í \xd6
Ó \xe0
Ú \xe9
ñ \xa4
Ñ \xa5
¿ \xa8
salto de línea \n
pitido altavoz \a
tabulación \t
Segundo: Al final de toda cadena el compilador insertará la secuencia de escape de carácter nulo de
una forma automática. Esto quiere decir que:

si almacenamos ’A’ se guardará el nº 65 (en binario)


si almacenamos ”A” se almacenará el nº 65 más \0 al ser una cadena, en este caso de sólo
un carácter (se necesitará por tanto dos bytes).
#include <ansi_c.h>
int main (void)
{
char letra;
printf("La respuesta correcta es sí");

4-14
letra='a';
putchar(letra);
getchar();
return 0;
}

4.05.-Arrays, conceptos básicos.

Un array es una variable que puede almacenar un conjunto de datos de idéntico tipo. Es decir
podemos definir arrays de caracteres, de números enteros o de coma flotante (más adelante se dedica
un tema exclusivamente a los arrays ya que estos podrán ser multidimensionales y almacenar no sólo a
caracteres sino a cadena de caracteres)
ejemplo:
char a[10];
char texto[8]="Sevilla";
char texto[8]={’S’,’e’,’v’,’i’,’l’,’l’,’a’,’\0’}
char nombre[]="España"; (la manera más cómoda)
int num[4];
int num[]={3,45,678,21}; (array de 4 números int)
long int numeros[57];
float res_cuentas[5]={0.034,45,67,23,0.98};

En la declaración de arrays de caracteres se reservará un espacio para la secuencia de


escape nulo, luego char[10]; podrá almacenar 9 caracteres y será necesario dimensionar a 8 un array
para almacenar el nombre de Sevilla.
Sin embargo la manera más cómoda es char nombre[]="España"; ya que de manera
automática se almacena sin problema y sin tener en cuenta el numero de caracteres a almacenar mas
uno correspondiente al indicador de final de cadena (\0).
Vemos también que podemos declarar arrays de números asignándoles valores iniciales
omitiendo la capacidad del mismo.
Vemos en la última línea que de los cinco números que podemos asignar sólo lo hacemos en
las tres primeras casillas de una manera automática, llamándose estas:
res_cuentas[0] ----> 0.034
res_cuentas[1] ----> 45.67
res_cuentas[2] ----> 23.098

Quedando el resto de las casillas o cajones con el número 0. A continuación vemos algunos
ejemplos:

Ejemplo 1:
#include<ansi_c.h>
int main(void)
{
int cont,a[5]={2,3,4}; //rellenamos las tres primeras casillas o registros
for(cont=0 ; cont<5 ; ++cont) printf("\n a[cont]=%d",a[cont]);

4-15
fflush(stdin);//limpia el buffer del teclado
getchar();
return 0;
}

Ejemplo 2:
#include <ansi_c.h>
int main (void)
{
int cont;
char a[]="ESPAñA";
a[4]=165;
puts(a);
fflush(stdin);//limpia el teclado
getchar();
return 0;
}

Importante: En todas las declaraciones de arrays donde no se asignan valores iniciales, la


capacidad del array debe ser definida. Es decir en declaraciones:

char a[10];
int num[4];
int num[4];
long int numeros[57];
En todas ellas se expresa la capacidad del array.

Los elementos de un array se numeran desde 0 a n-1 siendo n el número que expresa la
capacidad del array.
ejemplo:
char ciu[]="Malaga";

M a l a g a \0
ciu[0] ciu[1] ciu[2] ciu[3] ciu[4] ciu[5] ciu[6]

luego para un array denominado "ciu" de 7 elementos, estos irán desde ciu[0] a ciu[6].

Se podrá operar con cualquier elemento de un array de una forma individual, por ejemplo si
tenemos dos arrays de 4 numeros enteros denominados a y b, podremos realizar cualquier operación
con cualquier elemento de ambos:

int a[]={7,8,9,34};
int b[]={45,10,12,30};

4-16
podremos en cualquier parte del programa procesar cualquiera de estos elementos
individualmente, es decir:
c=a[0]+a[3]; (c tomará el valor 7+34=41)
d=a[2]-b[0]; (d tomará el valor 9-45=-36)

4.06.- Operadores aritméticos y lógicos.


Existen 5 operadores aritméticos en C:
+ suma.
- resta.
* multiplicación.
/ división.
% resto de división entera.
Ejemplos: a=34, b=12
a+b=46
a-b=22
a*b=408
a/b=2
a%b=10

es decir 34=(2*12)+10 <------- D=(d*c)+r


(Dividendo=divisor*cociente+resto)
Ejemplo 1:

#include <ansi_c.h>
int main (void)
{
int x,y,suma;
x=3;
y=10;
suma=x+y;
printf("suma=%d",suma);
getchar();
return 0;
}

Ejemplo 2:
#include <ansi_c.h>
int main (void)
{
int x,y,resto;
x=3;
y=10;
resto=y%x;

4-17
printf("resto=%d",resto);
getchar();
return 0;
}

Para el resto de operaciones matemáticas se pueden utilizar funciones matemáticas de biblioteca para
lo cual deberemos incluir como archivo de cabecera math.h .

Ejemplo:
#include<stdio.h>
#include<math.h>
int main(int argc, char *argv[]){
double a=34,b=12,resultado;
resultado=pow(a,b);
printf("a elevado a b=%lf",resultado);
return 0;
}
(En la primera línea de programa se declaran las variables a y b como tipo int asignándoles
además un valor.
En la segunda línea se declara la variable resultado como tipo float.
En la tercera, se utiliza la función de biblioteca pow(x,y) contenida en los archivos de librerías
math.lib y cuyo archivo de cabecera math.h es necesario incluir al principio del programa.
En la cuarta línea se presenta el valor de la variable resultado, llamando a esta mediante %lf

El operador % (resto de división entera) sólo se empleará con números enteros o variables de
tipo int, ya que si operamos con números decimales, esta no parece muy lógica. El resto de operadores
son utilizables con todo tipo de números o variables.

Para expresiones algebraicas complejas, es conveniente el subdividir esta en pequeñas partes,


por ejemplo:
z=(23/(2*(c-7)))*((40+b)/(12+a))
Sería más cómodo y comprensible el dividirla en dos partes, por ejemplo:
x=23/(2*(c-7));
y=(40+b)/(12+a);
z=x*y;

Otro modo de expresar operaciones algebraicas de una manera más concisa es la siguiente:
a+=100; equivale a: a=a+100;
x-=z; equivale a: x=x-z;
a*=50-b; equivale a: a=a*(50-b);
precio/=coste; equivale a: precio=precio/coste;

El operador sizeof (tamaño de) que indicará el número de bytes reservados por un número o
variable, por ejemplo:

4-18
int a,t;
t=sizeof a;
t tendrá el valor de 2, correspondiente al número de bytes reservados para un número int).
También se puede utilizar de la siguiente manera:
int x,y,z,u,v;
x=sizeof(char); // almacenará 1
y=sizeof(int); // almacenará 2 ó 4 bytes
z=sizeof(long int);
u=sizeof(float) /* almacenará 4
v=sizeof(double) /* almacenará 8
printf("\n el tipo char reservara=%d bytes",x);
printf("\n int =%d",y);
printf("\n long int=%d",z);
printf("\n float=%d",u);
printf("\n double=%d",v);

OPERADORES RELACIONALES: OPERADORES LÓGICOS:


a<b ---> a menor que b && ---> Y lógico
a>b ---> a mayor que b || ---> O lógico
a<=b ---> a menor o igual que b
a>=b ---> a mayor o igual que b ver ^ como operador o exclusivo
a==b ---> a igual a b
a!=b ---> a no igual a b

Si una expresión es cierta tomará el valor 1, si es falsa el valor cero.


Ejemplos:
int a=10,b=5,c=20,x;
x=a<b; //expresión falsa x tomará el valor 0
a+(2*b)==c; //exp. verdadera x tomará el valor de 1
b!=a; /*exp. verdadera*/
c>=4; /*exp. verdadera*/
x=(a>b); /*verdadera x tomará el valor 1*/
x=(b<=10 && a!=15); /*ver. x=1*/
x=((a!=2 || b>c)&&(c==a)); /*falsa x=0*/
x=(a>100); /*falso x=0*/
x=!(a>100); /*verdadero x=1*/
x=(a==10); /verdadero x=1*/
x=!(a==10); /*falso x=0*/
x=b-5>c+a; /*expresión falsa*/

podaríamos comprobar cada línea de la siguiente manera:

4-19
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[])


{
int cont;
char a;
int a=10,b=5,c=20,x;

x=a<b;
printf("valor de x=%d=",x);
while(getchar()!='\n';//equivale a fflush(stdin)
getchar();
Cls();//limpia la pantalla
fflush(stdin)//limpia el buffer del teclado
return 0;
}

4.07.- El operador condicional.


Se utiliza para que una variable tome un valor u otro en función de una expresión. Si esta, es
verdadera, tomará un primer valor, si es falsa el segundo.
Veamos algunos ejemplos:
a=(i<0)? 0:100;
La variable a tomará el valor 0 si i es menor que cero (expresión i<0 verdadera), y
tomará el valor 100 si i es mayor de cero (expresión i<0 falsa).
minimo=(x>y)? y:x;
La variable mínimo tomará el valor de y si la expresión es verdadera, y el valor de x si
la expresión es falsa.
Veamos otro ejemplo: para i=50
a=(!(110<2*i)&&i!=25)? 0:100;
La expresión es verdadera y por lo tanto a tomará el valor 0.
Ejemplo:
#include <ansi_c.h>
int main (void)
{
int a=23,b;
b=(a<100)?0:1;
printf("b=%d",b);
getchar();
return 0;
}

4.08.- Las funciones getchar( ) putchar( ) gets( ) y puts( ).

La función getchar() captura un carácter del teclado y la función putchar(c) escribe un


carácter en pantalla. Por ejemplo:

4-20
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[])


{
char a;
a=getchar();
putchar(a);
fflush(stdin)//limpia el buffer del teclado
getchar();
return 0;
}

La función gets() sirve para capturar una cadena de caracteres (alfanuméricos) y la función
puts() para mostrar una cadena en pantalla. Ejemplo:

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

char linea[80];
gets(linea);
puts(linea);
getchar();
return 0;
}

gets(linea) capturará la cadena escrita hasta 80 caracteres o hasta que pulsemos enter. La sentencia
puts(linea); presentará en pantalla a dicha cadena.

4.09.- La función scanf() y printf().

La función scanf() se utiliza para la introducción de cualquier valor numérico, carácter o


cadena de caracteres. Se puede denominar como una entrada de datos con formato. Su expresión
general es la siguiente:

scanf("cadena de control",arg 1,arg 2,...,arg n);

La función printf() se utiliza para la escritura en pantalla de cualquier valor numérico, carácter
o cadena de caracteres. Se puede denominar como una salida de datos con formato. Su expresión
general es la siguiente:

printf("cadena de control",arg 1,arg 2,...,arg n);

ambas pertenecen al estándar de C (stdio.h)Veamos un ejemplo:

#include <ansi_c.h>

4-21
#include <cvirte.h>

int main (int argc, char *argv[]){

char palabra[10];
float num_dec;
int ent;
printf(« Escribe una palabra, un numero entero y un numero con decimales\n") ;
scanf("%s %d %f",palabra,&ent,&num_dec);
printf("palabra=%s entero=%d numero con dec=%f",palabra,ent,num_dec);
printf("\nfin del programa");
fflush(stdin)

getchar();
return 0;
}

Vemos en la línea 5º como la cadena de control de scanf() realiza tres asignaciones utilizando
el símbolo % común a ambas funciones y a continuación las letras s d f que corresponden a los
distintos formatos de cadena int y float.
También es importante señalar que las variables van precedidas del signo & salvo los arrays
de caracteres. Si escribimos en la pantalla:
perro 135 87995.125
y pulsamos enter se introducirá: perro -----> palabra[10]
135 -----> ent
87995.125 ---> num_dec

También se hubieran introducido de igual manera si hubiésemos escrito cada dato pulsando
enter al final del mismo. Es decir:
perro (enter)
135 (enter)
87995.125 (enter)

La sexta línea mostrará en pantalla el contenido de las variables, realizando llamadas o


referencias a estas mediante el símbolo % y a continuación el tipo de formato %c %d %f

Por último la línea 7ª mostrará el mensaje en pantalla fin del programa utilizando printf() sin
llamada a ninguna variable. Comprobar que si no se hubiese puesto al principio un salto de linea \n se
hubiese escrito este mensaje a continuación de lo último escrito en pantalla.
Podemos decir que:
printf("fin del programa\n"); equivale puts("fin del programa");

Formatos comunes:

c -----> carácter
s -----> cadena

d -----> entero decimal (u ---> e. dec. sin signo)


ld -----> entero decimal largo
i -----> entero (dec. octal hexa.)

4-22
o -----> entero octal
x -----> entero hexadecimal

f -----> número coma flotante


e -----> número coma flotante exponecial
g -----> número coma flotante sin cifras significativas

sólo para scanf():

[...] -----> Entre corchetes se incluyen los caracteres que se pueden capturar.
[^\n] -----> El acento circunflejo excluye el carácter que no podrá capturar (en este caso el
fin de línea o enter)

sólo para printf():

- -----> El dato se ajusta a la izquierda dentro de un campo (ver ejemplos).


+ -----> El dato numérico se presentará en pantalla siempre con signo (positivo o
negativo).
0 -----> Hace que se presenten ceros en espacios vacíos de un campo.
# -----> Hace que los datos octales y hexadecimales sean precedidos por 0 y 0x
respectivamente. Si el número es decimal lo presentará siempre con el punto
decimal y todos los ceros correspondientes aunque tenga un valor entero.

Veamos algunos ejemplos:

Ejemplo 1.- Programa que captura una cadena compuesta sólo por los carácteres abcdeABCDE
incluido el carácter de espaciado.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

char letra[20];
scanf("%[abcdeABCDE ]",letra);
puts(letra);
printf("%s",letra);
getchar();
return 0;
}

Ejemplo 2.- Programa que captura todos los caracteres, incluido el espaciado, salvo el fin de línea
(enter).

#include <ansi_c.h>

4-23
#include <cvirte.h>

int main (int argc, char *argv[]){


char cadena[60];
printf(“escribe una cadena de caracteres con al menos dos palabras=”);
gets(cadena);
puts(cadena);

printf(“escribe de nuevo la cadena de caracteres con al menos dos palabras=”);


scanf("%[^\n]",cadena);
puts(cadena);
getchar();
return 0;
}

4-24
4.10.- Funciones matemáticas.

Función: Tipo: Propósito: Archivo include:

abs(i) int Retorna el valor absoluto de i. stdlib.h

acos(d) double Retorna el arco coseno de d. math.h

asin(d) double Retorna el arco seno de d. math.h

atan(d) double Retorna el arco tang. de d. math.h

atan2(dl,d2) double Retorna el arco tang. de dl/d2. math.h

ceil(d) double Retorna un valor redondeado por


exceso al siguiente mayor entero. math.h

cos(d) double Retorna el coseno de d. math.h

cosh(d) double Retorna el coseno hiperbólico. math.h

fabs(d) double Retorna el valor absoluto de d. math.h

exp(d) double Elevar e a la potencia d(e=2.7182818)


es la base del sistema de logaritmos
naturales [Neperianos]). math.h

floor(d) double Retorna un valor redondeado por


defecto al int menor más cercano. math.h

fmod(dl,d2) double Retorna el resto de dl/d2 (con


el mismo signo que dl) math.h

labs(l) long int Retorna el valor absoluto de l. math.h

log(d) double Retorna el logaritmo natural de d. math.h


log10(d) double Retorna el logaritmo(en base 10). math.h

pow(dl, d2) double Retorna dl elevado a la potencia d2. math.h

tan(d) double Retorna la tangente de d. math.h

tanh(d) double Retorna la tang. hiperbólica de d. math.h


sin(d) double Retorna el seno de d. math.h

sinh(d) double Retorna el seno hiperbólico de d. math.h

sqrt(d) double Retorna la raíz cuadrada de d. math.h

Otras funciones interesantes (existen en el estándar cientos de ellas)

atof(s) double Convierte la cadena s a una

4-25
cantidad en doble precisión. stdlib.h

atoi(s) int Conv.la cadena s en un entero. stdlib.h

atol(s) long Conv.la cadena s en long int. stdlib.h

calloc(ul,u2) void* Reserva memoria para un array de u1


elementos, cada uno de longitud u2
bytes. Retorna un puntero al principio
del espacio reservado. malloc.h o stdlib.h

Cls() void limpia la pantalla


difftime(ll,12)double Retorna la diferencia de tiempo
11 - 12 donde 11 y 12 representan
el tiempo transcurrido después de
un tiempo base(ver función time) time.h

exit(u) void Cerrar todos los archivos y buffers


y terminar el programa. (El valor de
u se asigna en la función para indicar
el estado de terminación.) stdlib.h

fclose(f) int Cierra el archivo f. Retorna un 0 si


el arc.se ha cerrado con éxito. stdio.h

feof(f) int Determina si se ha encontrado un


fin de archivo. Si es así, devuelve
un valor distinto de 0; en otro caso
devuelve 0. stdio.h
flush(stdin) limpia el bufer del teclado

fopen(sl,s2) file* Abre un archivo llamado s1, del tipo


s2 retorna un puntero al archivo. stdio.h

fprintf(f,..) int Escribe datos en el archivo f. stdio.h

fputc(c,f) int Escribe un carácter en el arc. f. stdio.h

fputs(s,f) int Escribe una cadena en el archivo f. stdio.h

fread(s,i1,i2,f)int Leer i2 elementos, cada uno de


tamaño i1 bytes, desde el archivo
f hasta la cadena s. stdio.h

fscanf(f,..) int Leer datos del archivo f. stdio.h

fseek(f,l,f) int Mover el puntero al archivo f una


distancia de 1 .bytes desde la
posición i (i debe representar el
principio del archivo, la posición
actual del puntero o el fin del
archivo). stdio.h

ftell(f) long int Retorna la posición actual del


puntero dentro del archivo f. stdio.h

4-26
fwrite(s,il,i2,f)int Escribir i2 elementos, cada uno
de i1 bytes, desde la cadena s
hasta el archivo f. stdio.h

getc(f) int Leer un carácter del archivo f. stdio.h

isalnum(c) int Determina si el argumento es alfanumérico.


Retorna un valor distinto de cero si es
cierto; en otro caso devuelve 0 ctype.h

isalpha(c) int Determina si el argumento es alfabético.


Retorna un valor distinto de cero si es
cierto; en otro caso devuelve 0. ctype.h

isascii(c) int Determina si el argumento es un


carácter ASCII. Retorna un valor
distinto de cero si es cierto; en
otro caso devuelve 0. ctype.h

malloc(u) void* Reserva u bytes de memoria Retorna


un puntero al principio del espacio
reservado. stdlib.h

rand(void) int Retorna un valor aleatorio positivo. stdlib.h

srand(u) void Inicia el generador de números


aleatorios. stdlib.h

strcmp(s1,s2) int Compara dos cadenas lexicográficamente.


Retorna un valor negativo si s1 < s2; 0 si
s1 y s2 son idénticas; y un valor positivo
si s1 > s2. string.h

strcpy(sl,s2) char*Copia la cadena s2 en la cadena sl. string.h

strlen(s) int Retorna el número de caracteres en la


cadena s. string.h

Notas: Tipo refiere al tipo de la cantidad devuelta por la función. Un asterisco denota un puntero.

e denota un argumento de tipo carácter


d denota un argumento de doble precisión
f denota un argumento archivo
i denota un argumento entero
1 denota un argumento entero largo
p denota un argumento puntero

4-27
s denota un argumento cadena
u denota un argumento entero sin signo

La mayoría de los compiladores comerciales de C vienen acompañados de muchas


más funciones de biblioteca. Consulta el manual de referencia de su compilador particular para una
información más detallada de las funciones anteriores y para tener una lista de, las funciones
adicionales.

4-28
4.11.- Ejercios básicos.

Ejercicio 4.11.1- Determina cuales expresiones son verdaderas y cuales son falsas:

100<5 falso
20!=20 falso
20==20 verdadero
'b'>'c' falso
100<3 && 'a'<'c' falso
100>3 || 'a'>'c' verdadero
106>12&&5==5 verdadera
106>12 && 5==5 (también puede escribirse así)
106 > 12 && 5 == 5 (o así)
!(34<500 || 5>2) falsa
!(100!=5&&7<10||2==5) falso

Ejercicio 4.11.2.- Tenemos un programa donde se ha definido las siguientes variables:


char a='M',b;
int i=10,j=5,k;
int x=3,y;

(escribir a=’M’ es igual a escribir a=77 que es el número asignado por la tabla ASCII
a dicho carácter)

Determina el valor de las siguientes expresiones compilando un programa básico:

a) k=a+i; k=87
b) y=(i!=21 && x>0.5)? 100:0.25; y=100
c) b=5+a; b=82
d) i+=j; i=15
e) j%=2; j=1
f) x*=10; x=30
g) y=(!(i=<j)&&(a>40))? 0.005:8.45; y=0.005
h) k=(((i%j)*5)<2)? 20:0; k=20
i) y=((10*x>0.5)&&(5<=i)&&(2<x*i)) y=1

Ejercicio 4.11.3.- Un programa en C contiene las siguientes declaraciones y asignaciones, comprobar


su resultado compilando un programa básico:

int a,b=53,c=’0’;

4-29
int x=10,y=2,z;
(En la codificación ASCII, el valor 53 corresponde al carácter 5, y al carácter cero le
corresponde el valor 48)

a) z=(b!=100 && c==48 || x>10); z=1


b) a=b+c; a=101
c) z=(!(b<c) && (x<y*4)|| y!=2)?;99.8:25; z=25
d) z=(c=='0'); z=1
e) z=(b==53 && y=>3); z=0
f) (b=='5' && y==x-5 || c!=48); expresión falsa
g) z=(b-3=='0')? 20 : 500; z=500
h) a=(100<='5'+'0')? 1:0; a=1
i) !(x*y-30<2) expresión falsa

Ejercicio 4.11.4.- Programa que solicita la entrada de un número y lo escribe en octal y hexadecimal.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a;
printf("escriba un número n=");
scanf("%d",&a); /*se escribirá en decimal*/
printf("\n\n dec=%d octal=%o hex=%x",a,a,a);
getchar();
return 0;
}

Ejercicio 4.11.5.- Programa que solicita la introducción de un dato en hexadecimal y lo presenta en


decimal y octal

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a;
clrscr();
printf("escriba un número hexadecimal n=");
scanf("%x",&a); /*se deberá escribir en hexadecimal*/
printf("\n\n decimal=%d",a);
printf("\n\n octal=%o",a);
while(getchar()!='\n');//vaciado del buffer del teclado
getchar();
return 0;
}

4-30
La especificación de un campo determina el números de caracteres o dígitos de un número.
Veamos algunos ejemplos:

Ejercicio 4.11.6.- Programa que acepta la introducción de tres números int de sólo tres dígitos y los
presenta en un campo de 5 espacios.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a,b,c;
scanf("%3d %3d %3d",&a,&b,&c);
printf("\na=%5d b=%5d c=%5d",a,b,c);
while(getchar()!='\n');
getchar();
return 0;
}
si escribimos: aparecerá en pantalla:
123 -----> a= 1 b= 2 c= 3
456 876 123 -----> a= 456 b= 876 c= 123
123456789 -----> a= 123 b= 456 c= 789
12 3456 789 -----> a= 12 b= 345 c= 6

Ya que tenemos definido un campo de tres espacios para introducir los números enteros, y un
campo de 5 espacios para su presentación en pantalla. Si queremos que se ajusten a la izquierda
tendremos que emplear el signo menos.

Ejercicio 4.11.7.- Programa que acepta la introducción de tres números int de sólo tres dígitos y los
presenta en un campo de 5 espacios ajustándolos a la izquierda.
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a,b,c;
scanf("%3d %3d %3d",&a,&b,&c);
printf("\na=%-5d b=%-5d c=%-5d",a,b,c);
getchar();
return 0;
}

si escribimos: aparecerá en pantalla:


123 -----> a=1 b=2 c=3
456 876 -235 -----> a=456 b=876 c=-23
123456789 -----> a=123 b=456 c=789
12 3456 789 -----> a=12 b=345 c=6

4-31
Es de señalar que el signo menos ocupará también un espacio.

Ejercicio 4.11.8.- Programa que captura y presenta dos números decimales en distintos formatos.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

float a,b;
scanf("%f %f",&a,&b);
printf("número a=%f \nnúmero b=%f",a,b);
printf("\n\nnúmero a=%2.2f \nnúmero b=%4.3f",a,b);
printf("\n\nnúmero a=%g \nnúmero b=%g”,a,b);
printf("\n\nnúmero a=%e \nnúmero b=%e",a,b);

getchar();
return 0;
}

Ejercicio 4.11.9.- Programa que introduce números enteros en un array.


#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int num[3];
clrscr();
scanf("%d",&num[0]);
scanf("%d",&num[1]);
scanf("%d",&num[2]);
printf("%d %d %d",num[0],num[1],num[2]);
getchar();
return 0;
}

Ejercicio 4.11.10.- Realiza un programa en el que se pueda introducir una cadena hasta pulsar enter y
posteriormente nos dé el número de caracteres de la misma, utilizar la función strlen().

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


char cad[50];
int i;

4-32
puts("escribe una frase");
gets(cad);
i=strlen(cad);
printf("la frase tiene=%d
caracteres",i);
getchar();
return 0;
}

Ejercicio 4.11.11.- Escribe un programa que compare dos cadenas y nos diga si son iguales o no,
utilizar la función strcmp().

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


char a[30],b[30],r,t;
int c;
clrscr();
puts("escribe una frase");
gets(a);
puts("escribe una segunda frase");
gets(b);
c=strcmp(a,b);
r=(c==0)? 's':'n';
t=(c==0)? 'i':'o';
printf("estas frases %c%c son iguales",r,t);
getchar();
return 0;
}

Ejercicio 4.11.12- Programa para calcular la longitud de una circunferencia y el área de un circulo,
dado el radio*/

#define pi 3.141592654
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


double r,l,s;
clrscr();
printf("Prog. para calcular la log. y area dado el radio");
printf("\n\n\t introduce el valor del radio en cm");
printf(" \n\t radio=");
scanf("%f",&r);
l=2*pi*r;
s=pi*r*r;
printf("\n\t la longitud de la circunferencia es:%lf cm",l);
printf("\n\n\t el area del circulo es:%lf cm cuadrados",s);
getchar();
return 0;

4-33
}

Ejercicio 4.11.12.- Cálculo de la tensión instantánea en un condensador Vc aplicarle una Vcc fija a
través de una R Vc=Vcc(1-e-t/RC)

#define e 2.7182818
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

float Vcc,r,t,c,i,v;
printf("\n\n\n\t prog. para calcular la tension en un C.");
printf("\n\n\t escriba el valor de \"Vcc\" en voltios");
printf("\n\t \" \" \" \" \"c\" en faradios");
printf("\n\t \" \" \" \" \"r\" en ohmios");
printf("\n\t \" \" \" \" \"t\" en segundos");
printf("\n\n\t Vcc=");
scanf("%f",&Vcc);
printf("\n\t c=");
scanf("%f",&c);
printf("\n\t r=");
scanf("%f",&r);
printf("\n\t t=");
scanf("%f",&t);
i=(Vcc/r)*exp(-t/r*c);
printf("\n\t intensidad (A) en el instante dado i=%f",i);
i=(Vcc/r)*pow(e,(-t/r*c));
printf("\n\t i=%f",i);
v=Vcc-r*i;
printf("\n\t tensión (V) de C en dicho instante v=%f",v);
getchar();
return 0;
}

Ejercicio 4.11.13.- Realiza un programa que calcule las soluciones de una ecuación de segundo grado.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

float a,b,c,x1,ra,rb;
char p;
printf("Prog.para cal.las raices de una ec.
de 2º grado");
printf("\n\n\t introduce el valor de \"a\",
\"b\" y \"c\"");
printf("\n\t para una expresión general de
\"axx+bx+c=0\"");
printf("\n\t a=");
scanf("%f",&a);
printf("\t b=");
scanf("%f",&b);

4-34
printf("\t c=");
scanf("%f",&c);
ra=(b*b-4*a*c);
p=(ra<0)? 'i':' ';
ra=(ra>0)? ra:ra*-1;
ra=sqrt(ra);
printf("\n\n\t ra=%f",ra);
rb=ra/(2*a);
x1=(-b/(2*a));
printf("\n\n\t x1=%f+%f%c y x2=%f-%f%c",
x1,rb,p,x2,rb,p);
printf("\n\npulsa enter para continuar");
getchar();
return 0;
}

Ejercicio 4.11.14.- (propuesto): Realiza un programa que dada la Vcc y la C, calcule la R


(considerando Vc=99% de la tensión de carga posible) para un tiempo de carga dado.

Vc/Vcc=1-e-t/RC --->
(1-Vc/Vcc)=e-t/RC ---> ln(1-Vc/Vcc)=-t/RC

luego: t=-RC.ln(1-Vc/Vcc)

Ejercicio 4.11.15.- (propuesto): Realiza un programa similar al anterior, donde podamos seleccionar
el % de carga(Vc=Vcc(1-e- T/RC).

Ejercicio 4.11.16.- (propuesto): Realiza un programa que presente en pantalla todos los caracteres
ASCII y su número correspondiente.

Ejercicio 4.11.17.- (propuesto): Realiza un programa que convierta una cadena alfabética de hasta 6
caracteres en mayúsculas (esta podrá introducirse en mayúsculas o minúscula).

4-35
4.12.- Sentencias de control.

Las sentencias de control condicional el flujo de un programa. Si hasta aquí, todos los
programas vistos, las líneas de un programa cualquiera se ejecutaban una sola vez y de una manera
correlativa. Con este tipo de sentencias podremos ejecutar una línea o un grupo de líneas si se cumplen
una condición o la expresión anexa a la palabra de control, por ejemplo:

...
línea 4;
while(a=>b){
línea 5;
línea 6;
línea 7;
}
línea 8;
...

En este ejemplo, las líneas 5,6 y 7 (encerradas entre llaves) se ejecutarán si la condición anexa
a while, es decir, (a=>b) es verdadera.

Podremos ejecutar una líneas o un grupo de líneas un número determinado de veces, o elegir
un grupo de sentencias de entre varios, dependiendo del valor de una variable, o saltar a otra parte del
programa (la famosa instrucción goto) aunque esto por lo que ya se explicó con respecto a los
programas estructurados, sólo será recomendable si con ello el programa gana en claridad.
Estas condiciones serán expresiones lógicas o aritméticas, al igual que las utilizadas con el
operador condicional.
Evidentemente, a poco que se complique un programa será necesario utilizar estas sentencias
de control pertenecientes todas ellas a las palabras claves de C.
Estas sentencias son:

while(expresión) Ejecuta la siguiente sentencia o grupo de sentencias


mientras la condición entre paréntesis sea válida.

do...while(expresión) Se ejecutará las líneas incluidas entre do y while y si expresión


es válida vuelve a ejecutarse sucesivamente mientras sea esta sea válida.

if(expresión) La sentencia o grupo de sentencias siguientes se


ejecutarán si la expresión es correcta. Se verá también if...else.

for(exp1;exp2;exp3) La sentencia o grupo de sentencias siguientes se


ejecutarán si la expresión 2 es verdadera. La expresión 1 inicia un índice y la expresión 3 lo
incrementa o disminuye. Ejemplo: for(a=0;a<20; break Esta
palabra de control sirve para salir de un bucle.

switch(expresión) Con esta palabra de control podremos elegir de entre


un grupo de casos distintos.

continue Esta palabra de control se utiliza al contrario que break, es


decir, para continuar con la ejecución de sentencias posteriores si la expresión anterior es válida.

4-36
4.12.1.- La sentencia while.

La sentencia while podemos traducirla por mientras, llevará anexa una expresión y mientras
esta sea válida la sentencia o grupo de sentencias encerradas entre llaves, se ejecutará.

Ejemplo 1º: Programa que escribe en pantalla los números desde 0 a 9.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int digito=0;
while(digito<=9) printf("%d\n",digito++);
printf("\aFIN");
fflush(stdin); //vaciado del buffer del teclado
getchar();
return 0;
}

Ejemplo 2º: Programa que pregunta cuantas veces se escribirá la palabra HOLA.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int num,a=0;
puts("indica cuantas veces se escribirá \"HOLA\"");
scanf("%d",&num);
while(a<num){
printf("HOLA\n");
++a;
}

fflush(stdin); //vaciado del buffer del teclado


getchar();
return 0;
}

El grupo de sentencias printf("HOLA\n") y ++a se ejecutarán mientras se dé la


condición a<num . Si no queremos que estas se repitan indefinidamente, deberemos variar la
expresión de control desde el bucle. En este caso se ha realizado mediante ++a.

4.12.2.- La sentencia do...while.

Esta sentencia compuesta se puede traducir por haz tal cosa mientras la expresión sea
válida. Se diferencia de la anterior en que al menos la sentencia simple o compuesta (grupo de
sentencias simples) se ejecutará al menos una vez.

Ejemplo 3º: Programa que pide la introducción de un número menor de 1000 y si este
no es correcto lo pedirá indefinidamente hasta que se cumpla la condición.

4-37
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


float a;
do{

puts("escribe un número menor de 1000");


scanf("%f",&a);
}while(a>=1000);
puts("el número es correcto");
getchar();
return 0;
}

Ejemplo 4º: Programa que calcula la suma y media de una serie de números.
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int n,cont=1;
float x,media,suma=0;

printf("¿cuantos números?");
scanf("%d",&n);
do{
printf("\n x=");
scanf("%f",&x);
suma +=x;
media=suma/cont;
printf(" suma=%6.2f",suma);
printf(" media=%6.2f",media);
++cont;
}while(cont<=n);
puts("\npulsa una tecla");
getchar();
return(0)
}

4.12.3.- La sentencia if e if...else.

Esta palabra clave podemos traducirla por un si condicional. Si se cumple la condición


anexa a if, se ejecutará la sentencia simple o compuesta siguiente.

Ejemplo 5º: Sentencia simple.

...
if(a<300 && b!='s') printf("ERROR PRUEBA OTRA VEZ");
...

Ejemplo 6º: Sentencia compuesta.

4-38
...
if(a<300 && b!='s'){
printf("ERROR PRUEBA OTRA VEZ");
++n_fallos;
sleep(1);
}
...

La sentencia if puede utilizarse en combinación con else que


podemos traducirla por si no ... de este modo una sentencia (o grupo de sentencias) se ejecutara si no
se ha ejecutado la sentencia(o grupo de sentencias) que van a continuación de if.
Si la condición es verdadera, se ejecutará el primer bloque, si no, el segundo.

Ejemplo 7º: Programa que solicita la entrada de un número, y escribirá en pantalla si es positivo o
negativo.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


float a;

puts("escribe un número");
scanf("%f",&a);
if(a>=0) puts("el nº es positivo");
else puts("el nº es negativo");
puts("\aFIN");
getchar():
return 0;
}

La sentencia a continuación de else se ejecutará si no se ha ejecutado la sentencia


condicionada a if.

4.12.4.- La sentencia for.

Se utiliza de la siguiente forma:

for(exp1;exp2;exp3) La sentencia o grupo de sentencias siguientes se


ejecutarán si la expresión 2 es verdadera. La expresión 1 se utiliza para iniciar un índice y la expresión
3 para incrementarlo o disminuirlo.

Ejemplo 8º: Programa que representará los números desde 0 a 24.

4-39
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int a;
for(a=0;a<25;++a) printf("%d",a);
puts("\a\nFIN");
getchar();
return 0;
}
También podemos escribirlo de la siguiente forma:
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int a;
for(a=0;a<24;++a)
printf("%d",a);
puts("\a\nFIN");
getchar();
return 0;
}

Donde la sentencia simple controlada por for se ha tabulado para indicar que depende
de ella.

Ejemplo 9: Programa de cálculo de potencias de dos, que preguntará primero cuantas


potencias se quiere que se escriban en pantalla.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


float x=1;
int cont,b;

printf("cuantas potencias?");
scanf("%i",&b);
for(cont=1; cont<= b;++cont){
printf("\n%g",x);
x*=2;
}
printf("\n pulsa una tecla ");
getchar();
return 0;
}

4.12.5.- La sentencia break.


Se utiliza para salir de un bucle. Podemos traducirla por interrumpir o romper. En el caso de
encontrarnos en un bucle que está a su vez dentro de otro, saltará al bucle superior.

Ejemplo 10º: Programa que solicita la introducción de un número menor de 1000 y si es


mayor vuelve a solicitarlo de una manera reiterativa. Si es menor, sale del bucle.

#include <ansi_c.h>

4-40
#include <cvirte.h>

int main (int argc, char *argv[]){


float a;
do{
puts("escribe un número menor de 1000");
scanf("%f",&a);
if(a<1000) break; /*sale del bucle si es correcto*/
puts("\nEl nº no es correcto");
}while(a>=1000);
puts("\nFIN");
getchar();
return 0;
}

4.12.6.- La sentencia switch.

Con ésta sentencia, podemos ejecutar una línea o grupo de líneas pertenecientes a un grupo
mayor. Esta funcionará con una variable de carácter, que dependiendo del valor que tome, el flujo del
programa se desviará entre distintas opciones denominadas case.
Ejemplo 11º: Problema que solicita la elección de un color mediante la pulsación de
una tecla y luego escribe en pantalla dicho color.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


char eleccion,p;
do{
printf("elige entre \"r\",\"b\" o\"n\"");
eleccion=getchar();
switch(elección) {
case 'r':
case 'R':
printf("rojo");
break;
case 'b':
printf("blanco");
break;
case 'n':
printf("negro");
break;
default:
printf("no has elegido entre \"r\", \"b\" o \"n\"");
}
printf("\n pulsa \"s\" o \"n\" para continuar");
p=getchar();
}
while(p=='s');
printf("\n fin del programa");
getchar();
return 0;
}

4.12.7.- La sentencia continue.

4-41
Se utiliza para saltar las sentencias posteriores dentro de un bucle si se da la condición anterior
if.

Ejemplo 12º: Programa que solicita la introducción de un número menor de 1000 y positivo, y
si es mayor o negativo vuelve a solicitarlo de una manera reiterativa. Si es correcto sale del bucle.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
float a;
do{
puts("\nescribe un número menor de 1000=");
scanf("%f",&a);
if(a>=0)continue;
puts("\nEl número es negativo");
}while(a>1000||a<0);
puts("el número es correcto");
getchar();
return 0;
}

En el programa si (a>0) saltará las sentencias posteriores del bucle, pero no saldrá de él. Si no
es válida el bucle seguiré ejecutándose.

4.12.8.- La sentencia exit.

La sentencia exit sirve para terminar un programa incluso si se está en cualquier tipo de bucle.

Ejemplo 13: Escribe un programa que obtenga un número entero positivo desde el teclado, e
imprima el mensaje "HOLA" tantas veces como indique el número, y que acabe si el número es
negativo.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int t;
printf("escribe un nº
entero positivo\n");
scanf("%d",&t);
if(t<0)exit(0);
for(;t>0;--t)
printf("\nHOLA");
getchar();
return 0;
}

4.13.- Funciones.

4-42
Un código fuente de un programa consta de distintas funciones, una de las cuales debe ser la
función main. Hasta ahora, todos los programas que hemos visto constan tan sólo de esta función.
Una función es un segmento del programa que realiza una determinada tarea bien definida
(podemos decir que se asemeja a una subrutina o una macro). Podemos definirla también como una
unidad de código autocontenida, diseñada para realizar tareas determinadas.
Estas se definirán al igual que main() entre llaves y tendrán un nombre y unos argumentos
denominados formales encerrados entre paréntesis.
Veamos un ejemplo de programa que contenga una función denominada funcion_1():

void main()
{
línea 1;
línea 2;
funcion_1( ); /*llamada a la función*/
línea 4;
...
línea 25;
funcion_1( );//llamada a la función

línea 27 ;
}

void funcion_1( ) //definición de la función


{
línea 1;
línea 2;
...
línea 9;
return;
}
En el ejemplo vemos que a la función se le llama desde main dos veces (se podrá llamar a la
función todas las veces que queramos) luego es evidente que para evitar tediosas repeticiones de partes
de un programa, es interesante estructurar este código fuente con una o varias funciones, a parte de la
función main().

A una función podemos tratarla como una caja negra, a la que podemos introducir un valor o
varios (opcional) denominados argumentos formales de tipo char, int, float...etc, ejecuta una acción
y/o procesa esta entrada, y puede devolver (opcional) otro valor.

main() se puede escribir también void main(void)


1º 2º 3º

que corresponderá: 1º valor devuelto por la función .


2º nombre de la función.
3º argumento formal que admite la función.

Veamos algunos ejemplos:

Ejemplo 1º: La función saluda() no tendrá argumentos formales y tampoco devolverá valor alguno,
tan sólo ejecutará una acción simple.

#include <ansi_c.h>
#include <cvirte.h>

4-43
void saluda( void){
puts("\n\nHOLA \nEstas dentro de la función");
puts("pulsa una tecla para continuar");
getchar();
return;
}
int main (int argc, char *argv[]){

gotoxy(30,10); /*sitúa el cursor col.30, fila 10")*/


puts("Ahora vamos a llamar a la función\nPulsa una tecla");
getchar();
saluda();
puts("\n\n\aFIN");
getchar();
return 0;
}

La palabra clave return sirve para retornar de nuevo al programa o función principal main().
Si a continuación de return aparece una expresión entre paréntesis, esta queda como valor de retorno
de dicha función.
Las funciones distintas de main debe ir delante de estas o declararse en main, al igual que las
variables a utilizar, veamos un ejemplo;

Ejemplo 2º: La función mayor() va a aceptar dos valores enteros (argumentos formales) y va a
devolver el mayor de ellos.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a,b,resultado; //declaración de variables a utilizar.


int mayor(int x,int y); //declaración de función a utilizar.
puts("escribe dos números enteros separados por espacio")
puts("en blanco o pulsando enter");
scanf("%d %d",&a,&b);
resultado=mayor(a,b); /*llamada a la función*/
printf("\nel mayor de estos dos números es %d",resultado);
getchar();
return 0;
}

int mayor(int x,int y) { //definición de la función.

if(x>y) return(x);
else return(y);
}

Vemos que en la definición de la función va precedida del tipo de valor que devuelve int
mayor() y que dentro de los paréntesis se definen los tipos de los argumentos que acepta.

Ejemplo 3º:

4-44
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int n; //declaración de variable a utilizar.
long int factorial(int n); //declaración de función a utilizar.
printf("Escribe el nº del cual se calculará su factorial");
printf("\n nº=");
scanf("%d",&n);
printf("\n\n n!=%ld",factorial(n));
getchar();
return 0;
}

long int factorial(int n)


{
int i;
long int prod=1;
if(n>1)
for(i=2;i<=n;++i)
prod *=i;
return(prod);
}

Si hubiésemos escrito la definición de la función antes que la función principal main(), no


sería en este caso necesario declararla.

Utilización de funciones en otros programas. Podemos escribir en un archivo tantas funciones


como queramos y luego este introducirlo como archivo de cabecera mediante #include<nombre.h>
denominandose a estas con el nombre de macros, y al archivo de cabecera (de extensión h) archivo de
macros.

4.14.- Recursividad..

Se denomina recursividad a la facultad de una función de llamarse a sí misma. Veamos un


ejemplo en que una función que sólo escribe un asterisco en pantalla y acepta un numero int, se llama
a sí misma.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a;
void asterisco(int x);
puts("¿números de asteriscos a escribir?");
scanf("%d",&a);
asterisco(a);
puts("\n");

4-45
getchar();
return 0;
}

void asterisco(int x)
{
if(x==1) return;
putchar('*');
asterisco(x-1);
}

4.15.- Ampliación sobre arrays..

Un array es una agrupación de caracteres, números enteros, números decimales e incluso


cadenas de caracteres. Estos pueden ser estáticos, automáticos o externos, de una dimensión o
multidimensionales.

Veamos unos ejemplos de cómo declarar arrays:

int numeros[10]; almacenará diez números enteros (desde


numeros[0] a numeros[9].

float decimales[45]; almacenará 45 números decimales (desde decimales[0] a


decimales[44].

char letras[7]; almacenará 7 caracteres (desde letras[0] a letras[6]), o bien 6


caracteres más el carácter nulo ’\0’ si se tratase de una
cadena.

int a[4][2]; almacenará 4*2=8 números enteros cuatro filas por dos columnas:
a[0][0] a[0][1]
a[1][0] a[1][1]
a[2][0] a[2][1]
a[3][0] a[3][1]

char letras[]="California"; almacenará once caracteres correspondientes a las diez letras mas el
nulo ’\0’ ( donde las "casillas" del array se llenaran
con el código ASCII de los caracteres:

letras[0]--->’C’
letras[1]--->’a’
letras[2]--->’l’
...
letras[9]--->’a’
letras[10]-->’\0’

char color[3]={’R’,’E’,’D’}; en este caso no se almacenará el carácter nulo,


correspondiendo:

color[0]--->’R’

4-46
color[1]--->’E’
color[2]--->’D’

char color[3]="RED"; igual que el caso anterior(sin el carácter nulo).

char color[]="RED"; igual que los dos casos anteriores (con el carácter nulo).

static float x[6]={0,0.25,0.345,0,23.7,45};

4.15.1.- Procesamiento de arrays de 1 dimensión.

El lenguaje C no permite operaciones que impliquen arrays completos (al contrario de otros
lenguajes), así que estos deben realizarse elemento a elemento, por supuesto que la dimensión de
ambos debe ser idéntica.

Ejemplo primero: vamos a realizar un programa que defina a dos arrays a y b de tres números
enteros, dandole valores iniciales en ambos y nos presente en pantalla el resultado que debe ser otro
array al que denominaremos c.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int n,c[3];
int a[3]={7,14,32};
int b[3]={14,4,100};
for(n=0;n<3;++n) c[n]=a[n]+b[n];
printf("c[0]=%d \n",c[0]);
printf("c[1]=%d \n",c[1]);
printf("c[2]=%d \n",c[2]);
getchar();
}

Vemos que es necesario efectuar un bucle que vaya sumando cada elemento del array a con el
correspondiente elemento del array b. Este programa podría haberse realizado también de una manera
más resumida:

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int n,c[3];
int a[3]={7,14,32};
int b[3]={14,4,100};
for(n=0;n<3;++n) printf("\n c[%d]=%d",n,a[n]+b[n]);
getchar();
}

Ejemplo segundo: Supongamos que queremos leer una lista de n cantidades en coma flotante y
calcular la media. Además de calcular simplemente la suma, se calculará también la desviación de

4-47
cada uno de los valores respecto a la media, siguiendo la expresión d = xi - media donde xi representa
las cantidades i=1,2,3, ...,n y media representa la media calculada.

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int n,cont;
float media,d,suma=0;
float lista[100]; /*array con capacidad para 100 números float*/

/*leer el valor de n */
printf("¿Cuantos números para calcular la media?");
scanf("%d",&n);
printf("\n");

/*leer los números y calcular su suma*/


for(cont=0;cont<n;++cont){
printf("i=%d x =",cont+1);
scanf("%f",&lista[cont]);
suma+=lista[cont];
}

/*calcula la media y escribe la respuesta*/


media=suma/n;
printf("\nLa media es %5.2f\n\n",media);

/*calcula y escribe las desviaciones respecto de la media*/


for (cont=0;cont<n;++cont){
d=lista[cont]-media;
printf("i=%d x=%5.2f d=%5.2f\n",cont+1,lista[cont],d);
}
return 0;
}

Vemos que cuando hacemos referencia a un elemento del array lista en la segunda función
scanf se utiliza un ampersand & (scanf("%f",&lista[cont]);).

4.15.2.- Paso de arrays a funciones.

Para pasar un array a una función, el nombre del array debe aparecer solo sin
corchetes. Los valores del array pueden ser alterados por la función y ser reconocidos dentro de main
sin ningún problema.
Veamos un ejemplo de un programa que presenta los tres números enteros de un array,
llama a la función sumauno(que sumará una unidad a cada número y presentará de nuevo los tres
números del array:

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){


int cont;
int n[3]={3,5,7};
void suma_uno();

4-48
for(cont=0;cont<3;++cont)printf("n[%d]=%d\n",cont,n[cont]);
suma_uno(n);
for(cont=0;cont<3;++cont)printf("n[%d]=%d\n",cont,n[cont]);
getchar();
return 0;
}

void suma_uno(int x[3]) //o mejor void suma_uno(int *x) acepta un puntero a entero
{
int cont;
for(cont=0;cont<3;++cont)x[cont]+=1;
return;
}

4.15.3.- Arrays multidimensionales.

Los arrays multidimensionales son definidos prácticamente de la misma manera que los arrays
unidimensionales, excepto que se requiere un par separado de corchetes para cada índice. Así un array
bidimensional requerirá dos corchetes, un array tridimensional tres ... y así sucesivamente.
Ejemplo:
int numeros[4][7] ---> tendrá una capacidad de 4 filas por siete columnas de números
int, es decir, una capacidad de 4*7=28 números int.

float cifras[3][5][8] ---> tendrá una capacidad de 3 filas por cinco columnas por 8
tablas de números float, es decir, una capacidad de 3*5*8=120 números float.

Un array por ejemplo a[5][3] contendrá los siguientes elementos:

a[0][0] a[0][1] a[0][2]


a[1][0] a[1][1] a[1][2]
a[2][0] a[2][1] a[2][2]
a[3][0] a[3][1] a[3][2]
a[4][0] a[4][1] a[4][2]

Estos elementos dependiendo del tipo como se haya definido el array (int, float, chart ...etc)
podrán contener un número o una letra.

Veamos una definición de array multidimensional donde se le asigna un valor inicial:

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

asignandose de la siguiente forma:

a[0][0]=1 a[0][1]=2 a[0][2]=3


a[1][0]=4 a[1][1]=5 a[1][2]=6
a[2][0]=7 a[2][1]=8 a[2][2]=9
a[3][0]=10 a[3][1]=11 a[3][2]=12
a[4][0]=13 a[4][1]=14 a[4][2]=15

Veamos como ejemplo un programa que defina un array de 5 filas por tres columnas y que
represente en la pantalla a modo de matriz todos sus elementos. Realizar el programa de la forma más
reducida posible.

4-49
#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int a[5][3]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int f,c;
for(f=0;f<5;++f){
putchar('\n');
for(c=0;c<3;++c)
printf("a[%d][%d]=%2d ",f,c,a[f][c]);

}
getchar();
return 0;
}

Para procesar arrays multidimensionales, por ejemplo sumar dos arrays, estos deben tener las
mismas dimensiones, veamos un ejemplo de ello realizando un programa que sume dos arrays de
cuatro filas por dos columnas de numeros enteros y nos muestre el resultado. Los valores iniciales
serán: a[4][2]={1,2,3,4,5,6,7,8} y b[4][2]={10,20,30,40,50,60,70,80}

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int f,c;
int a[4][2]={1,2,3,4,5,6,7,8};
int b[4][2]={10,20,30,40,50,60,70,80};
int r[4][2];
for(c=0;c<2;++c){
for(f=0;f<4;++f)
r[f][c]=a[f][c]+b[f][c];
}
for(c=0;c<2;++c){
putchar('\n');
for(f=0;f<4;++f)
printf("r[%d][%d]=%3d ",f,c,r[f][c]);
}
getchar();
return 0;
}

Ejemplo de programa que pide la introducción de elementos en una tabla de 3*2 y luego muestra dicha
tabla:

#include <ansi_c.h>

int main (void)


{

4-50
int contF,contC,tabla[3][2];

for(contF=0;contF<3;++contF){
for(contC=0;contC<2;++contC){
printf("\n tabla[%d][%d]=",contF,contC);
scanf("%d",&tabla[contF][contC]);
}
}

printf("\n La tabla es:\n");

for(contF=0;contF<3;++contF){
for(contC=0;contC<2;++contC){
printf(" tabla[%d][%d]=%d",contF,contC,tabla[contF][contC]);
}
printf("\n");

printf("\n\nFIN DEL PROGRAMA");


getchar();
getchar();
return(0);

Programa para buscar coincidencias en una tabla de 5x10


#include <ansi_c.h>
#include <utility.h>
#include <cvirte.h>

int main (void)


{ float semilla;
int f,c,n=0,num;
int x[5][10];
//introducción se semilla para el generador
printf("Introduce una semilla=");

scanf("%f",&semilla);
srand(semilla);
//bucle para introducir aleatoriamente todos los datos
for(f=0;f<5;++f){
for(c=0;c<10;++c){
x[f][c]=rand()%10;

//bucle para comprobar todos los datos


for(f=0;f<5;++f){
printf("\n %d %d %d %d %d %d %d %d %d
%d",x[f][0],x[f][1],x[f][2],x[f][3],x[f][4],x[f][5],x[f][6],x[f][7],x[f][8],x[f][9]);

4-51
}

printf("\n\n numero para buscar coincidencias=");


scanf("%d",&num);
//bucle para comprobar las coincidencias
for(f=0;f<5;++f){
for(c=0;c<10;++c){
if(num==x[f][c])
++n;

}
printf("\n\n El numero de veces que se repite es %d",n);

fflush(stdin);
getchar();
printf("\n Fin del programa");
Delay(2);
return 0;
}

4.15.4.- Arrays y cadenas de caracteres.

Vamos a ver como primer ejemplo, un programa que acepte diez frases de hasta 15 caracteres
y posteriormente las muestre.

#include <ansi_c.h>
#include <cvirte.h>

int main (void){

int n;
char x[10][15];
for(n=0;n<10;++n){
printf("\nescribe la frase numero%d= \n",n);
gets(x[cont]); //scanf(“%s”,&x[n]); //scanf("%[^\n]",x[n]);
getchar();
}
getchar();

for(n=0;n<10;++n)
printf("\nla frase numero%d es: \n%s",n,x[n]);
getchar();
return 0;
}

Vamos a ver como segundo ejemplo, un programa que reordene un array de 5 números
enteros, y posteriormente los muestre ya ordenados:

#include <ansi_c.h>
#include <cvirte.h>

4-52
int main (void)
{

int num[5],cont_a,cont_b,aux;

for(cont_a=0;cont_a<5;++cont_a){
printf("\n num[%d]=",cont_a);
scanf("%d",&num[cont_a]);
}

for(cont_a=0;cont_a<4;++cont_a){
for(cont_b=cont_a+1;cont_b<5;++cont_b)
if(num[cont_a]>num[cont_b]){
aux=num[cont_a];
num[cont_a]=num[cont_b];
num[cont_b]=aux;
}
for(cont_a=0;cont_a<5;++cont_a)
printf("\nnum[%d]=%d",cont_a,num[cont_a]);
fflush(stdin);//limpia teclado
getchar();
}

printf("\n\nFIN DEL PROGRAMA");


getchar();
getchar();
return(0);
}

Vamos a ver como tercer ejemplo, un programa para reordenar cadenas de caracteres. Supongamos
que queramos introducir una lista de nombres y reordenarlas alfabéticamente. El problema planteado
es similar al ordenar una lista de números. Las palabras las introduciremos en un array bidimensional
de caracteres, por lo que cada palabra será introducida en una fila de este array. Y por último
utilizaremos las funciones de biblioteca strcmpi y strcpy, estas funciones se usan para comparar dos
cadenas y para copiar una cadena en otra respectivamente.
La función strcmpi es una variación de la función strcmp, que compara alfabéticamente cadenas sin
distinguir entre mayúsculas y minúsculas, al contrario de strcpm que sí las tiene en cuenta.
La función strcmpi acepta dos cadenas como argumentos y devuelve un valor entero, dependiendo del
orden relativo de las dos cadenas, tal como sigue:
- Devuelve un valor negativo si la 1ª cadena precede alfabéticamente a la 2º.
- Devuelve un valor cero si ambas cadenas son idénticas.
- Devuelve un valor positivo si la 2ª precede alfabéticamente a la 1ª.

Por tanto si la strcmpi(cadena1,cadena2) retorna un valor positivo, indicará que la segunda cadena
deberá ir delante de la primera.

Por último, el programa aceptará un número no determinado de cadenas, hasta que los tres primeros
caracteres de una cadena sean FIN, ignorandose esta palabra.

#include <ansi_c.h>
#include <cvirte.h>

4-53
#include <string.h>

int main (int argc, char *argv[]){

int cont_a,cont_b;
char x[5][12];

for(cont_a=0;cont<5;++cont_a){
printf("escribe la frase nº%d",cont_a);
gets(x[cont_a]);
}
for(cont_a=0;cont_a<4;++cont_a)
for(cont_b=cont_a+1;cont_b<5;++cont_b)
if(strcmp(x[cont_a],x[cont_b])>0){
strcpy(aux,x[cont_a]);
strcpy(x[cont_a],x[cont_b]);
strcpy(x[cont_b],aux);
}
printf(“\n\n\n”);
for(cont_a=0;cont_a<5;++cont_a)
printf(“\n%s”,x[cont_a]);
getchar();
return 0;
}

4-54
4.16.-Punteros.

4.16.1.-Concepto de puntero.
Un puntero es una variable que almacena la posición o dirección de memoria de otro dato que
puede ser una variable o un elemento de un array. Un puntero nos proporciona la posibilidad de usar
direcciones de memoria, esto hace que los programas que utilizan punteros puedan ser más eficientes,
ya que permiten aproximarnos a la forma de trabajo de la máquina.
Los punteros están muy relacionados con los arrays, el nombre del array en en realidad un
puntero al primer elemeinto del mismo.

Veamos un ejemplo de puntero, partiendo de una variable x de valor 10:

variable: x = 10
dirección de la variable: &x = 5AF
puntero de esta variable: px = 5AF
o bien: punt_x = 5AF
valor almacenado en dicha dirección: 10
valor almacenado donde apunta el puntero: *px = 10

Vemos que si la variable es x, &x representa su dirección, y por lo tanto un puntero de dicha
variable que podremos denominarlo como queramos (no tiene porqué llamarse así) por ejemplo
punt_x o px o puntero_1 tendrá como valor la dirección de esta variable. Mencionar también que se
representa por *punt_x al valor almacenado por la variable x, es decir al valor almacenado donde
apunta dicho puntero.

Veamos un segundo ejemplo:


#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int u = 3;
int v;
int *pu; /*declaración de puntero de un entero(de la variable u)*/
int *pv; /*puntero de la variable de un entero(de la variable v)*/
pu = &u; /*asigna la dirección de u al puntero pu*/
v = *pu; /*asigna el valor de u a v ya que *pu=u=3*/
pv = &v; /*asigna la dirección de v al puntero pv*/

printf("\n u=%d &u=%x pu=%x *pu=%d",u,&u,pu,*pu);


printf("\n v=%d &v=%x pv=%x *pv=%d",v,&v,pv,*pv);
getchar();
return 0;
}

4-55
En pantalla se presentará el valor de las variables, las direcciones de dichas variables, los
punteros de dichas variables y por último el valor almacenado a donde apuntan dichos punteros, luego:
u = *pu v = *pv
&u = pu &v = pv

Veamos un tercer ejemplo:

#include <ansi_c.h>
#include <cvirte.h>

int main (int argc, char *argv[]){

int u1,u2;
int v=3;
int *pv=&v;/*hace innecesaria la línea “pv=&v” */

u1=2*(v+5);
u2=2*(*pv+5);
printf("\n u1=%d u2=%d",u1,u2);
getchar();
return 0;
}

El programa presentará un mismo valor para ambas variables u1 y u2 de 16. luego podremos
tratar a v de igual forma a *pv.

Es importante reseñar que no se puede asignar una dirección concreta a un puntero, es decir,
no podremos por ejemplo escribir en un programa &x=5AF; sino que será el propio ordenador quien
asigne una dirección.
Ya hemos visto en los ejemplos anteriores como declarar punteros a variables int. En general, un
puntero debe ser declarado como cualquier otra variable y asignarle posteriormente un valor (que será
en este caso una dirección de variable). La expresión general podría ser:

tipo_dato *punt_var;
Por ejemplo:
float u; /*declaración de la variable u*/
float *ptu; /*declaración del puntero de u*/
char a; /*declaración de la variable a*/
char *punt_a /*declaración del puntero de a*/

Es importante señalar que en la definición del puntero se utiliza el asterisco (float *ptu)
pero no en la sentencia de asignación de la dirección (ptu=&u).

4-56
4.16.2.- Paso de punteros a una función.

Vimos en el capítulo anterior como pasar un array como argumento en una llamada a una
función, siendo todos los elementos de esta accesibles por dicha función. También podemos en una
llamada a una función, pasar como argumento a un puntero. En ambos casos citados se conoce este
paso de información como paso de argumentos por referencia.
En el caso de pasar un valor o valores de tipo int, char o float ..etc en una llamada a una
función, se conoce este paso de información como paso de argumentos por valor.
En este último caso, este valor puede modificarse en dicha función, a no ser que la variable sea
externa y por lo tanto adcesible a las distintas funciones del programa.

Veamos un ejemplo:

void SumaCinco(int *x, int *y){


*(y)=*(x)+5;
*(y+1)=*(x+1)+5;
*(y+2)=*(x+2)+5;
return;
}

int main (void)


{
int x[3]={1,3,5},y[3];
SumaCinco(x,y);
printf("\nEl valor de y[0]es %d",y[0]);
printf("\nEl valor de y[1]es %d",y[1]);
printf("\nEl valor de y[2]es %d",y[2]);

printf("\nEl valor de *(y) es %d",*(y));


printf("\nEl valor de *(y+1) es %d",*(y+1));
printf("\nEl valor de *(y+2) es %d",*(y+2));

printf("\n\nFIN DEL PROGRAMA");


getchar();
return(0);
}
Veamos un ejemplo:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int u=1;
int v=3;
void func1(int u, int v);
void func2(int *pu,int *pv);
printf("\nAntes de la llamada a func1: u=%d v=%d",u,v);

4-57
getchar();
func1(u,v);
getchar();
printf("\n\nDespués de la llamada a func1: u=%d v=%d",u,v);
getchar();
printf("\nAhora vamos allamar a func2, pulsa una tecla");
getchar();
func2(&u,&v);
printf("\n\nDespués de llamar a func2: u=%d v=%d",u,v);
getchar();
return 0;
}

void func1(int u,int v)


{ u=0;
v=0;
printf("\nDentro de func1: u=%d v=%d",u,v);
getchar();
return;
}

void func2(int *pu, int *pv)


{ *pu=0;
*pv=0;
printf("\nDentro de la func2: *pu=%d *pv=%d",*pu,*pv);
getchar();
return;
}

Al ejecutar el programa, mostrará los valores 1 y 3 antes de llamar a func1, dentro de func1 los
valores serán los asignados por la función es decir, cero en ambos casos. Al mostrarse de nuevo los
valores de ambas variables ya fuera de func1, los valores vuelven a ser de 1 y 3, por lo tanto func1 no a
podido modificar estos valores (paso por valor).
La llamarse a func2 estos se modifican dentro de la función, mostrandose en pantalla el valor
de cero para ambas variables al igual que en la primera función, pero con la diferencia de que al salir
de dicha función, estos valores sí han sido modificados manteniendose ahora el valor de cero dado por
la función (paso por referencia).

4.16.3.- Punteros y arrays unidimensionales.


Realmente el nombre de un array unidimensional es un puntero al primer elemento de ese
array.

Las direcciones: equivalen a:


&x[0] x
&x[1] x+1
&x[2] x+2
... ...
&x[n] x+n

Los datos: equivalen a:

4-58
x[0] *x
x[1] *(x+1)
x[2] *(x+2)
... ...
x[n] *(x+n)

Veamos un ejemplo:
#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int x[8]={2,4,6,8,10,12,14,16};
int i;
for(i=0;i<8;++i)
printf("\ni=%d x[i]=%d *(x+i)=%d &x[i]=%x
x+i=%x",i,x[i],*(x+i),&x[i],x+i);
getchar();
return 0;
}

Veremos que lod valores x[i] son iguales a *(x+i), y los valores &x[i] iguales a x+i.

Veamos un segundo ejemplo:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int x[12],i;
for(i=0;i<12;++i){
printf("escribe el nº %2dº=",i);
scanf("%d",&x[i]);
}
for(i=0;i<12;++i){
printf("\ni=%2d x[%2d]=%6d *(x+%d)=%6d",i,i,x[i],i,*(x+i));
printf("printf("&x[%2d]=%3x x+%2d=%3x",i,&x[i],i,x+i);
}
getchar();
return 0 ;
}

Veremos al ejecutar el programa que el valor x[i] es igual a *(x+i) y que la dirección
&x[i] es igual a x+i.

En estos ejemplos se comprueba que el nombre de un array unidimensional es en realidad un


puntero del primer elemento de dicho array. Es decir, la dirección &num[0] será igual que la dirección
x.
Por lo tanto, es posible definir un array como puntero, existiendo el inconveniente de no poder
asignar valores iniciales, por lo que será necesaria una asignación convencional posterior.

4-59
Las dos definiciones son equivalentes, pero la definición convencional de un array produce la
reserva de un bloque fijo de memoria al principio de la ejecución del programa, mientras que esto no
ocurre si se define como puntero. Sin embargo, cuando se va a almacenar un número importante de
datos, por ejemplo 10 números int, es conveniente reservar un bloque de memoria por adelantado, para
ello utilizaremos la función de biblioteca malloc() para asignar suficiente memoria al array.

Veamos un ejemplo de lo dicho:

int *x /*define a un puntero a entero*/


x = malloc(10*sizeof(int)); /*reserva un bloque de memoria para 10 nº int*/

La función malloc() devuelve un puntero a un carácter siendo x un puntero int por lo que,
siendo eceptable la forma de uso anterior ( x=malloc(10*sizeof(int)) ), se puede realizar para mayor
seguridad una conversión de tipo de la siguiente forma:

x=(int*)malloc(10*sizeof(int));

Este tipo de reserva se denomina "reserva dinámica de memoria" .

Cuando se programa en C, no es inusual usar expresiones con punteros en vez de referencias a


elementos individuales del array. El programa resultante puede aparecer extraño al inexperto, pero
deja de serlo cuando el programador se acostumbra a acceder a valores almacenados en direcciones
específicas. Generalmente sólo se necesita un poco de práctica.

Veamos un ejemplo con un programa que va a reordenar un array unidimensional de enteros


de mayor a menor usando para ello notación de punteros:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int i,n,*x;
void reordenar(int n,int *x);

/*leer un valor para n*/


printf("\n¿Cuantos números serán introducidos?");
scanf("%d",&n);
printf("\n");

/*reserva dinámica de memoria*/


x = (int*)malloc(n*sizeof(int));

/* leer la lista de números*/


for (i=0;i<n;++i){
printf("i=%d x= ",i+1);
scanf("%d",x+i);
getchar();
return 0;
}

4-60
/*reordenar todos los elementos del array*/
reordenar(n,x); /*mostrar la lista de números reordenada*/
printf("\n\nLista de números reordenada: \n\n");
for(i=0;i<n;++i)printf("i=%d x=%d\n",i+1,*(x+i));
getchar();
}

void reordenar(int n, int *x) /*reordenar la lista de números*/


{
int i,elem,temp;
for(elem=0;elem<n-1;++elem)
/*buscar el menor del resto de los números*/
for(i=elem+1;i<n;++i)
if(*(x+i)<*(x+elem)){/*intercambiar dos números*/
temp = *(x+elem);
*(x+elem) = *(x+i);
*(x+i) = temp;
}
return;
}
En este programa el array de enteros es definido como un puntero a entero. La asignación
inicial de memoria para la variable puntero se hace mediante la función de biblioteca malloc(). En
todo el programa se usa la notación de punteros para acceder a elementos individuales del array. Por
ejemplo, la declaración de la función reordenar() dentro de main() ahora especifica que el segundo
argumento es un puntero a una cantidad entera en vez de un array de enteros. Este puntero identificará
el comienzo del array de enteros.
También vemos que la función scanf() especifica ahora la dirección del i-ésimo elemento
como x+i en lugar de &x[i]. Similarmente, la función printf() representa el valor del i-ésimo elemento
como *(x+i) en vez de x[i].
Dentro de la función reordenar(), el segundo argumento formal está ahora definido como una
variable puntero en lugar de como un array de enteros. Esto es consistente con la declaración de la
función en main(). Las diferencias más pronunciadas se encuentran en la sentencia if. En particular
notar que cada referencia a un elemento simple del array está escrita como el contenido de una
dirección. Así x[i]está escrito como *(x+i) y x[elem] como *(x+elem). Esta sentencia if puede ser
vista como un intercambio condicional entre los contenidos de dos direcciones, mejor que como un
intercambio entre dos elementos diferentes de un array convencional.

4.16.4.-Operaciones con punteros.


Hemos visto en el apartado anterior, que se puede sumar un valor entero a un nombre de array
para acceder a un elemento individual del array. El valor entero es interpretado como el índice del
array; representa la localización relativa del elemento deseado con respecto al primero del array. Esto
funciona ya que todos los elementos del array son del mismo tipo y por tanto cada elemento ocupa un
mismo número de celdas de memoria (mismo número de bytes o palabras). El número de celdas que
separan a dos elementos del array dependerá del tipo de datos del array, pero de esto se encarga el
compilador automáticamente y por tanto no concierne al programador directamente.
Este concepto se puede extender a las variables puntero. En particular, un valor entero puede
ser sumado o restado a una variable puntero, pero el resultado de la operación debe ser interpretado

4-61
con cuidado. Supongamos que px es una variable puntero que representa la dirección de una variable
x. Podemos escribir expresiones como ++px, --px, (px+3), (px+i) y (px-i), donde i es una variable
entera. Cada expresión representará una dirección localizada a cierta distancia de la posición original
representada po px. La distancia exacta será el producto de la cantidad entera por el número de bytes o
palabras que ocupa cada elemento al cual apunta px.

Veamos un ejemplo, si px apunta a un entero, como un entero requiere dos bytes de


memoria, entonces la expresión (px+2) resultará en una dirección 6 bytes más allá del entero apuntado
por px.
Una variable puntero puede ser restada a otra siempre que ambas variables apunten a
elementos del mismo array. El valor resultante indica el número de palabras o bytes que separan los
correspondientes elementos del array. Veamos un ejemplo:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int *px,*py;
static int a[6]={1,2,3,4,5,6};

px=&a[0];
py=&a[5];
printf(“px=%x py=%x”,px,py);
printf(“\n\npy-px=%x”,py-px);
getchar();
return 0;
}

Si se ejecuta el programa daría como salida:


px=52 py=5C

py-px=5

La diferencia entre 5C y 52 es de 10, pero al estar almacenados como números int, el resultado
es el esperado, es decir, 5.

A modo de resumen, las operaciones que pueden realizarse con punteros son:

- A una variable puntero se le puede asignar la dirección de una variable ordinaria (pv=&v).
- A una variable puntero se le puede asignar el valor de otra variable puntero (por ejemplo
px=py), siempre que ambos punteros apunten al mismo tipo de datos.
- Una cantidad entera puede ser sumada o restada a una variable puntero (por ejemplo pv+3,
++pv).
- Una variable puntero puede ser restada de otra siempre que apunten a datos del mismo array.
- Dos variables puntero pueden ser comparadas siempre que ambas apunten a datos del mismo
tipo.
void SumaCinco(int *x,int *y){
*(y)=*(x)+5;
*(y+1)=*(x+1)+5;

4-62
*(y+2)=*(x+2)+5;
return;
}

int main (void)


{
int x[3]={1,3,5},y[3];
SumaCinco(x,y);
printf("\nEl valor de y[0]es %d",y[0]);
printf("\nEl valor de y[1]es %d",y[1]);
printf("\nEl valor de y[2]es %d",y[2]);

printf("\nEl valor de *(y) es %d",*(y));


printf("\nEl valor de *(y+1) es %d",*(y+1));
printf("\nEl valor de *(y+2) es %d",*(y+2));

printf("\n\nFIN DEL PROGRAMA");


getchar();
return(0);
}

4.17.- Tipos de almacenamientos de variables.

Las variables se pueden clasificar por el tipo de datos (char, int, float ...etc) o bien por el tipo
de almacenamiento, dividiéndose en auto, extern, static y register.
A veces el tipo de almacenamiento asociado a una variable se puede establecer simplemente
por la localización de su declaración en el programa. En otras situaciones, sin embargo, la palabra
clave que especifica un tipo particular de almacenamiento se tiene que colocar al principio de la
declaración de la variable. Veremos como dependiendo del tipo de almacenamiento, una variable se
podrá comportar de una u otra manera.
Veamos simplemente en como se realiza estas declaraciones sin profundizar en su significado:

auto int x, ,z;


extern int valor ,total,indice;
static float a;
register int mes,dia;
register char u;

char
Tipo de datos: int
float
Variables:

auto
Tipo de almacenamiento: extern
static

4-63
register

Variables automáticas: Estas variables se declaran dentro de una función y son locales a esta, es
decir serán reconocidas sólo dentro de dicha función. Las variables automáticas no son necesarias
declararlas como tales, por lo tanto, cualquier variable declarada como hasta este momento (sin
ninguna alusión a su forma de almacenamiento) se interpretará como una variable automática.

Variables externas: Estas no están ligadas a una función determinada. Su ámbito se extiende desde el
punto en que se declaran, hasta el resto del programa, por lo que pueden ser llamadas por cualquier
función posterior. Mantienen para una función el valor asignado desde otra, por lo que es interesante a
la hora de transferir información desde una función a otra, ya que el comando return sólo transfiere un
dato.
Una definición de variable externa debe realizarse fuera de cualquier función y
normalmente antes de las funciones que acceden a esta.

Variables estáticas: Este tipo de variables se definen dentro de una función, por lo tanto son de
ámbito local. Para ello es obligatorio emplear la palabra clave static ya que si no se consideraría
automática.
Al contrario que las variables automáticas, estas retienen el valor almacenado durante toda la
vida del programa.
A todas las variables estáticas cuyas declaraciones no incluyan valores iniciales explícitos se
les asignará el valor cero.

Veamos un ejemplo de variable estática:


#include <ansi_c.h>
int a;
void SumaUno(void){
static int cont=1;
a=a+1;
printf("\n\nNde veces accedido a la funcion=%d",cont);
++cont;
return;
}

int main (void)


{
printf("Introduce un valor int=");
scanf("%d",&a);

SumaUno();
printf("\nEl nuevo valor de a es: %d",a);

SumaUno();
printf("\nEl nuevo valor de a es: %d",a);

printf("\n\nFIN DEL PROGRAMA");


getchar();
getchar();
return(0);

Veamos otro ejemplo de variable estática:

4-64
#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int cont;
void función(void);
for(cont=1;cont<=5;cont++){
printf("Aquí está la prueba %d:\n",cont);
funcion();
}
getchar();
return 0;
}

void funcion(void)
{
int a=1;
static int b=1;
printf("a=%d b=%d\n",a++,b++);
}

Cada vez que se accede a la función funcion(), la variable a toma el valor 1, pero la variable
estática b contiene el último valor asignado, ignorando el que se le da en su definición.

#include <ansi_c.h>

int main (void)


{
register long int cont;
printf("PULSA UNA TECLA PARA EMPEZAR");
getchar();
for (cont=0;cont<500000000;++cont);

printf("\nEl valor contado es %ld",cont);


printf("\n\nFIN DEL PROGRAMA");
getchar();

return(0);

4-65
4.18.- Programación a bajo nivel.
C permite la manipulación de bits individualmente dentro de una palabra. Así los bits pueden
ser desplazados hacia la izquierda o hacia la derecha, invertidos, o enmascarados. Las plicaciones que
requieren tale operaciones son familiars a los programadores en lenguaje ensamblador. C también
permite organizar en grupos individuales los bits dentro de una palabra. Esto permite empaquetar
datos de una sola palabra.

4.18.1.- Variables de registros.

Este tipo de almacenamiento se utiliza casi exclusivamente a los tipos int y char. La palabra
clave register obliga al compilador de C a mantener el valor de las variables declaradas de esta manera
en un registro del microprocesador, en lugar de la memoria, que es donde habitualmente se almacenan
las variables. Esto hace que las operaciones sobre estas sean mucho más rápidas, ya que no se requiere
un acceso a memoria. Esta característica las hace ideales para el control de un bucle.
Este tipo de almacenamiento sólo puede aplicarse a variables locales, y a los parámetros
formales en una definición de función. No se permiten variables externas del tipo register.

4.18.2.- Operaciones a nivel de bits.

Se pueden dividir en tres tipos:


- El operador complemento a 1 ~.
- Los operadores lógicos a nivel de bits & ^ |.
- Operadores de desplazamiento de bits<< >>.

- El operador de complemento a uno ~ (alt+126) es un operador monario que invierto los bits de su
operando, por tanto los unos se transforman en ceros y los ceros en unos. Este operador precede
siempre a su operando. El operando tiene que ser un entero (incluido integer long, short, unsigned o
char). Generalmente el operando será un octal o una cantidad hexadecimal sin signo, pero no es
obligatorio. Ejemplo (para 16 bits):

Expresión: Valor:
~0xc5 0xff3a
~0x1111 0xeeee
~0xffff 0
~52 01777725
~0177777 0

En las constantes octales el primer dígito equivale a un solo bit.

Ejemplo de programa que muestra el complemento a uno de un número:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
{
char f;
int x,y=0x5b3c;
x=sizeof(int);
printf("\nel numero di bits para int es=%d",x);
printf("\nel numero HEXAD=%x COMP A UNO=%x\n",y,~y);

getchar();
return 0;

4-66
}

El resultado será y=0x5b3c ~y=0xffffa4c3

- Los operadores lógicos a nivel de bits y& o exc^ (alt+94) o | cada uno de estos operadores
requiere operandos. Las operaciones se realizan independientemente bit a bit.

b1 b2 b1&b2 b1^b2 b1|b2


1 1 1 0 1
1 0 0 1 1
0 1 0 1 1
0 0 0 0 0

Veamos unos ejemplos:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){

int a=0x5f,b=0xa7,c;
c=a&b;
printf("\nel resultado es=%x\n",c);

getchar( );
return 0;
}

Siendo el resultado 7 5f 0101 1111


a7 1000 0111
res a&b 0000 0111

podemos ver las tres operaciones a la vez:

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int a=0x5f,b=0xa7,c;
c=a&b;
printf("\nel resultado es=%x\n",c);
c=a^b;
printf("\nel resultado es=%x\n",c);
c=a|b;
printf("\nel resultado es=%x\n",c);
getchar();
return 0;
}

5f 0101 1111
a7 1000 0111
res a^b=d8 1101 1000

4-67
5f 0101 1111
a7 1000 0111
res a|b=df 1101 1111

Enmascaramiento: es un proceso en el que un patrón dado de bits convierten un dato en otro al


operarse con este patrón o máscara. Para recuperar la información original, el dato enmascarado debe
operarse de nuevo con dicho patrón o máscara. Veamos un ejemplo:

Máscara o patrón= 0x5a


Dato= 0xa9
Si cogemos un dato o conjunto de datos cualquiera y los operamos a nivel de bits (o exclusiva) con la
máscara, el dato o conjunto de estos, varían para hacerse irreconocibles. La única manera de obtener
los datos inicialmente será operando de nuevo estos datos con la máscara.

Veamos el proceso de enmascaramiento:

Dato 0xa9 1010 1001


Másc 0x5a 0101 1010
(op o exc) Dato resultante 0xf3 1111 0011

Para obtener el resultado original, debemos operar el dato resultante con la máscara (secreta)

Dato resultante 0xf3 1111 0011


Másc 0x5a 0101 1010
(op o exc)Dato original 0xa9 1010 1001

Ejercicio nº 1: Realiza como ejercicio un programa que solicite la escritura de una frase no mayor de
50caracteres, los encripte y los muestre en pantalla. Posteriormente los desencriptará y mostrará de
nuevo en pantalla la frase inicial. Usar como máscara 0xa7.

/*PROGRAMA QUE PIDE LA INTRODUCCIÓN DE UNA


FRASE Y LUEGO LA ENCRIPTA Y LA DESENCRIPTA*/

#include <ansi_c.h>

int main (void)


{
char frase[50],res[50],res2[50];
int cont;
printf("\nIntroduce una frase=");
gets(frase);

for(cont=0;cont<50;++cont){
res2[cont]=0;
res[cont]=0;
}
for(cont=0;cont<50;++cont){
if(frase[cont]==0)break;
res[cont]=frase[cont]^0xa7;
}

4-68
printf("\n\n La frase encriptada queda=%s",res);

for(cont=0;cont<50;++cont){
if(res[cont]==0)break;
res2[cont]=res[cont]^0xa7;
}

printf("\n\n La frase desencriptada queda=%s",res2);

printf("\n\nFIN DEL PROGRAMA");

getchar();
return(0);

Ejercicio nº 2: Realiza un programa que nos indique en pantalla con verdadero o falso si el bit nº 10 de
in registro int es uno -> verdadero o 0-> falso. Para ello el programa nos solicitará la entrada de un
número int (este número int, podría ser en realidad un registro de una tarjeta de adquisición de datos,
donde cada bit corresponde a una entrada digital 0-1). Utilizar para ello la operación lógica adecuada y
una máscara para dicho fin.

- Operadores de desplazamiento de bits<< >>

Los dos operadores de desplazamiento a nivel de bits son desplazamiento a la izquierda << y
desplazamiento a la derecha >> Cada operador requiere dos operandos. El primero es un operando de
tipo entero que representa el patrón de bits a desplazar, el segundo es un entero sin signo que indica el
número de desplazamientos (si los bits en el primer operando son desplazados en 1,2,3 bits, y así
sucesivamente). Este valor no puede exceder del número de bits asociado con el tamaño de palabra del
primer operando.
El operador de desplazamiento a la izquierda produce que los bits en el primer operando sean
desplazados a la izquierda el número de posiciones indicado por el segundo operando. Los bits de más
a la izquierda (los de desbordamiento) en el patrón original de bis se perderán. Las posiciones de la
derecha que quedan vacantes se rellenan con ceros.

Por ejemplo, supongamos que a es una variable entera sin signo cuyo valor es 0x6dbf. La expresión
b=a<<6;

int b,a=0x6dbf;
b=a<<6; //desplazará 6 posiciones los bits de la variable a y el número binario //restante
lo introducirá en b
//también se podría haber escrito de la forma a<<=6 equivale a a=a<<6

Comprobar:
a=0x6dbf -> 0110 1101 1011 1111
b=0x6fc0 -> 0110 1111 1100 0000 <- desplazamiento de 6 bits a la izquierda
#include <utility.h>
#include <ansi_c.h>
#include <cvirte.h>

4-69
int main (void){

int b,a=0xf;
b=a>>3; //probar b=a<<6;
printf("b=%x",b);
fflush(stdin);
getchar();
return 0;
}

4.19.- Estructuras y uniones.

Unas de las virtudes del C está en la facilidad para procesar datos complejos, siendo una
herramienta muy potente para ello, el formato de estructura.
Esta es una especie de superarray, que puede estar formado por distintos tipos de datos int,
char, float. También punteros, arrays y otras estructuras pueden ser incluidas como elementos dentro
de una estructura principal. Los elementos que conforma dicha estructura se denominan miembros.
Estrechamente relacionada con estas lo están las uniones, cuya diferencia estriba en que todos
los miembros de la unión tienen el mismo área de almacenamiento, independientemente del tipo que
sean.

4.19.1.- Definición de un estructura simple.

En la declaración de una estructura deben ser definidos todos sus miembros, veamos un
ejemplo:

#define TIT 40
#define AUT 30
#include <ansi_c.h>
#include <cvirte.h>
int main (void){
struct { /*definición de la estructura*/
char titulo[TIT];
char autor[AUT];
int precio;
}ficha;

printf(“\n Introduce el título del libro:”);


gets(ficha.titulo);
printf(“\n Introduce el nombre del autor:”);
gets(ficha.autor);
printf(“\n Introduce su precio:”);
scanf(“%d”,& ficha.precio);
printf(“\n\nDatos introducidos:”);
printf(“%s escrito por %s:%d Euros.\n”, ficha.titulo, ficha.autor, ficha.precio);
getchar();
return 0;
}

4-70
Vemos con este ejemplo que una vez definida la estructura ficha podemos acceder a todos sus
miembros anteponiendo al nombre de estos elementos, el nombre de la estructura, como por ejemplo:
ficha.precio o ficha.titulo.

Veamos cómo podemos crear 100 fichas de este modelo:

/*PROGRAMA QUE CREA 100 FICHAS PERO QUE ESCRIBE EN LA FICHA CERO
Y LEE LA FICHA CERO*/

#include <ansi_c.h>
#include <cvirte.h>
int main (void){
struct { /*definición de la estructura*/
char titulo[40];
char autor[30];
int precio;
}ficha[100];
printf("Introduzca título del libro:\n");
gets(ficha[0].titulo);
printf("Introduzca el nombre del autor:\n");
gets(ficha[0].autor);
printf("Introduzca ahora su precio:\n");
scanf("%d",&ficha[0].precio);
printf("\n\nDatos introducidos:");
printf("%s por %s:%d ptas.\n",ficha[0].titulo,ficha[0].autor,ficha[0].precio);

printf("\n\nFIN DEL PROGRAMA");


getchar();
return;
}

Crea a continuación un programa que presente un menú


1 Escribir una ficha (preguntará el número de ficha a escribir)
2 Leer una ficha (preguntará el número de la ficha a leer)
3 Salir

/* PROGRAMA QUE PRESENTA un menú:


1 Escribir una ficha (preguntará el número de ficha a escribir)
2 Leer una ficha (preguntará el número de la ficha a leer)
3 Salir*/
#include <ansi_c.h>
#include <cvirte.h>
int main (void){
int elec, n;
struct { //definición de la estructura
char titulo[40];
char autor[30];
int precio;
}ficha[100];
do{
printf("\n\n\n1 Escribir una ficha\n2 Leer una ficha\n3 Salir\n\nOPCION=");
scanf("%d",&elec);
switch(elec){
case 1:
printf("\nN Ficha a escribir=");
scanf("%d",&n);
getchar();//while(getchar()!='\n') //fflush(stdin);//para que no salte la línea

4-71
printf("Introduzca título del libro:");
gets(ficha[n].titulo);
printf("Introduzca el nombre del autor:");
gets(ficha[n].autor);
printf("Introduzca ahora su precio:");
scanf("%d",&ficha[n].precio);
break;
case 2:
printf("\nN Ficha a leer=");
scanf("%d",&n);
printf("\n\nTitulo:%s\nAutor:%s\nPrecio:%d",
ficha[n].titulo,ficha[n].autor,ficha[n].precio);
break;
case 3:
break;
default:
printf("\nELIGE CORRECTAMENTE POR FAVOR");
}
}while(elec!=3);
printf("\n\nFIN DEL PROGRAMA");
fflush (stdin);
getchar();
return;
}

OTRA FORMA DE RESOLVERLO:


/* PROGRAMA QUE PRESENTA un menú:
1 Escribir una ficha (preguntará el número de ficha a escribir)
2 Leer una ficha (preguntará el número de la ficha a leer)
3 Salir
*/
#define TIT 40
#define AUT 30
#include <utility.h>
#include <ansi_c.h>
#include <cvirte.h>

int main (void){


struct { //definición de la estructura
char titulo[TIT];
char autor[AUT];
int precio;
}ficha[100];
int cont,opcion;
do{
Cls(); //BORRADO DE PANTALLA
printf("\n1 Escribir una ficha");
printf("\n2 Consultar una ficha");
printf("\n3 Salir");
printf("\n\n Opcion=");
scanf("%d",&opcion);
switch(opcion){

case 1:
printf("n de ficha a escribir(0-99)=");
scanf("%d",&cont);
fflush(stdin);
printf("\n Introduzca t\xa1tulo del libro:");// \xa1 es el código ASCII de í
gets(ficha[cont].titulo);
printf("\n Introduzca el nombre del autor:");
gets(ficha[cont].autor);
printf("\n Introduzca ahora su precio:");
scanf("%d",& ficha[cont].precio);
printf("\n\n Datos introducidos:");
break;

case 2:

4-72
printf("n de ficha a consultar(0-99)=");
scanf("%d",&cont);
printf("\nTitulo:%s \n Autor:%s \n precio=%d euros.\n", ficha[cont].titulo, ficha[cont].autor,
ficha[cont].precio);
fflush(stdin);
getchar();
break;

case 3:
exit(0);

default:
printf("\n\nELIGE CORRECTAMENTE");
fflush(stdin);
getchar();
}
}while(1);
}

4-73
Hemos definido en el ejemplo anterior una estructura denominada ficha Podemos declarar otras
estructuras (podemos denominarlas también variables de estructuras)con idénticos miembros, de la
siguiente forma:

struct ficha { /*definición de la estructura*/


char titulo[TIT];
char autor[AUT];
int precio;
}libro_inf,libro_lit,lib_elec;

También se podría haber escrito de la siguiente forma:

struct ficha{ /*definición de la estructura*/


char titulo[TIT];
char autor[AUT];
int precio;
};
struct ficha lib_inf,lib_lit,lib_elc; //variables de
estructuras tipo libro.

Tendremos en este caso una estructuras patrón


denominada libro y tres variables iguales (con los
mismos miembros) denominadas:

1ª lib_inf
2ª lib_lit
3ª lib_elec
Podremos de igual forma acceder a un miembro de cualquiera de ellas, por ejemplo:
libros.titulo
lib_inf.titulo
lib_elec.precio
(serán todas ellas variables distintas)

También se podría haber declarado estas estructuras, sin haber utilizado una estructura patrón, de la
siguiente forma:

struct{ /*definición de la estructura*/


char titulo[TIT];
char autor[AUT];
int precio;
}lib_inf,lib_lit,lib_elc;/*definición de 3 variables estructura*/

Tal vez, la forma más elegante de crear multiples estructuras iguales es crear un patrón o tabla
modelo, y haciendo referencia a esta tabla, todas las estructuras semejantes que necesitemos, veamos
un ejemplo:

struct ficha{ /*definición de la estructura patrón*/

4-74
char titulo[40];
char autor[30];
int precio;
};
struct ficha libros_tec,lib_elec,lib_lit,lib_inf; /*definición de las variables del tipo estructuras*/
...etc

4.19.2.- Definición de una estructura compleja.

Supongamos que queremos una estructura según la figura:

Esta figura correspondería a una estructura compleja, la forma de programarla será bastante intuitiva,
vistos los apartados anteriores:

struct fecha{ //declaración de una 1ª estructura patrón.


int mes;
int dia;
int anno;
};

struct libros { //declaración de una 2ª estructura patrón.


char titulo[40];
char autor[30];
int precio;
struct fecha fecha_ent,fecha_sal; //declaración de 2 variables de tipo estructura fecha.
};

struct libros
l
ibros_tec,libros_fil,libros_elec;
//declaración de 2 variables de tipo
estructura libros.

4-75
4.19.3- Array de estructuras.

Vamos a definir un array de 50 estructuras simples:

struct tabla{ //definición de una estructura patrón.


int mes;
int dia;
int anno;
};
struct tabla FechaAltas[50];

Donde FechaAltas[50] es un array de cincuenta estructuras tipo tabla.

4-76
4.20.- Archivos.

/*********************************************************************************
PROGRAMA QUE ALMACENA FICHAS EN UN ARCHIVO Y LAS RECUPERA
PRESENTA UN MENÚ PARA ESCRIBIR O LEER FICHAS, Y PARA SALVAR LA INFORMACIÓN EN
UN ARCHIVO O LEER LA INFORMACIÓN DESDE UN ARCHIVO
*********************************************************************************/
#include <utility.h>
#include <ansi_c.h>
#include <cvirte.h>

char nombre[10];

struct { /*definición de la estructura*/


char titulo[40];
char autor[30];
int precio;
}ficha[100];

void salvar(void)
{
FILE *punt;
char c, nombre[13];
Cls();
puts("Nombre del archivo donde guardar la informaci\xa2n:");
scanf("%s",nombre);
punt=fopen(nombre,"w");
if (punt==0)puts("Error no se ha podido abrir");
fwrite(&ficha,76,100,punt);
fclose(punt);
return;
}

void leer(void)
{
FILE *punt;
Cls();
puts("Nombre del archivo a leer:");
scanf("%s",nombre);
punt=fopen(nombre,"r");
if (punt==0)puts("Error no se ha podido abrir");
fread(&ficha,76,100,punt);

fclose(punt);
return;
}

int main (void){

int elec, n;
printf("Tamaño de la ficha=%d",sizeof(ficha));
getchar();
do{
printf("\n\n\n1 Escribir una ficha\n2 Leer una ficha\n3 Salvar informaci\xa2n en archivo\n4
Leer fichas de archivo\n5 Salir\n\nOPCION=");
scanf("%d",&elec);
switch(elec){
case 1:

4-77
printf("\nN Ficha a escribir=");
scanf("%d",&n);
getchar();//while(getchar()!='\n') //fflush(stdin);//para que no salte la línea
printf("Introduzca t\xa1tulo del libro:");
gets(ficha[n].titulo);
printf("Introduzca el nombre del autor:");
gets(ficha[n].autor);
printf("Introduzca ahora su precio:");
scanf("%d",&ficha[n].precio);
break;
case 2:
printf("\nN Ficha a leer=");
scanf("%d",&n);
printf("\n\nTitulo: %s\nAutor: %s\nPrecio: %d", ficha[n].titulo, ficha[n].autor, ficha[n].precio);
break;
case 3:
salvar();
break;

case 4:
leer();
break;

case 5:
break;

default:
printf("\nELIGE CORRECTAMENTE POR FAVOR");
}
}while(elec!=5);

printf("\n\nFIN DEL PROGRAMA");


fflush (stdin);

getchar();
return;
}

/*********************************************************************************
PROGRAMA QUE CREA UN ARRAY DE 100 NÚMEROS FLOAT DONDE PODEMOS INTRODUCIR
VALORES, LEERLOS
SALVARLOS EN UN ARCHIVO Y RECUPERARLOS
*********************************************************************************/
#include <utility.h>
#include <ansi_c.h>
#include <cvirte.h>

int tamanno=100;

float numeros[100];

void salvar(void)
{
FILE *punt;
char c, nombre[13];
int cont;
Cls();
puts("?Nombre del archivo");
scanf("%s",nombre);

4-78
punt=fopen(nombre,"w+");
if (punt==0)puts("Error no se ha podido abrir");
/* TAMBIEN SE PUEDE REALIZAR DE ESTA MANERA
for(cont=0;cont<tamanno;++cont)
fwrite(numeros+cont,sizeof(float),1,punt); //fwrite(&numeros[cont],sizeof(float),1,punt);
*/
fwrite(numeros,sizeof(float),tamanno,punt);

fclose(punt);
return;
}

void leer(void)
{
FILE *punt;
int cont;
char c, nombre[13];
Cls();
puts("?Nombre del archivo a leer");
scanf("%s",nombre);
punt=fopen(nombre,"r");
if (punt==0)puts("Error no se ha podido abrir");
/* TAMBIEN SE PUEDE REALIZAR DE ESTA MANERA
for(cont=0;cont<tamanno;++cont)
fread(numeros+cont,sizeof(float),1,punt);
//fread(&numeros[cont],sizeof(float),1,punt);
*/
fread(numeros,sizeof(float),tamanno,punt);
fclose(punt);
return;
}

int main (void){

int elec, n,tamanno;

//printf("INTRODUCE EL TAMA\xa5O DEL ARRAY DE N\xe9MEROS FLOAT=");


//scanf("%d",&tamanno);
//pf=malloc(sizeof(float)*tamanno);
do{
printf("\n\n\n1 Introducir n\xa3meros float\n2 Leer n\xa3meros float\n3 Salvar
informaci\xa2n en archivo\n4 Leer informaci\xa2n de archivo\n5 Salir\n\nOPCION=");
scanf("%d",&elec);
switch(elec){
case 1:
printf("\nN de registro a escribir=");
scanf("%d",&n);
getchar();//while(getchar()!='\n') //fflush(stdin);//para que no salte la línea
printf("\nN\xa3mero=:");
scanf("%f",numeros+n); // scanf("%f",numeros[n]);
break;
case 2:
printf("\nN de registro a leer=");
scanf("%d",&n);
printf("\nN\xa3mero=%f",*(numeros+n));
//printf("\nN\xa3mero=%f",numeros[n]))
break;

4-79
case 3:
salvar();
break;

case 4:
leer();
break;

case 5:
break;

default:
printf("\nELIGE CORRECTAMENTE POR FAVOR");
}
}while(elec!=5);

printf("\n\nFIN DEL PROGRAMA");


fflush (stdin);

getchar();
return;
}

4-80
4.21.- Ejercicios.

4.21.1.- Realiza un programa realiza la tabla de multiplicar 0-10 de cualquier numero inferior o igual a
3276.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int numero=0,contador=0,total=0;
printf("Introduce un número (MAX=3276) n=");
scanf("%d",&numero);
printf("TABLA DE MULTIPLICAR DEL %d\n\n\n", numero);
while (contador<11){
total=contador*numero;
printf("%d",numero);
printf(" * ");
printf("%d",contador);
printf(" = ");
printf("%d\n",total);
contador++;
}
getchar();
return 0;

4.21.2.- Escribir un programa que solicite una entrada de un número menor de 1000 y calcule la raíz
cuadrada de dicho número, en caso contrario dará un mensaje de error y pedirá de nuevo la
introducción del número.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
float a;
char r;
etiqueta_1:
printf("escribe un nº positivo menor de 1000\n\n\t");
scanf("%f",&a);
while(a>0) {
if(a<1000) {
a=sqrt(a);
printf("\n\n\t la raíz es=%.2f",a);
break;
}
else {
printf("numero incorrecto pulsa intro para continuar");
getchar();
break;
}
}
while (a<0) {
printf("numero incorrecto pulsa intro para continuar");
getchar();
break;
}
printf("\n\n\t ¿quieres continuar \"s\" o \"n\"\n\n\t ");

4-81
getchar();
r=getchar();
if (r=='s') goto etiqueta_1;
printf("fin");
getchar();
return 0;
}

4.21.3.- Escribir un programa de tres maneras distintas que simplemente imprima los números del 1 al
99 en pantalla.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int t;
for(t=1;t<100;++t) {
printf("%d ",t);
delay(100);
}
getchar();
return 0;

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int t=1;
while(t<100) printf("%d ",t++);
getchar();
return 0;

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int t=1;
do {
printf("%d ",t++);
} while(t<100);
getchar();
return 0;

4.21.4.- Programa que solicita una entrada de días,horas minutos y segundos separados por comas y
los convierte en segundos.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
long dias,horas,minutos,segundos,seg;
int n; /*número de datos introducidos*/
const int segminuto = 60,minhora = 60,horasdia = 24;
const long seghora = segminuto*minhora; /*constantes calculadas*/
const long segdia = seghora*horasdia;

4-82
printf("\n Conversión de unidades de tiempo a segundos:\n\n");
printf("Días, horas, minutos, segundos: "); /*mensaje*/
n = scanf("%ld,%ld,%ld,%ld",
&dias,&horas,&minutos,&segundos); /*entrada de datos*/

if (n < 4) { /*controla los datos*/


printf("\n- Ha introducido sólo %d" /*de entrada*/
" de los 4 datos requeridos.\n",n);
} else { /*todo correcto*/
seg = segundos; /*empieza por segundos*/
seg += (minutos*segminuto); /*añade los minutos*/
seg += (horas*seghora); /*las horas*/
seg += (dias*segdia); /*y los días*/

printf("\n%ld días, %ld horas, %ld minutos"


" y %ld segundos = %ld segundos\n",
dias,horas,minutos,segundos,seg);
}
getchar();
return 0;

4.21.5.- Crea un programa que pida una cadena de caracteres (una palabra o nombre) y que lo imprima
al contrario utilizar la función de librería "strlen(nombre_cadena)".
#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int t;
char s[80];

printf("escribe una cadena


de caracteres\n\n");
gets(s);
putchar('\n');
for(t=strlen(s);t;t--)
putchar(s[t-1]);
getchar();
return 0;

}
4.21.6.- Escribe un programa en "C" que solicite la introducción de diez números (enteros base 10). A
continuación los mostrará en una línea como comprobación y dará la media aritmética y el valor
máximo de ellos.
Se utilizará para almacenar estos números un array denominado "valor[10]" de tipo int.
Los números podrán ser introducidos escribiéndolos con espacios en blanco entre ellos o
pulsando "enter" a continuación de cada número (utilizar para ello un bucle for).

#define NUM 10
#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int i,suma,media,max,valor[NUM];

4-83
printf("Introducir 10 nº enteros separados por esp. en blanco\n");
printf("o pulsando \"enter\"\n");
for(i=0;i<NUM;i++)
scanf("%d",&valor[i]); /*lee los diez numeros*/
printf("los diez nº son:\n");
for(i=0;i<NUM;i++)
printf("%6d",valor[i]); /*comprueba la entrada*/
for(i=0,suma=0;i<NUM;i++)
suma +=valor[i];
media=suma/NUM;
printf("\n\n La media aritmética es:%d",media);
for(max=valor[i],i=1;i<NUM;i++) /*comprueba el valor máximo*/
if(valor[i]>max)
max=valor[i];
printf("\n\n el valor máximo es:%d",max);
getchar();
return 0;

4.21.7.- Escribir una función denominada max(x,y) que devuelve el mayor valor de sus dos
argumentos formales enteros (la función acepta dos números enteros y devuelve un valor entero).

int max(int x,int y)


{
if(x>y) return(x);
else return(y);
}

4.21.8.- Realizar un programa que pida introducir 10 números separados por un espacio en blanco o
pulsando "enter" (introducirlos en un array) y utilizando la función creada denominada max(x,y) que
devuelve el mayor valor de sus dos argumentos formales enteros, escribir el mayor de ellos.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int i,m,numeros[10]; //declaración de variables a utilizar.
int max(int x,int y); //declaración de función a utilizar.
printf("introduce diez números separados por espacios en blanco\n");
printf("o pulsando\"enter\", y te diré cual es el mayor\n");
for(i=0;i<10;i++)
scanf("%d",&numeros[i]);
printf("los diez números son:\n");
for(i=0;i<10;i++)
printf("%8d",numeros[i]);
for(i=1;i<10;++i)
m=max(numeros[0],numeros[i]);
printf("\n\nel número mayor es: %d",m);
printf("\nfin...pulsa una tecla\a");
getchar();
return 0;
}

int max(int x,int y)


{

4-84
if(x>y) return(x);
else return(y);
}

4.21.9.- Escribe un programa que solicite la introducción del nombre, dirección y teléfono, y los
muestre a continuación entre dos líneas de asteriscos, utilizar para ello una función denominada
"asteriscos()" que escriba 65 asteriscos.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
char n[30],d[30],t[10]; //declaración de variables a utilizar.
void asteriscos(); //declaración de función a utilizar. Si la función se sitúa antes de
//main() no es necesario declararla
printf("introduce tu nombre\n");
gets(n);
printf("\n introduce tu dirección\n");
gets(d);
printf("\n introduce tu teléfono\n");
gets(t);
asteriscos(); //llamada a la función.
puts(n);
puts(d);
puts(t);
asteriscos();
getchar();
return 0;
}

void asteriscos(void)
{
int cont;
for(cont=1;cont<=65;cont++)
putchar('*');
putchar('\n');
return;
}

4.21.10.- Escribe, al igual que el problema anterior, un programa que solicite la introducción del
nombre, dirección, teléfono y nº de asteriscos, y los muestre a continuación entre dos líneas de
asteriscos, utilizar para ello una función denominada asteriscos(n) que escriba en pantalla un número
n de asteriscos.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
char n[30],d[30],t[10]; //declaración de variables a utilizar.
int n; //declaración de variable a utilizar.
void asteriscos(int n); //declaración de función a utilizar.

printf("introduce tu nombre\n");
gets(n);
printf("\n introduce tu dirección\n");
gets(d);
printf("\n introduce tu teléfono\n");

4-85
gets(t);
printf(“\n introduce el nº de asteriscos a escribir en la línea\n”);
scanf(“%d”,&n);

asteriscos(n); //llamada a la función.


puts(n);
puts(d);
puts(t);
asteriscos(n); //llamada a la función.
getchar();
return 0;
}

void asteriscos(int n)
{
int cont;
for(cont=0;cont<n;cont++)
putchar('*');
putchar('\n');
return;
}

4.21.11.- Escribir una función recursiva denominada "print_num() que tenga un argumento entero.
Imprimirá en la pantalla los números del 1 al "n", en donde "n" es el valor de argumento.

print_num(int n){
if(n==1) printf("%d",n);
else {
printf ("%d",n);
print_num(n-1);
}
return;
}

4.21.12.- Escribe un programa de conversión de binómica a polar y de polar a binómico. El programa


pedirá qué tipo de coversión. A continuación pedirá el módulo y argumento o bien la parte real e
imaginaria dependiendo de la elección. Estas dos conversiones deberán realizarse mediante dos
funciones denominadas: conv_p_b() y conv_b_p().
Seguidamente deberá mostrarse el valor convertido de una manera "legible" (presentación
forma binómica ---> 34.45+26.08j presentación en forma polar ----> -98[-23º).
Resaltar que las funciones trigonométricas manejan valores en radianes.
Por último preguntará si se quiere continuar o no, volviendo al principio del programa en caso
afirmativo.
CONDICIONES:
a) No se utilizará "goto" en ninguna parte del programa.
b) En caso de no responder correctamente en cualquier parte del programa, este nos lo indicará y
pedirá de nuevo los valores.
c) Se podrá escribir directamente en forma polar o en forma binómica.

#define PI 3.1415
#include <ansi_c.h>

4-86
#include <cvirte.h>
float r,i,m,a;
int main (int argc, char *argv[]){ void conv_p_b(float x,float y);
void conv_b_p(float w,float z);
float x,y,w,z;
char c;
do{

do{
puts("\t\t--- PROGRAMA DE CONVERSIÓN ----");
puts("\n\t1 Polar a Binómica");
puts("\n\t2 Binómica a Polar");
printf("\n\n\t\t\tPulsa 1 ó 2 opción=");
c=getchar();
if(c=='1'||c=='2')break;
puts("\a\nERROR SELECCIONE CORRECTAMENTE");
getchar();
}while(c!='1'||c!='2');
switch(c){
case '1':
printf("Módulo=");
scanf("%f",&x);
printf("\nArgumento=");
scanf("%f",&y);
conv_p_b(x,y);
printf("\n-------->%.2f%+.2fj",r,i);
break;
case '2':
printf("Parte real=");
scanf("%f",&w);
printf("\nParte imaginaria=");
scanf("%f",&z);
conv_b_p(w,z);
printf("\n--------->%.2f[%.2fº",m,a);
break;
default:
puts("\n\aELIGE CORRECTAMENTE");
break;
}
do{
printf("\n¿Quieres continuar? pulsa \"s\" o \"n\"");
c=getchar();
if(c=='n')break;
if(c!='s'){
puts("\a\nERROR ELIGE CORRECTAMENTE pulsa intro");
getchar();
}
}while(c!='s');
}while(c=='s');
puts("\n\a\t\t FIN");
getchar();
return 0;
}

void conv_p_b(float x,float y)


{
y=(y*2*PI)/360;
r=x*cos(y);
i=x*sin(y);
}

4-87
void conv_b_p(float w,float z)
{
m=sqrt((w*w)+(z*z));
a=((atan(z/w))*360)/(2*PI);
}

4.21.13.- Escribe un programa en el podamos introducir los números con decimales (float) que
queramos hasta 100 como límite y nos calcule la suma de ellos la media aritmética y el menor de ellos.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int n,cont;
float menor,suma=0;
float lista[100];

printf("¿cuantos números para calcular la media?");


scanf("%d",&n);
for(cont=0;cont<n;++cont){
printf("\n n%dº=",cont+1);
scanf("%f",&lista[cont]);
suma+=lista[cont];
printf("suma=%f",suma);
}

for(cont=0,menor=lista[cont];cont<n;cont++)
if(lista[cont]<menor)
menor=valor[cont];
printf("\nEl menor de estos números es %f",menor);
getchar();
return 0;
}

4.21.14.- Escribe un programa en el podamos introducir los números con decimales (float) que
queramos hasta 100 como límite y nos calcule mediante tres funciones denominadas suma(),
madia_arit() y menor(), la suma de ellos la media aritmética y el menor de ellos.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int n,cont;
float menor,suma=0;
float lista[100];
float suma();
float media_arit();
float menor();

printf("¿cuantos números para calcular la media?");


scanf("%d",&n);
for(cont=0;cont<n;++cont){
printf("\n n%dº=",cont+1);
scanf("%f",&lista[cont]);
suma+=lista[cont];
printf("suma=%f",suma);
}

printf(“\n\nLa suma de todos ellos es:%.4f”,suma(n,lista));

4-88
printf(“\n\nLa media aritmética es:%.4f”.media_arit(n,lista));
printf(“\n\nEl menor de ellos es:%.4f”,menor(n,lista));
getchar();
return 0;
}

float suma(int n,float lista[100])


{
int cont;
float acumulado;
for(cont=0;cont<n;++cont)acumulado+=lista[cont];
return(acumulado);
}

float media_arit(int n,float lista[100])


{
int cont;
float acumulado;
for(cont=0;cont<n;++cont)acumulado+=lista[cont];
return(acumulado/n);
}

float menor(int n,float lista[100])


{
int cont;
float minimo;
for(cont=0,minimo=lista[cont];cont<n;cont++)
if(lista[cont]<minimo)
minimo=valor[cont];
return(minimo);
}

4.21.15.- Realiza un programa que sea capaz de sumar dos arrays de tres números enteros definidos en
la misma declaración de los arrays y mostrarlos en pantalla.

#include <ansi_c.h>
#include <cvirte.h>
int main (int argc, char *argv[]){
int n,c[3];
int a[3]={7,14,32};
int b[3]={14,4,100};

for(n=0;n<3;++n) c[n]=a[n]+b[n];
for(n=0;n<3;++n) printf("c[%d]=%d\n",n,c[n]);
getchar();
return 0;
}

4.21.16.- Realiza un programa que cree una array de numeros enteros de 3 filas por 4 columnas y pida
la introducción de los mismos mostrando en pantalla cada elemento donde se van a introducir el
número y al final muestre en pantalla la matriz completa.

#include <ansi_c.h>
#include <cvirte.h>

4-89
int main (int argc, char *argv[]){
int num[3][4],n,m;

for(n=0;n<3;++n)
for(m=0;m<4;++m){
printf("escribe el número que quieres introducir en:\n");
printf("num[%d][%d]=",n,m);
scanf("%d",&num[n][m]);

printf("El array completo es:\n\n");


for(n=0;n<3;++n){
for(m=0;m<4;++m)
printf("num[%d][%d]=%d ",n,m,num[n][m]);
printf("\n");
}
getchar();
return 0;
}

4-90

Potrebbero piacerti anche