Вы находитесь на странице: 1из 49

Una breve

introduccin

Por qu C?
- C es el idioma natal de Unix.
- C es portable Un cdigo escrito en
una mquina se puede usar en otra.
- C es un lenguaje breve Tiene un
conjunto de operadores poderoso y
eficientes.
- C es la base de C++ y Java.
- C por supuesto que tiene sus bemoles.

Aspectos Bsicos de C
/* Maraton en kilometros */
#include <stdio.h>
main( )
{
int miles, yards;
float kms;
miles = 26;
yards=385;
kms = 1.609*(miles+yards/1760.0);
printf(un maraton tiene %f
kilometros\n,kms);
}

Detalles del programa


/* Comentarios */

#include <stdio.h>
Incluye una copia del archivo stdio.h en este punto del
cdigo. Este archivo lo provee el sistema C. Se
incluye este archivo porque contiene informacin de la
funcin printf( ) Otro archivo de este tipo es:
<math.h>
main()
Es la funcin donde se escribe el programa principal.
La ejecucin de un programa siempre empieza con
esta funcin.
{
Con los parntesis curvos inicia una funcin y se
termina. Tambin delimita expresiones.
int miles, yardas;
Declaracin de variables. int es una palabra-clave
(palabras reservadas), tienen significado especial para
el compilador, le dicen que miles y yards son enteros.

float kms;
Es una declaracin. float es una palabra-clave (palabras que
no pueden usarse como nombres de variables, hay 32 en C).
Le dice al compilador que las variables que le siguen son
nmeros reales.
miles=26;
yards=385;
Son expresiones de asignacin. El signo = es un operador de
asignacin. Los nmeros 26 y 385 son enteros constantes.
kms = 1.609*(miles + yards/1760.0);
Es una expresin de asignacin. Los operadores *, +, /, se
refieren a la multiplicacin, suma y divisin.
printf(un maraton tiene %f kilometros\n, kms);
Es una expresin que llama a la funcin printf(). Entre comillas
est la cuerda de control. Dentro de la cuerda est la
especificacin de conversin o formato %f , ah se colocar un
numero real: kms.

Divisin de enteros resulta en enteros y el


residuo se desecha. As que 9/2 tiene un
valor entero de 4. La expresin 9.0/2 es un
real dividido por un entero y al evaluarse se
convierte en un real cuyo valor ser 4.5
kms = 1.609*(miles + yards/1760);
bug pues yards (385) es de tipo entero
dividido por otro entero, lo cual dara por
resultado 0.
kms=1.609*(miles + yards/1760.0);

printf() y scanf()
input and output. Estas funciones son parte del sistema
C existen en una librera y estn disponibles
dondequiera que se encuentre un sistema C. Los
prototipos de estas funciones estn en stdio.h
Argumentos: cuerda de control y otros argumentos
Para imprimir letras sobre la pantalla
printf(abc);

printf(%s,abc);

printf(%c%c%c,a,b,c);

printf(Introduzca los valores de A, w, y B\n);


scanf(%f %f %d,&a,&w,&b);
printf(Ud. Introdujo A= %e, w= %f, y B=
%d\n,a,w,b);
Pantalla:
Introduzca los valores de A, w, y B
0.0245 1.235 35
Ud. Introdujo A= 2.45e-02, w= 1.235 y B=
35

Conversiones de printf() y scanf()


c
d
f
lf o LF
s

como carcter
como entero
como nmero con punto decimal
como nmero doble precisin
como cuerda

Conversiones slo de printf()


e
g

como nmero real en notacin cientfica


en el formato e o f, el que sea mas corto

Flujos de Control
Sirven para alterar el flujo secuencial normal en
un programa.

if y if-else proveen acciones alternativas.


while y for proveen mecanismos de ciclos.
Estos requieren la evaluacin de expresiones
lgicas que pueden ser falsas o verdaderas.
if( expresin)
operacin

if (expr)
accin
else
accin
while(expr)
accin
for(exp1;expr2;expr3)
accin
expr1;
while(expr2){
accin
expr3;
}

/* calcula el maximo el minimo y el promedio */


#include <stdio.h>
#include <stdlib.h>
main()
{
int i;
double x, min, max, sum, avg;
if( scanf(%lf,&x) != 1) {
printf(no se encontraron datos\n);
exit(1);
}
min = max = sum = avg = x;
for( i=2; scanf(%lf,&x) == 1; i += 1) {
if( x < min)
min = x;
else if( (x > max)
max = x;
sum += x;
avg = sum/i;
}
printf(min = %3.5f, min= %3.5f, avg = %3.5f\n,min, max, avg);
}

if( scanf(%lf,&x) != 1) {
printf(no se encontraron datos\n);
exit(1);
}
lf long float, es equivalente a double. Almacena lo que lee en la direccin de
x, (&x se lee como la direccin de x & es el operador direccion). La
funcin scanf regresa un valor int (entero) que es el nmero de
conversiones exitosas que realiza. Si no lee nada, imprime, se imprime un
mensaje y sale del programa con la funcin exit() (esta en stdlib.h), que
toma un solo argumento tipo int, se le da un entero diferente de cero si la
salida no se considera normal.
min = max = sum = avg = x;
for( i=2; scanf(%lf,&x) == 1; i += 1)
Se inicializa la variable i con el valor 2. luego se hace una prueba para ver si
la expresin lgica scanf(%lf,&x) == 1 es verdadera. Si scanf() puede leer
caracteres de la corriente de entrada standard, lo interpreta como un
double y coloca ese valor en la direccin de x, se ha hecho una conversin
exitosa y y scanf() regresa el valor 1. == es el operador igual a el entero
que regresa scanf() es igual a 1? (Error comn es usar = en vez de ==). Si
si lo es, el ciclo se repite.
variable OP= expresin
donde OP puede ser +, -, *, o / es equivalente a
variable = variable OP (expresin)
En este caso i += 1 es i = i + 1

if( x < min)


min = x;
else if ( x > max)
max = x;
Esta construccin es un if-else: La accin despus del else
es un un condicional if. Aqu el min y max se actualizan con
cada lectura de los datos.
Se puede crear un archivo de datos, por ejemplo datos,
compliamos el programa con la instruccin:
cc o promedio promedio.c
y se crea el ejecutable promedio. Ahora se da el comando
promedio < datos
con esto la entrada se redirecciona hacia el programa
promedio

Operadores de incremento y
decremento
Son operadores usables como pre-fijos o post-fijos. Si val
es una variable de tipo int, entonces ++val y val++ son
expresiones vlidas.
Se aplican a variables, no a constantes o a expresiones
ordinarias:
++i
a-Vlido
367++
++(a*b+1)
Invlido
Cada expresin: ++i, i++ tiene un valor y adems, cada
una, causa que se le incremente el valor de i por 1.
++i : aumenta el valor de i por 1,
y toma ese valor aumentado para la expresin

i++: esta expresin primero toma como valor de i, y luego


lo aumenta por 1.
int a, b, c=0;
a = ++c;
b = c++;
printf(%d %d %d\n, a, b, ++c);
/*** 1 1 3 se imprime en la pantalla ***/
El operador - disminuye el valor de i.
Ejercicio: Qu cree se imprimir con
int a, b=0, c=0;
a = ++b + c++;
printf(%d %d %d\n,a,b,c);
a= b++ + --c;
printf(%d %d %d\n,a,b,c);

Operador Modulo %
a % b da el residuo de dividir a entre b. As que, por
ejemplo 10%3 tiene el valor 1.
Qu hace la siguiente seccin de programa ?
for( i=1; i<=50 ; i++){
if( i%5 == 0) printf(\n);
printf(a[%d]= %f ,i,a[i]);
}
Operadores
Operadores
Operadores

Lgicos: && y, || o, ! negacin


de Igualdad: == igual a, != no igual a
relacionales: < , <=, >, >=

Operador Condicional ? :
Toma tres expresiones, su forma general es:
expr1 ? expr2 : expr3
Primero se evalua expr1, si es verdadera, se evalua expr2 y
ese es el valor de la expresin condicional como un todo. Si
expr1 es falsa, se evala expr3 y ese el es valor de toda la
expresin condicional
if(y < z)
x=y;
else
x=z;
As se asigna a x el mnimo entre y & z. Es equivalente a
x= (y<z) ? y : z
El tipo de la expresin total lo determina expr2 & expr3.

Arreglos, Cuerdas y Apuntadores


Arreglos 1-dimensionales. Datos que tienen un
ndice. El ndice en C empieza en 0.
#define N 10
float a[N];
Aparta espacio para a[0], a[1],,a[9] diez
elementos. Es una buena practica definir el
tamao del arreglo como una constante simblica.
Sobrepasar el tamao de un arreglo es un error
comn al programar.

Inicializacin:
float f[5] = {0.0, 1.0, 2.0, 3.0, 4.0};
int a[10] = {0};
Ejemplo del uso de arreglos:
#include <stdio.h>
#define N 5
main()
{
int i, j, score[N]= {99, 87, 85, 94,70}, sum;
for(sum=0, i=0;i<N; ++i)
sum += score[i];
printf(%5.2f es el promedio\n,(double) sum/N);

(double) sum/N;
usa un operador cast cuyo efecto es convertir el valor int
de sum a un valor double. Este operador cast se realiza
primero antes que la divisin, as que tendramos una
divisin entre un un double y un entero, lo cual nos da un
double. Sin este cast la fraccin se descartara, y el el
printf, por el formato, marcara un error.
POINTER (Apuntadores). Una variable se almacena con un
cierto nmero de bytes en una localizacin particular
(direccin) de memoria en una mquina. Los apuntadores
se usan para accesar memoria y manipular direcciones.
Un apuntador es la direccin de un objeto en memoria.
Si p es un apuntador, el valor directo de p es una
localizacin en memoria o direccin.

ILUSTRACION:
int a=1, b=2, *p;
Las variables a,b,p estn almacenadas e memoria como:
a

b
1

p
2

Pensamos en p como una flecha. Pero como no se le ha


asignado un valor no sabemos a que apunta. Si escribimos
p= &a;
Esto lo leemos como a p se le asigna la direccin de a y el
diagrama sera:

Diagrama nuevo:
a
1

Ahora hacemos la asignacin: b= *p;


Que se lee a la variable b se le asigna el valor a que apunta
p, y como p apunta hacia a,
b = *p; es equivalente a b = a;
Un programa que ilustra la distincin p = &a, y b =*p es:

#include <stdio.h>
main()
{
int i = 7, *p ; /* variable p de tipo entero */
p = &i;
/* p apunta a la direccin de i */
printf(%s%d\n%s%p\n, Valor de i :, *p,
Localizacion de i: , p);
}
Lo que se lee en la pantalla es:
Valor de i : 7
Localizacin de i : effffb24
La variable i debe declararse antes detomar su direccin.
%p es el formato preferido para el valor de un apuntador

Relacin entre arreglos y apuntadores


El nombre de una arreglo por s mismo es una direccin. Pero a
diferencia de un apuntador que puede asignrsele diferentes
direcciones como valores, un arreglo es una direccin (o
apuntador) que es fijo.
Cuando se declara un arreglo, el compilador da espacio contiguo
en la memoria para contener todos lo elementos de arreglo. La
direccin base del arreglo es la direccin del primer elemento a[0].
int a[10], i, *p, sum;
p = a; /* equivale a p = &a[0] */
p = a +1; /* equivale a p = &a[1] */
Si los elementos a[i] ya tienen valores, podemos sumar sus
valores con
for( sum=0,p=a; p< &a[10]; ++p)
sum += *p;

Funciones
La parte de un cdigo que describe lo que hace una funcin
se llama definicin de la funcin No debe confundirse con la
declaracin de la funcin (las funciones tambin se
declaran antes de usarse).
tipo nombre(lista de parametros) {
declaraciones
acciones
}
El tipo, nombre y lista de parmetros constituyen cabezal
de la funcin.
{ cuerpo de la definicin de la funcin}

int factorial( int n)


{
int i, product= 1;
for( i=2; i<= n; ++i)
product *= i;
return product;
}

/* cabezal */
/* empieza el cuerpo */

El primer int le dice al compilador que el valor que regresa


la funcin es de tipo entero (y si es necesario convertido a
entero). Solo hay un parmetro. La funcin se llama con la
instruccin: factorial(7);
Si la funcin no regresa ningn valor, sta debe ser del tipo
void. Si no se pone el tipo, la funcin ser int por default.
Los parmetros actan como sostenedores de espacio. Si no
hay parmetros, se escribe ah void (palabra clave).

Cualquier variable declarada en el cuerpo de la funcin ser


local a dicha funcin. Otras variables pueden declararse
exteriores a la funcin, esas son variables globales.
Cuando el programa se topa con la declaracin return, la
ejecucin de la funcin se termina y el control regresa al
lugar desde donde se llam a la funcin.
La declaracin o prototipo de la funcin se da, por
ejemplo como
double power(double x, double y);
El prototipo de funcin le dice al compilador el nmero y el
tipo de argumentos que se van a pasar a la funcin, y el
tipo de valor que se regresar. Pero los identificadores x, y
no los usa el compilador. Por eso tambin se puede escribir
double power(double , double );

#include <stdio.h>
float maximo(float x, float y);
float minimo(float x, float y);
void imprimir(int, float , float);
int main( void )
{
int i, n;
float max, min, x;

printf(Introduzca el numero de valores N\n);


scanf(%d,&n);
printf(Introduzca %d valores reales\n,n);
scanf(%f,&x);
max = min = x;
for(i = 2; i <= n; ++i){
scanf(%f,&x);
max = maximo(max,x);
min = minimo(max,x);
}
imprimir(n,max,min);
return 0;

float maximo(float x, float y)


{
if( x > y)
return x;
else
return y;
}
float minimo(float x, float y)
{
if( x < y)
return x;
else
return y;
}

void imprimir(int n, float x, float y)


{
printf(el maximo de la lista de %d nmeros es %f y el
minimo %f\n,n, max, min);
}
Los datos pueden ponerse en un archivo datos y se corre el
programa escribiendo
ejecutable < datos
o bien el usuario los escribe en la pantalla.
for( i = 2; i <= n; ++i){
scanf(%f,&x);
max = maximo(max,x);
min = minimo(min,x);
}
En cada ciclo se lee un nuevo valor para x, entonces los valores de
max y x pasan como argumentos de la funcin maximo y el mayor
de los dos se regresa y asigna a max. Similarmente se pasan las
variables min y x como argumentos de minimo y se asigna a min e
menor de los dos.

En C, los argumentos de las funciones siempre pasan


slo su valor. Es decir, se hace una copia del valor de
cada argumento, y son estas copias las que se procesan en
la funcin. Como consecuencia, la variables que pasan como
argumentos a las funciones NO CAMBIAN en el ambiente o
lugar donde se llamaron.
#include <stdio.h>
int main( void )
{
int a=1;
void change(int); /*
printf(a= %d\n,a);
change(a);
printf(a=%d\n,a);
return 0;
}

funcin interna a main */


/* se imprime 1 */
/* se impime ?? */

void change( int a)


{
a = 100;
}
Cuando a se pasa como argumento de la funcin
se produce una copia de a, es esta copia, y no la
misma variable a la que pasa a la funcin. As que
en el ambiente en que se llama a la funcin (en
main), la variable a no cambia.

Para que una funcin llame variables por referencia, deben


usarse apuntadores en la lista de parmetros. Y cuando se
llama la funcin, deben pasarse direcciones de variables
como argumentos.
#include <stdio.h>
int main(void)
{
int i=3, j=5;
void intercambia(int *, int *);
intercambia(&i, &j);
printf(%d %d\n,i,j); /* se imprime 5 3 */
return 0;
}

void intercambia(int *p, int *q)


{
int tmp;
tmp= *p;
*p = *q;
*q = tmp;
}
Toma dos argumentos del tipo pointer a enteros y no
regresa nada. La variable tmp es local de tipo int (y se usa
para guardar temporalmente un valor).
A tmp se le asigna el valor al que apunta p. Se le asigna al
objeto al que apunta p, el valor al que apunta q. El objeto al
que apunta q se le asigna el valor de tmp. Se han cambiado
en main los valores de objetos donde apunten p y q.

Arreglos como argumentos de funciones


En la definicin de una funcin, un parmetro que se
declara como un arreglo es realmente un apuntador. Como
notacin de conveniencia, el compilador permite notacin
de parntesis al declarar pointers como parmetros.
double sum(double a[], int n)
{
/* n es el tamao de a[] */
int i;
double sum= 0.0;
for(i=0;i<n; i++) sum += a[i];
return sum;
}
La declaracin double a[] es equivalente a double *a

Arreglos 2-dimensionales
Aunque los elementos de un arreglo se almacenan en
espacios contiguos uno tras de otro, es conveniente pensar
en un arreglo 2-dimensional como una coleccin rectangular
de elementos con filas y columnas.
Si declaramos
float a[2][4];
pensamos que el arreglo se acomoda como
a[0][0] a[0][1]
a[1][0] a[1][1]

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

a[0][4]
a[1][4]

La direccin base del arreglo es &a[0][0], no a. Empezando


el la direccin base, el compilador asigna espacio contiguo
para 8 floats.

Declaracin Formal de Parmetros


Cuando un arreglo multidimensional es un parmetro en una
definicin de funcin, todos los tamaos, exceptuando el primero,
deben especificarse, de modo que el compilador pueda almacenarlo
correctamente. Considere la declaracin
float a[2][4];
Esto aparta espacio para una matriz 2x4.
float suma(float a[][4])
{
int i,j;
float sum=0.0;
for(i=0;i<2;i++)
for(j=0;j<4;j++) sum += a[i][j];
return sum;
}
Inicializacin: int a[2][3]={1,2,3,4,5,6};
int a[2][3]={{1,2,3},{4,5,6}}; int a[][3]={{1,2,3},{4,5,6}};

Lo inadecuado de los arreglos


Suponga que se declara una matriz 3x3
float a[3][3];
y quiere usarse una funcin que calcule su determinante. Si
la matriz ya recibi valores, quisiramos
det = determinate(a);
cuya definicin se vera como:
float determinante(float a[][3])
{
.
Se mencion que es necesario especificar el 3 para que el
compilador trabaje bien. As que nuestra funcin trabajar
slo para matrices 3x3. Si queremos calcular el
determinante de una matriz 4x4, se requiere escribir una
nueva funcin !!

Construccin de matrices con arreglos de


apuntadores
Si uno empieza con un apuntador que apunta a un
apuntador que apunta a un float, se puede construir una
matriz de cualquier tamao que uno quiera, y pasarlas a
funciones diseadas para trabajar con matrices de tamao
arbitrario.
Aqu esta el cdigo para crear el espacio para una matriz:
int i, j, n;
float **a, det, tr;
. . . . . . . . . . . . /* se obtiene n de algn lado */
a = calloc(n, sizeof(float *));
for(i=0;i<n;i++) a[i] = calloc(n,sizeof(float));
El tamao de a no se necesita saber a priori, ni se necesita
como definir como constante. Una vez conocido el tamao
deseado, se usa la funcin calloc de la librera standard para

crear espacio para la matriz. Cuando se llama a esta funcin


como:
calloc(n, sizeof( type))
se crea espacio para un arreglo de n elementos del tipo
especificado (en este caso un apuntador que apunta a un
float), y se regresa la direccin base del arreglo. As que
a = calloc(n, sizeof( float *));
crea espacio para a (una arreglo de tamao n, de
apuntadores a float), en
for(i=0;i<n;i++) a[i] = calloc(n,sizeof(float));
a cada elemento de a, se le asigna la direccin base del
espacio creado en memoria para un arreglo de floats de
tamao n

Pensamos en a en la memoria como en el diagrama:


0
1
0

n-1

n-1

2
0

n-1

n-1

n-1

a se almacena en la memoria como un arreglo de


apuntadores, la expresin a[i][j] se usa para accesar el
elemento de la i-sima fila y j-sima columna. Como es
del tipo **a, entonces a[i] es del tipo float *, y puede
pensarse como la i-sima fila de la matriz. Como a[i] es del
tipo float *, se sigie que a[i][j] es del tipo float.
Ahora se puede pasar como argumento:
det = dterminante(a,n);
tr = traza(a,n);
float traza(float **a, int n)
{
int i;
float sum=0.0;
for(i=0;i<n;i++) sum += a[i][i];
return sum;
}

Ajustando los ndices


Espacio asignado por calloc() ( contiguos allocation) no
regresa al sistema cuando uno sale de la funcin, debe
usarse free() explcitamente para regresar ese espacio.
free(a), hace esto. calloc puede usarse para iniciar el
conteo desde 1. El libro Numerical Recipes en C, tiene un
archivo nrutil.c donde se hace todo esto.
#include nrutil.c
float *b, **a;
b=vector(1,n);
a=matrix(1,n,1,m);
Al final de la funcin debe liberarse el espacio:

free_vector(b,1,n);
free_matrix(a,1,n,1,m);

Debe usarse un apuntador a un archivo, y la funcin fopen()


y fclose() de la librera standard. Su funcin prototipo esta
en stdio.h
int main(void)
{
FILE *fp;
fp= fopen(file.dat,w);
.....
fclose(fp);
}

fopen() toma dos argumentos de cuerda. El


primero nombra al archivo con el que se
trabajar, y el segundo indica el modo, los mas
comunes son r para leer, y w para escribir.
Para escribir, en algn lugar del programa se usa:
fprintf(fp,%e\t%e\t%e\n,x,f(x),g(x));
Y para leer un archivo ya existente se usa:
fscanf(fp,%f, &z);

Funciones matemticas
C tiene funciones matemticas cuyos prototipos estn en
math.h
sqrt()

pow()

exp()

log()

sin()

cos()

tan()

Exceptuando pow(), todas estas funciones toman un solo


argumento de tipo double y regresan uno de tipo double.
pow() toma dos argumentos de tipo double, regresa uno
double:
pow(2.0, 2.5) 2.0 se eleva a la potencia 2.5
Hay muchas funciones: funciones hiperblicas, logartmicas,
exponenciales, arco tangente, arco seno, valor absoluto,
tc.

Usando Assertions
Suponga que la funcin f(a,b) se disea para generar
valores positivos, y queremos asegurarnos de esto,
entonces usamos:
c=f(a,b);
assert(c>0);
Si c>0 no se cumple, assert() escribe un mensaje y aborta.
assert() tiene sus prototipos en assert.h
Si supone que a debe ser 1 o -1, y que b debe estar en el
intervalo [5,10] escribimos:
assert(a==1 || a == -1);
assert(b>= 5 && b<=10);
assert() es fcil de usar y agrega robustez al cdigo.

Algunos ejercicios
I. Escriba un programa que pida un nmero entero y escriba
todos los nmeros primos menores que l. (Sugerencia:
use el operador %)
II. Escriba un cdigo que calcule e imprima los nmeros de
Fibonacci: f0= 0, f1=1, f_i+1= f_i+f_i-1, y juntamente con
cada nmero su respectivo cociente de Fibonacci: q_i =
f_i/f_i-1 con i=2,3,4,N, haga N=45 por ejemplo. A qu
valor converge q_j?
III. Sea a un nmero real positivo, considere la sucesin:
x0=1, x_i+1 = 0.5 (x_i + a/x_i) i= 0,1,2,. Puede
mostrarse que x_i -> sqrt(a) cuando i -> infty. Escriba un
programa que lea valores de a, use el algoritmo para
calcular la raz de a. Detenga la iteracin cuando
|a-x_i*x_i| < EPS , ud de el valor de EPS.

Вам также может понравиться