Documente Academic
Documente Profesional
Documente Cultură
Prlogo....................................................................................................................4
Prlogo del 2003.................................................................................................4
Prlogo del 2014.................................................................................................4
PARTE I: LO MS BSICO....................................................................................5
Introduccin........................................................................................................5
Conceptos generales..........................................................................................5
Variables y constantes........................................................................................5
Instrucciones de entrada / salida........................................................................6
Secuencias de escape.....................................................................................11
Aritmtica en C.................................................................................................11
Archivos de inclusin........................................................................................17
Variables globales y locales y reglas de alcance.............................................18
PARTE II: PROGRAMACIN ESTRUCTURADA................................................20
Condicin if-else...............................................................................................20
Condicin switch-case......................................................................................23
Ciclo for.............................................................................................................25
Ciclo while.........................................................................................................29
Ciclo do-while...................................................................................................30
PARTE III: FUNCIONES.......................................................................................33
PARTE IV:ARREGLOS Y ESTRUCTURAS.........................................................44
Arreglos unidimensionales...............................................................................44
Arreglos de tamao no predefinido..............................................................57
Arreglos de dos o ms dimensiones................................................................59
Arreglos con tamao no predefinido............................................................65
Arreglos de ms dimensiones..........................................................................67
Estructuras........................................................................................................69
Cadenas de caracteres....................................................................................72
PARTE V: APUNTADORES..................................................................................76
Apuntadores a variables...................................................................................77
Apuntadores y funciones..................................................................................79
Apuntadores y arreglos....................................................................................82
Arreglos de apuntadores..................................................................................87
Argumentos de la lnea de comandos..............................................................92
PARTE VI: ARCHIVOS.........................................................................................93
PARTE VII: MEMORIA DINMICA.....................................................................108
Listas enlazadas simples................................................................................108
rboles binarios..............................................................................................116
APNDICE A: LA BIBLIOTECA ESTANDAR.....................................................136
stdio.h.............................................................................................................136
Archivos......................................................................................................136
Salida con formato.....................................................................................137
Prlogo
Prlogo
Prlogo del 2003
Antes que nada quiero agradecer a las personas que me apoyaron para publicar
este libro, la Lic. Ana Gabriela Hernandez, la Ing. Karina Requena, el Ing Juan
Carlos Saenz, el Ing. Claudio Arzola, el Ing. Jess Valles y a Luz Cristina
Hernandez, que hizo la portada.
El libro lo escrib pensando en algo que fuera lo ms claro posible y que fuera
directo al punto, en lo personal no me gustan los libros donde lo que abunda es
la paja, y segn yo, creo y deseo que este prlogo sea la nica paja que tenga
este libro. Hablando de la claridad y de ir directo al grano, este libro no abunda
en ejemplos, presenta un ejemplo que pretenda ilustrar lo ms posible el tema y
lo explica a profundidad. Por eso a lo largo del libro recomiendo crear
situaciones distintas y practicar lo ms que se pueda, porque el libro te dice
cmo hacer las cosas, pero no tiene un ejemplo para cada cosa distinta. El libro
no es para nada largo, al contrario, por lo mismo recomiendo que se lea
completo no es la gran biblia de C, pero si lo lees completo tendrs una
plataforma bastante slida en los aspectos fundamentales (o sea los ms
importantes) del lenguaje. Es preferible que tengas algo de experiencia con
algn otro lenguaje de programacin o con el diseo de algoritmos, pero no es
del todo necesario, solo necesitaras poner ms atencin.
Es tiempo de terminar con este prologo, si bajaste el libro desde Internet o lo
copiaste en un disco lo puedes regalar a quien t quieras, pero no lo modifiques
ni lo plagies. Aunque no es un sper libro ni te cost mucho adquirirlo implic un
trabajo para m, un trabajo que espero que valores y que te sea muy til. Disfruta
entonces el libro y salo bien, mucha suerte :) ...
PARTE I: LO MS BSICO
PARTE I: LO MS BSICO
Introduccin.
El lenguaje C lo escribieron Dennis Ritchie y Brian Kernigham cuando trabajaban
con Ken Tompsom en el desarrollo de una nueva versin del sistema UNIX, en
los laboratorios Bell, o sea que C se escribi para escribir UNIX. C es un
lenguaje muy compacto porque el ejecutable que resulta es muy pequeo, es
muy potente y flexible, aparte de que tiene gran portabilidad porque un cdigo
que se escribe para un sistema en particular puede correr sin modificaciones, o
con muy pocas, sobre otro sistema diferente, aparte de que es independiente del
hardware. C es un lenguaje muy pequeo en el sentido de que no tiene muchas
instrucciones, lo que lo hace amplio es su biblioteca de funciones, que es algo
que lo hace muy flexible porque uno puede escribir su propia librera de
funciones y usarla en los programas.
Algo que quiero aclarar es que mucha gente trata a C y a C++ como la misma
cosa, esa gente se equivoca. El lenguaje C es un lenguaje imperativo, se basa
en una secuencia de rdenes para simular o para resolver problemas, pero el
lenguaje C++ es un lenguaje orientado a objetos, nada que ver. La forma de
manejar varios aspectos en C es diferente a la de C++. C++ ofrece varias
cualidades que C no tiene y viceversa, as que hazte a la idea de que este libro
es de C y no de C++.
Conceptos generales.
Las fases para hacer un programa son teclear un cdigo fuente, compilarlo a
cdigo objeto, y finalmente se enlaza para obtener un ejecutable. 1
El cdigo fuente es un archivo de texto que contiene todas las instrucciones que
han de ejecutarse para alcanzar la meta que el programador desea. El compilar
un programa es transformar todas las instrucciones del programa a un lenguaje
que la computadora pueda entender. Este cdigo objeto tiene referencias a otras
funciones y datos externos, o sea que no estn incluidos en el mismo cdigo
fuente, que al momento de enlazarlo se junta con los otros programas objetos de
los archivos que se necesiten para que el programa funcione. Y por ltimo
tenemos el programa ejecutable que es un cdigo que la mquina puede
entender y ejecutar.
Variables y constantes.
En un programa, y supongo que ya sabes ms o menos qu es un programa y
cmo se compone, hay valores que pueden cambiar o que deben admitir datos
1
PARTE I: LO MS BSICO
que el usuario necesite, como la temperatura, el promedio de una persona o lo
que sea, estos datos son variables y pues siempre estn sujetos a sufrir
cambios, por otro lado tenemos valores que no deben cambiar como la
constante o algn parmetro importante para que el programa funcione bien.
Tanto las variables como las constantes tienen tipos de datos, C tiene varios
tipos de datos, pero los ms bsicos son:
int: valor entero, pondra el rango admitido, pero depende en mucho del
sistema.
float: flotantes, nmeros como 3.14159 o 1.23 E16.
char: caracter, han de saber que en C no hay tipo de datos "cadena",
cmo guardar una palabra o algo as? Eso lo vemos despus.
PARTE I: LO MS BSICO
ser printf y la de entrada va a ser scanf, por ejemplo una lnea como la que
sigue.
printf("Que demonios hace esto?");
Imprime "Que demonios hace esto?" pero sin las comillas. Esas se ponen en la
funcin para delimitar la cadena que se va a imprimir. Pero bueno vamos a juntar
lo que hemos visto hasta ahora para escribir el primer programa en C. Por cierto,
no pienso poner detalles acerca de cmo crear el cdigo fuente y de cmo
compilarlo, eso tiene que ver de qu clase de compilador ests usando y pues
no puedo adivinar.
/*Esto es un comentario*/
#include <stdio.h> /*este es un archivo de cabecera, luego te explico, por ahora
solo ponlo*/
/*si este archivo el programa no hace nada*/
int main(int argc, char **args)/*inicia la funcin principal, me choca decirlo, pero
no preguntes solo ponlo as*/
{
printf("Hola mundo!!!");
return 0;
}
Que bonito! Pero y eso de qu sirve? Por lo pronto teclea el programa y
gurdalo con la extensin .c, ponle el nombre que quieras y consrvalo.
/*esto es un comentario*/
Es importante poner comentarios en los programas, para acordarnos que
hicimos y que otras gentes puedan entender qu pasaba por nuestra mente
cuando escribimos esas lneas de cdigo. Hay otra forma de poner comentarios,
que es ms propia de C++, que no es lo mismo que C, pero a veces funciona.
Esta forma es poner dos diagonales (//) al principio de cada lnea de comentario.
PARTE I: LO MS BSICO
#include<stdio.h>
Esta parte es muy importante, aqu incluimos un archivo, que es el que tiene las
funciones de entrada y salida, su nombre significa STandardD Input Output, la
extensin .h se refiere a head o cabecera, se les llama as porque siempre se
ponen a la cabeza del cdigo fuente. Hay muchos archivos de cabecera y ojal
que los veamos despus.
int main(int argc, char **args)
{
...
...
return 0;
}
En C todo se divide en funciones o segmentos de cdigo que hacen alguna
tarea en especial, regresan algn tipo de valor o no regresan nada y tambin
reciben datos o no, la funcin main es la directora de todas las dems, nada
funciona sin ella, en este caso main regresa un valor entero (int) mediante la
lnea return 0; esta vez solo regresa un 0, los valores que recibe se os pasa el
sistema operativo.
De vuelta con las funciones de entrada / salida, sabemos que un programa no
sirve de nada si no regresa un resultado til, la cosa es cmo poner los nmeros
y datos importantes en la salida o la entrada de nuestros programas, veamos el
siguiente cdigo.
#include<stdio.h>
int main(int argc, char **args)
{
int numero = 10; /*el nmero vale 10*/
printf("el numero vale %d", numero);
return 0;
}
PARTE I: LO MS BSICO
Podrs ver la notacin "%d" al final de la cadena, esto le dice a la funcin que en
ese punto inserte el valor entero decimal que viene a continuacin, luego
despus de la coma viene la variable que tiene que imprimir, no es tan
complicado despus de todo. Ese mismo programa pudo haberse escrito as.
...
int main(int argc, char **args)
{
printf("el numero vale %d", 10);
return 0;
}
El resultado es el mismo, lo que a la funcin printf le interesa es recibir un valor
entero, no le importa de donde venga. Hay ms formatos para imprimir diversos
tipos de valores, son los que siguen.
%f Valor flotante.
%c Imprime un caracter.
No son todos los formatos de entrada / salida, pero s nos sacan de casi
cualquier apuro.
Vamos a ver como poner varias cosas dentro del mismo printf, mira el siguiente
programa.
#include<stdio.h>
int main(int argc, char **args)
{
int val = 5;
char letra = 'o'; /*nota que el caracter se delimita por ' '*/
PARTE I: LO MS BSICO
printf("El numer%c es %d", letra, val);
return 0;
}
Como ves, se pueden poner varios argumentos en la funcin printf y se van
recogiendo en orden, o sea que si pongo printf("%d %f", 10.56, 4) es un error, se
debe poner printf("%d %f", 4, 10.56) en este programa vimos cmo colocar
caracteres y cmo se inicializan, no pierdas el detalle de poner las comillas
simples para encerrar el caracter que se va a poner.
Los formatos de salida son los mismos que los formatos de entrada, con unas
pocas diferencias, revisa el siguiente cdigo para aceptar valores desde el
teclado.
#include<stdio.h>
int main(int argc, char **args)
{
int num1, num2, num3; /*si, se pueden poner varias variables dentro de la
misma declaracin*/
printf(" Introduce un numero: ");
scanf("%d", &num1);
printf(" Introduce otros dos numeros: ")
scanf("%d %d", &num2, &num3);
printf("numero 1 = %d, numero 2 = %d, numero 3 = %d", num1, num2, num3);
return 0;
}
Como podrs adivinar el primer scanf lee un numero entero y lo pone en "num1",
el detalle de poner un & delante del nombre de la variable es muy importante, si
no lo pones pues el nmero que metiste no se va a guardar en la variable, luego
vemos qu significa ese smbolo. La parte ms complicada viene en el segundo
scanf, vienen dos variables, aqu lo que pasa es que hay que poner el numero 2,
un espacio y luego el numero 3, en lo personal no me gusta usar esa clase de
10
PARTE I: LO MS BSICO
formato, pero cada quien...
Secuencias de escape.
Si estuviste compilando y corriendo los programas, cosa que espero que hagas
y que experimentes un poco, te aseguro que es la mejor forma de aprender. Si lo
hiciste te habrs fijado en lo feo que imprime las cosas, para eso tenemos unas
secuencias de escape que nos permiten dar cierto formato a la impresin (tanto
como una terminal lo permite), hay secuencias de escape para poner una nueva
lnea, para retroceder sobre la lnea, etc., son los siguientes.
\n Nueva lnea
\t Tabulador horizontal
\\ Diagonal inversa
\v Tabulador vertical
\' Apostrofe
\r Regreso de carro
\" Comillas
\b Regresar un espacio
\f Avance de forma
Por ejemplo para escribir "hola mundo!!!" sin que el prompt empiece en la misma
lnea y el programa quede medio difcil de entender se pone as.
printf("\n\t\"Hola mundo!!!\"\n\n");
Escribe algunos programas o lo que quieras donde puedas revisar las
secuencias de escape para que veas cmo funcionan, ya que domines bien las
funciones de entrada y salida vamos a ver cmo hacer operaciones con
nmeros.
Aritmtica en C.
Se supone que ya sabes (muy poco) de cmo introducir variables y como
11
PARTE I: LO MS BSICO
imprimirlas, resulta ms o menos claro que la mayora de los programas deben
realizar clculos numricos para que sirvan de algo, las operaciones que
podemos hacer son las siguientes.
Resta: "-", a - b
Incrementos: Son operadores unitarios, o sea que solo se usan con una
variable, no como la suma que requiere dos variables, escribir ++var es
como decir "incrementa la variable var en uno antes de usarla", en cambio
escribir var++ sera decir "usa la variable var y luego la incrementas en
uno". Tambin se puede usar la resta poniendo --var o var--, pero as no
se puede mostrar bien su funcionamiento, ser ms claro cuando veamos
ciclos.
Tambin hay operadores para comparar, como el > (mayor que), o el <= (menor
o igual), pero los veremos cuando leguemos al tema de las decisiones, por lo
pronto vamos a escribir unos programas para hacer operaciones con unos
nmeros.
El primer programa que vamos a hacer es uno muy sencillo que sume dos
nmeros enteros y muestre el resultado.
#include<stdio.h>
int main(int argc, char **args)
{
int a, b, c; /*ya habamos visto que se pueden poner varias declaraciones en la
misma lnea*/
12
PARTE I: LO MS BSICO
printf("
scanf("%d", &b);
c = a + b; /*suma, puedes poner los smbolos pegados si quieres*/
printf("\n\tLa suma de %d + %d es %d!!!\n\tQu padre\n", a, b, c);
return 0;
}
Por favor haz el programa, escrbelo bien y crrelo para que veas cmo trabaja.
Un consejo, no s que compilador ests usando, estoy seguro de que ya habrs
cometido algunos errores y pues no has de haber batallado mucho para
corregirlos porque son programas muy chicos, pero procura leer muy bien los
mensajes que tu compilador te d, generalmente el error est una lnea antes de
donde te dice el compilador. Te recomiendo que hagas este programa y una vez
que funcione bien le quites un punto y coma por ah y veas el mensaje de tu
compilador, o quita el return, quita un &, alguna coma o lo que sea para que te
acostumbres al funcionamiento de tu compilador y agarres prctica para resolver
errores, la vas a necesitar.
Espero que ya hayas hecho lo que te ped, revisa las lneas siguientes.
int a, b, c; /*ya habamos visto que se pueden poner varias declaraciones en la
misma lnea*/
c = a + b; /*suma, puedes poner los smbolos pegados si quieres*/
printf("\n\tLa suma de %d + %d es %d!!!\n\tQu padre\n", a, b, c);
Fjate que estamos trabajando con tres variables distintas, ese programa se
13
PARTE I: LO MS BSICO
puede hacer con solo dos variables. Cambia las lneas anteriores por estas
lneas.
int a, b;
printf("\n\tLa suma de %d + %d es %d!!!\n\tQue padre\n", a, b, a+b);
Por ltimo borra la lnea donde haces la suma de c = a + b y compila el
programa otra vez, crrelo y ve el resultado que te arroja.
El siguiente programa muestra la cmo se usa la operacin de mdulo (residuo).
#include<stdio.h>
int main(int argc, char **args)
{
int num, mod;
printf(" Escribe un numero: ");
scanf("%d", &num);
mod = num % 3;/*mod = residuo de num / 3*/
printf("
return 0;
}
Este programa tambin se puede escribir as.
#include<stdio.h>
14
PARTE I: LO MS BSICO
int main(int argc, char **args)
{
int num;
printf(" Escribe un numero: ");
scanf("%d", &num);
printf("
return 0;
}
En C se pueden transformar los tipos de datos en caso de que se necesite. Por
ejemplo si escribimos esto.
float a, b;
int c;
...
...
c = a+b;
El compilador regresa un error porque no podemos guardar un flotante en un
entero, pero si la suma la escribimos as.
c = (int)(a+b);
A esto se le llama conversin explcita de tipo, o sea que estamos obligando a lo
que resulte de sumar a+b a convertirse en un valor entero. Las versiones ms
nuevas de ANSI C no marcan error, quiz una advertencia, lo que ocurre en este
caso es que al querer guardar un valor flotante dentro de una variable entera el
valor se redondea y se pierden datos. Por ejemplo, si a = 2.3 y b = 1.4, a + b =
3.7, si c es entera al hacer c = a+b, entonces c = 2.3 + 1.4 o sea c = 3.7 el
resultado final sera que c = 3.
Por otro lado C convierte los tipos de datos segn las operaciones realizadas
con ellos utilizando algo llamado promocin de tipos, siempre el resultado de
una operacin ser del tipo ms grande involucrado
15
PARTE I: LO MS BSICO
Descripcin
Post- incremento y decremento
Llamada a funcin
Elemento de vector
Seleccin de elemento por referencia
Seleccin de elemento con puntero
Asociatividad
Izquierda a
derecha
++ -+!~
(type)
*
&
sizeof
*/%
+<< >>
< <=
> >=
== !=
&
^
|
&&
||
c?t:f
16
Derecha a
izquierda
PARTE I: LO MS BSICO
=
+= -=
*= /= %=
<<= >>=
&= ^= |=
Asignaciones
izquierda
Archivos de inclusin.
Como viste, en todos los programas que hemos hecho viene la inclusin del
archivo del archivo stdio.h, este es parte de la biblioteca estndar. Y ya te haba
explicado que ah vienen todas las instrucciones de entrada y salida. Trata de
quitar esa lnea y vers que el compilador de manda errores en las funciones de
entrada y salida. Esos archivos son para guardar funciones que se usan mucho
y pues es pesado estarlas escribiendo, a veces yo los uso para dividir mis
programas en archivos ms chicos y fciles de leer. Al poner el nombre del
archivo entre "<>" le decimos al compilador que lo busque en su propio directorio
include, en cambio si le ponemos comillas le damos la ruta completa, por
ejemplo #include "c:\\mio.h" busca precisamente ese archivo y no lo busca en
otro lado. Si ponemos #include "lynx.h" lo busca en el mismo directorio donde
est el cdigo fuente. Vamos a hacer un experimento, teclea el siguiente cdigo.
/*contenido de cabeza.h*/
#include<stdio.h>
int a;
int b;
int c;
/*fin de cabeza.h*/
Guarda este archivo como cabeza.h, dentro del mismo directorio escribe el
siguiente cdigo.
17
PARTE I: LO MS BSICO
/*contenido de cabeza.c*/
#include"cabeza.h"
int main(int argc, char **args)
{
a = 5;
b = 6;
c = a+b;
printf("La suma es %d\n", c);
return 0;
}
Ahora guarda este cdigo como cabeza.c en el mismo directorio donde
guardaste cabeza.h y compila el programa, bsicamente el resultado es el
mismo que si hubieras escrito todo en el mismo archivo.
18
PARTE I: LO MS BSICO
int a = 5;/*variable local*/
{/*inicio de un bloque, bloque 2*/
int a = 13;/*otra variable, pero propia del bloque dos, la variable
a del bloque 1 es invisible aqu*/
printf("Dentro del bloque 2 a vale %d\n", a);
}
/*a la salida del bloque 2 a vale 5, nunca cambi su valor*/
printf("Dentro del bloque 1 a vale %d\n", a);
return 0;
}
En este caso hay dos variables a en el programa, pero la a del bloque 2 "oculta"
a la a del bloque 1.
#include<stdio.h>
int main(int argc, char **args)
{/*bloque 1*/
int a = 5;
{/*bloque 2*/
int b = 10;
/*dentro del bloque 2 a (del bloque 1) es visible*/
printf("Dentro del bloque 2 a vale %d y b vale %d\n", a, b);
}
/*fuera del bloque 2 b es invisible, no existe*/
return 0;
}
19
PARTE I: LO MS BSICO
Aqu vemos que la variable a es visible en el bloque 2, pero b no es visible en el
bloque 1, lo que pasa es que una variable es visible "hacia adentro" de los
bloques, pero no hacia afuera, por eso de las variables globales, ya que se
declaran muy afuera son visibles en todos los bloques. El truco es que si dentro
de un bloque o funcin declaramos una variable con el mismo nombre que una
de "ms afuera", la de ms afuera no ser visible, solo se podr trabajar con la
de ms adentro. Tienes que trabajar un poco poniendo a prueba lo que vimos
aqu, ya que es la manera en que puedas aprender, este libro es solo la lnea de
salida para que sepas qu es C y cmo usarlo.
Ahora que ya vimos las primicias de C, ms o menos como son los errores,
variables, etc., podemos pasar a la siguiente parte, que es la programacin
estructurada.
Condicin if-else.
A veces es necesario decidir entre dos caminos o dos acciones distintas si una
condicin, o varias se cumplen, la primer estructura para tomar decisiones que
vamos a ver es el if, que a veces es acompaado por else. Para tomar
decisiones hay que evaluar condiciones, en C tenemos operadores lgicos y
relacionales, son los siguientes.
Relacionales:
Mayor que
>
Menor que
<
>=
<=
Igual
==
Diferente
!=
Lgicos:
And lgico
&&
Or lgico
||
20
Negacin
Vamos a suponer que queremos decir que "si a es mayor o igual que 3 y b es
diferente de c", esto se puede escribir as: "(a >= 3) && (b != c)". As es, puedes
poner parntesis para separar expresiones o para agruparlas.
Pero es mejor que hagamos unos programas para poder ver cmo funcionan los
operadores y la decisin if. El siguiente programa toma un nmero, lo compara
con diez y te dice si es mayor o menor.
#include<stdio.h>
int main(int argc, char **args)
{
int num;
printf("\tIntroduce un numero: ");
scanf("%d", &num);
/* if(num > 10) equivale a decir "si num es mayor que 10"*/
if(num > 10)
{
/*en caso de que num sea mayor que diez imprime el mensaje*/
printf("
}
/*se sale del if y se continua con el programa*/
return 0;
}
El programa es muy sencillo, simplemente compara el nmero con diez e
imprime un mensaje si es mayor, el funcionamiento de la instruccin if es muy
simple, ahora vamos a cambiar un poco el programa, si el nmero es mayor que
diez va a imprimir el mensaje, pero de lo contrario va a imprimir otro mensaje.
Cambia el siguiente cdigo...
21
}
Al poner esas ltimas lneas es como decir "si es mayor que diez haz esto, de lo
contrario haz esto otro". Se pueden poner sentencias ms complicadas para
tomar decisiones, por ejemplo para evaluar rangos de valores. El siguiente
pedazo de programa ve que el nmero est entre 100 y 200, que seran los
lmites permitidos, en cazo de que el nmero este fuera de ese rango ser
rechazado.
If( (num >= 100) && (num <= 200) )
{
/* si el nmero est entre 100 y 200*/
printf("
}
else
{
/*si el nmero es menor que 100 o mayor que 200*/
printf("
El numero no es vlido\n");
}
Tambin se pueden poner un if dentro de otro if, vamos a suponer que una
calificacin sirve si est entre 60 y 100, si est entre 60 y 75 vamos a poner un
mensaje de que la calificacin est regular, si est entre 76 y 100 vamos a decir
22
/*en este punto sabemos que la calificacin no puede ser menor que 60*/
if( cal < 76)
{
/*si la calificacin es menor que 76 es regular*/
printf("regular\n");
}
/*de lo contrario la calificacin debe ser mayor o igual que 76, sirve
de mucho la teora de conjuntos para estas cosas*/
else
{
printf("muy bien\n");
}
}
Condicin switch-case.
Existe otra estructura para tomar decisiones, vamos a suponer que tenemos un
men de tres letras, de la a a la c. Podramos hacer una estructura de if's
anidados o algo por el estilo, pero a veces resulta ms sencillo, como en este
caso, utilizar una estructura de casos para el men. La estructura switch-case
funciona as.
#include<stdio.h>
int main(int argc, char **args)
{
23
scanf("%c", &op);
/*en esta lnea se le dice a switch que va a trabajar con la variable op*/
switch(op)
{
case 'a': /*en caso de que op sea a*/
printf("
break;
case 'c':
printf("
break;
default: /*default actua cuando no se eligi una letra correcta
no es necesario ponerla, pero puede ser muy util*/
printf("
}
return 0;
}
Creo que no necesita mucha explicacin el cmo funciona el switch, puede
funcionar con enteros, flotantes o caracteres. Dentro de los casos hay una
instruccin nueva, break es una instruccin que rompe todas las estructuras, en
este caso break hace que el programa se salga de la estructura switch, a veces
es importante ponerla. Escribe el mismo programa, pero qutale todos los
break's, juega con l y ve que es lo que pasa si eliges una b por ejemplo. Creo
que no te va a gustar qu es lo que pasa. Ahora regresa los break's a donde
deben de ir y quita la instruccin default (y tambin todo lo que est dentro del
24
Ciclo for.
En C hay tres tipos de ciclos, el ciclo do-while, while y el for, la verdad es que no
encuentro cmo explicarte como funciona el ciclo for sin usar ejemplos, as que
vamos a hacer un programa.
El siguiente programa va a presentar un men, se van a tener dos opciones,
imprimir todos los nmeros pares del 0 al 100 o imprimir los nones del 0 al 100.
Claro que necesitamos ciclos para hacer todo eso, seran muchas lneas de
cdigo. Para hacer el programa vamos a usar un switch, dos if's y dos ciclos for.
#include<stdio.h>
#define N 100 /*algo nuevo, definir valores previos*/
int main(int argc, char **args)
{
int i;
int op;
/*imprimiendo el men*/
printf("\n\t\tMenu\n\n");
printf("\t1) Imprimir los nones\n");
printf("\t2) Imprimir los pares\n");
printf("
scanf("%d", &op);
switch(op)
{
case 1:
/*el ciclo for es como decir "desde i = 0; mientras que sea menor que N;
incrementa i de uno por uno*/
for(i=0; i<N; i++)
25
Ciclo while.
Existe otro ciclo diferente, el ciclo while realiza la misma tarea mientras una
condicin se cumpla, es ms sencillo que el ciclo for, vamos a hacer un
programa que capture una letra varias veces y la vaya imprimiendo hasta que la
letra sea z.
#include<stdio.h>
int main(int argc, char **args)
{
char letra;
printf("Introduce las letras que quieras, para salir introduce una z\n");
while((letra = getchar()) != 'z')
{
29
Ciclo do-while.
El programa que acabamos de hacer (el del while), tiene una pequea falla, yo
quera que imprimiera la z otra vez, pero no la pone! Pero el seor Ritchie
30
long fact(int);
En este prototipo de funcin vemos un tipo de dato nuevo, long es un entero y se
trata como tal, pero es ms largo, si un entero normalmente trabaja con 16 bits,
que le da un rango de -2+1 a 2-1 el long trabaja con 32 bits, el doble, as que
puede almacenar nmeros desde -2+1 a 2-1 (puede variar segn la
implementacin) hay otro tipo de variable entera, short, que trabaja con la mitad
de bits, o sea que en un procesador de 32 bits trabajara con 8 bits que nos
dara un rango de valores de -127 a 127. Pero eso no es todo todos estos,
aparte del char y los flotantes (float y double), se pueden hacer sin signo la
palabra unsigned, en el caso del unsigned int cambia el rango de 0 a 65535,
pero bueno, volvamos a nuestras funciones, ya sabemos que esta funcin va a
regresar un valor long, que puede ser muy grande, que se va a llamar fact y que
va a recibir un valor entero. En los prototipos de funcin no es necesario poner el
nombre de las variables, solo el tipo, si quieres puedes poner el nombre de la
variable, pero no pasa nada si no lo haces.
printf(" El factorial de %d es %d\n", num, fact(num))
En este printf llamamos la funcin fact como un parmetro ms, cmo es esto?
Ya lo habamos visto antes, el valor que regresa fact es el valor que printf
imprime en nuestro mensaje. Al poner fact(num), le estamos mandando ese
entero para que trabaje con l.
long fact(int a)
{
...
...
return fact;
}
Aqu empezamos a trabajar con nuestra funcin aqu s debemos poner el
nombre de la variable que va a recibir, puede ser diferente, puede llamarse como
sea siempre que siga siendo entero, as que se me ocurri ponerle a. Escribimos
todas las instrucciones y al ltimo est el return fact, puedes poner el return
donde se te antoje, puede ser dentro de un if o un switch, como sea, pero
generalmente va al ltimo. Return manda el valor de regreso a quien quiera que
haya llamado a la funcin, en este caso le manda el valor de fact a la funcin
printf para que lo imprima.
38
Como puedes ver, una funcin puede recibir cualquier tipo de parmetro y
pueden ser diferentes entre s, adems de que pueden ser varios de ellos.
Hasta ahora hemos llamado funciones y les hemos mandado parmetros, pero
han sido pasos "por valor". Lo que quiere decir es que el programa crea una
copia de las variables y trabaja con las copias, a veces es mejor (ya sea por
espacio en memoria o por otras cosas) que las variables no se copien, sino que
la funcin trabaje con las originales. Esto lo vamos a ver despus, vamos a
hacer un programa que muestre cmo se copian las variables. Este programa va
a tomar un valor entero y le va a sacar su cuadrado.
#include<stdio.h>
int cuad(int);
int main(int argc, char **args)
{
int a;
printf("Introduce un numero para sacar su cuadrado: ");
scanf("%d", &a);
printf("El cuadrado de %d es %d\n", a, cuad(a));
return 0;
}
int cuad(int a)
{
a *= a;
return a;
}
Espero que lo hayas escrito y hayas visto como funciona, en la funcin cuad
estamos cambiando el valor de a, incluso lo estamos regresando a main, pero el
40
41
Recuerdas la frmula del factorial? Era algo como !n = n * (n-1) * (n-2) * ... * (1).
En forma recursiva la frmula sera !n = n * !(n-1). En este programa vemos dos
cosas, que se pueden poner operaciones entre parntesis para que return se
encargue de ellas, pero bueno eso es parte integral de C, y se puede hacer en
todos lados, como en fact(a-1), no hay problema por eso, lo otro es que una
funcin se puede llamar a s misma, eso se llama recursividad, si miras la
frmula recursiva de la frmula del factorial es exactamente la misma que escrib
en el return, funciona y lo hace bien.
Hay dos tipos de recursividades, la interna y la externa, la interna es esta que
acabamos de ver, la externa es cuando la funcin 1 llama a la funcin 2, y esta
llama otra vez a la funcin 1 y as las dos funciones recurren entre s. Mira bien
la funcin fact, mira que tiene una condicin, y en un punto tiene que regresar un
valor fijo, en la recursividad debe haber una condicin para que en un punto
dado la funcin no se vuelva a llamar a s misma (o a otra en el caso de la
recursividad externa), en este caso me fui siguiendo la frmula, el uno es el
ltimo numero que se multiplica y el factorial de 0 es 1 as que hice que cuando
el valor recibido fuera 0 la funcin regresara un 1, ese es el tope o caso base.
Ya hemos avanzado bastante, supongo que en este punto haz de pensar que los
programas que estamos haciendo estn muy simples, pero no puedo poner
programas ms complejos en el libro, solo puedo darte las herramientas para
que escarbes y te sea ms fcil aprender a programar en C. De todas formas el
libro no te sirve de nada si no tratas de complicarte la vida un poco y tratas de
hacer experimentos, puedes combinar lo que quieras, poner ciclos dentro de los
switchs, o poner switchs dentro de los ciclos, puedes mezclar todo con todo,
programar es como jugar lego, tienes las piezas y las armas a tu gusto. Yo solo
te estoy dando las piezas para que juegues, lo dems es cosa tuya. Creo que
vamos bien hasta este momento, no hemos visto muchas funciones de la
biblioteca estndar, pero hemos visto algunos trucos y propiedades de C que te
van a servir mucho. Ya estamos listos para entrar al siguiente tema, los arreglos,
aparte en el siguiente tema vamos a ver las estructuras, que son un tipo de dato
que tarde o temprano vas a usar mucho, como no hallo donde ponerlo pues lo
vamos a ver en la siguiente parte del libro. Por favor tmate un descanso repasa
un poco lo que ya vimos, porque de ahora en adelante vamos a hacer
programas de ms de 100 lneas, porque me interesa que aprendas a leer
cdigo y que veas unos buenos ejemplos. En realidad C es muy sencillo y muy
pequeo, y hasta este punto vamos muy bien y creo que te he podido explicar
todo de la forma ms simple, pero vamos a ver ms ejemplos, y va a ser lo largo
del libro.
43
44
46
MENU\n\n");
printf("
a) Llenar el arreglo\n");
printf("
printf("
printf("
d) Salir\n");
printf("
Tu opcion: ");
op = getchar();
49
52
56
");
61
63
Arreglos de ms dimensiones
Llevo dos aos programando en C, es muy poco, pero ya me s algunos buenos
trucos, es que C es muy sencillo y compacto. En este tiempo nunca he
necesitado una matriz de ms de dos dimensiones, pero el siguiente programa
(lo hice por curiosidad) trabaja con una matriz de tres dimensiones. Es muy
complicado ver como inicializa los valores y cmo se pueden acomodar (al
menos lo es para m), pero pens que sera una buena referencia.
67
Estructuras.
Ya vimos que un arreglo puede contener varias variables del mismo tipo, pero
ahora hay un problema, el siguiente problema es que necesitamos capturar y
listar la informacin de 10 alumnos, la informacin de cada alumno tiene su
nombre, su matrcula y su promedio. Son muchos datos, necesitamos alguna
estructura de datos que los pueda contener todos. El siguiente programa va a
contener tres variables distintas dentro de la misma estructura, vamos a ver
cmo se da de alta una estructura (declararla), y cmo manipular sus datos.
#include<stdio.h>
struct datos{
int a;
float b;
69
Cadenas de caracteres
Vamos a hacer un arreglo de diez estructuras, pero a nivel local en main, ese
arreglo de estructuras va a almacenar los datos de los diez alumnos (nombre,
matrcula y promedio) los va a ordenar en base a la matrcula y por ltimo los va
a imprimir en orden.
#include<stdio.h>
#include<string.h>
#define A 10 /*corresponde a alumnos*/
#define N 50 /*largo del nombre*/
struct alumnos{
int mat;
char nombre[N]; /*un arreglo de caracteres*/
float prom;
};
void captura(struct alumnos []);
void ordena(struct alumnos []);
void imprime(struct alumnos []);
int main(int argc, char **args){
struct alumnos a[A]; /*se supone que as declaramos el arreglo de estructuras*/
captura(a);
ordena(a);
imprime(a);
return 0;
}
72
PARTE V: APUNTADORES
Algo que hace de C un lenguaje muy potente son los apuntadores, nos dan
mucha flexibilidad y potencia. Digamos que la memoria principal del sistema es
como un barrio, un apuntador sera el viejito que se sabe las direcciones de
todos los que viven ah, te puede decir la informacin que necesitas de cada
persona que vive en ese barrio sin que tengas que ir hasta ella. En los
problemas de memoria dinmica, por ejemplo, hay una funcin que encuentra un
espacio libre y lo aparta, luego esa funcin regresa la direccin de la memoria
que puede ser utilizada, para acceder a esa direccin se necesitan apuntadores.
O para manejar cadenas de caracteres y arreglos (es lo mismo), en realidad lo
que se hace es trabajar con apuntadores. Es mucho ms fcil y eficiente poner
4
76
PARTE V: APUNTADORES
un dato en una direccin de memoria, hacer un apuntador hacia esa variable y
poder trabajar con esa variable a travs del apuntador, a distancia. En este tema
vamos a trabajar mucho tiempo, al principio los apuntadores son complicados,
sobre todo al tratarse de cadenas y arreglos (aunque sea lo mismo los vamos a
diferenciar), pero se usan mucho, ya lo vers. Entonces es mejor trabajar mucho
con esto.
Apuntadores a variables.
Lo ms bsico de un apuntador es el que apunta a una variable sencilla, vamos
a ver qu significa el ampersand (&) de la funcin scanf y tambin los dos
trminos bsicos tratando con apuntadores.
Lo primero que quiero que hagas (por el momento), es que aprendas esto.
& Significa "direccin de" y * significa el "valor que esta en (tal direccin)".
Cmo es esto? Mira el siguiente cdigo y por favor escrbelo y hazlo correr.
#include<stdio.h>
int main(int argc, char **args){
int var;
printf("La direccion en memoria de var es %p\n", &var);
return 0;
}
La salida del programa es una lnea como "printf("La direccion en memoria de
var es %p\n", &var);", espero que ya te haya cado el veinte de lo que quiere
decir el &, se refiere a la direccin de memoria de la variable. Entonces ahora te
puedo decir que al escribir scanf("%d", &variable) estamos diciendo algo como
"recoge un valor entero decimal y lo pones en la direccin de memoria fulana de
tal".
Un apuntador es una variable pequea que guarda la direccin de memoria de
una variable, puede ser de cualquier tipo, desde int hasta struct, aparte puede
ser void (apuntador genrico). En el siguiente cdigo se muestra como usar un
apuntador.
#include<stdio.h>
77
PARTE V: APUNTADORES
PARTE V: APUNTADORES
En estas lneas imprimimos la direccin de la variable a en cdigo hexadecimal,
en la segunda lnea imprimimos el valor verdadero del apuntador b, que es la
direccin de a.
printf("Introduce el valor de a: ");
scanf("%d", &a);
printf("El valor de *b es %d\n", *b);
En este pedazo vemos como podemos cambiar el valor de a y verlo usando el
apuntador, nota que al poner el asterisco ponemos el valor que est en dicha
direccin de memoria, recuerda lo que escrib antes: "& significa 'direccin de' y *
significa el 'valor que esta en (tal direccin)'".
printf("Vuelve a cambiar el valor de a: ");
scanf("%d", b);
printf("Ahora a vale %d\n", a);
Aqu cambiamos el valor de a usando su apuntador en la funcin scanf,
acurdate lo que significa poner el ampersand en una variable normal, aqu
usamos el apuntador y obtenemos el mismo resultado.
printf(" a + 2 es %d y *b + 2 es %d\n", a+2, *b+2);
En esta lnea puedes ver cmo se pueden hacer operaciones tanto con la
variable como con el apuntador (usando su asterisco claro).
Apuntadores y funciones.
Vamos a ver un uso de los apuntadores, uno bueno, espero recuerdes que
cuando pasamos un valor a una funcin lo que se haca en realidad era copiarlo
y trabajar con la copia. A veces no queremos que un programa haga eso,
observa el siguiente cdigo y ve la diferencia.
#include<stdio.h>
void min(char *letra){
if(*letra >= 65 && *letra <= 90){
*letra += 32;
79
PARTE V: APUNTADORES
}
}
int main(int argc, char **args){
char letra;
char *pletra = &letra;
printf("Introduce una letra en mayusculas ");
letra = getchar();
min(pletra);
printf("Ahora la letra es %c\n", letra);
return 0;
}
Acurdate del programa que hicimos hace rato donde cambiaba las letras a
minsculas, en este programa escrib una versin usando punteros, hay una
diferencia muy grande, el valor no se copia, en realidad cambia el original.
void min(char *letra){
if(*letra >= 65 && *letra <= 90){
*letra += 32;
}
}
En la declaracin de la funcin especifico que va a recibir un apuntador, luego le
doy el tratamiento como a cualquier variable, cambio su valor y la funcin
termina,
min(pletra);
Cuando llamo a la funcin le paso el apuntador que haba declarado e
inicializado con la variable que nos interesa cambiar a minsculas.
Lo que pasa es lo siguiente, cuando declaro la funcin le digo que va a recibir un
apuntador, nada del otro mundo, cuando llamo la funcin le mando un
apuntador, todo en orden. Dentro de la funcin se trabaja como con cualquier
80
PARTE V: APUNTADORES
variable normal, pero no regresa ningn valor. Lo que pasa es que el puntero s
se copia, el truco es que aunque sea una copia el apuntador de la funcin
apunta hacia donde mismo, entonces la variable original cambia aunque no est
dentro de la funcin, es algo as como una llamada de larga distancia.
Otra forma de escribir el programa sera esta.
#include<stdio.h>
void min(char *letra){
if(*letra >= 65 && *letra <= 90){
*letra += 32;
}
}
int main(int argc, char **args){
char letra;
printf("Introduce una letra en mayusculas ");
letra = getchar();
min(&letra);
printf("Ahora la letra es %c\n", letra);
return 0;
}
La diferencia es que no declaramos un apuntador en main, al llamar a la funcin
simplemente le mandamos la direccin de la variable que nos interesa cambiar.
Aqu el apuntador no se copia, simplemente que el apuntador de la funcin min
se carga con la direccin de la variable que vamos a convertir en minsculas.
Vamos a ver un ltimo cdigo antes de pasar al siguiente tema, este programa
va a capturar un nmero flotante y lo va a convertir a su cuadrado.
#include<stdio.h>
81
PARTE V: APUNTADORES
void cuad(float *);
void main(void){
float num;
printf("Introduce un numero: ");
scanf("%f", &num);
cuad(&num);
printf("El cuadrado de tu numero es %f\n", num);
}
void cuad(float *a){
*a *= *a;
}
Apuntadores y arreglos.
Escribir este librito me va a servir mucho, el tema que vamos a ver enseguida se
me complica bastante. Hay algo que has de saber, un arreglo es un apuntador
que apunta a espacios de memoria contiguos. Si pones una lnea como int a[3]
ests apartando tres espacios de memoria que estn uno tras otro y a es su
apuntador, ciertamente. Cuando ponemos algo como a[2] estamos diciendo
"smale dos espacios al apuntador este a ver que se encuentra ah", podras
poner a[234], no te va a poner ningn error, simplemente va a apuntar a algn
lugar de la memoria, el secreto es que *a es lo mismo que a[0]; y que *(a+1) es
lo mismo que a[1]. Mira el siguiente cdigo y ve el resultado.
#include<stdio.h>
void recorre(int *, int []);
int main(int argc, char **args){
int arr[3] = { 2, 5, 8};
printf(" Te voy a probar que un arreglo es un apuntador\n\n");
recorre(arr, arr);
82
PARTE V: APUNTADORES
return 0;
}
void recorre(int *a, int b[]){
printf(" *a = %d y b[0] = %d\n", *a, b[0]);
printf(" *(a+1) = %d y b[1] = %d\n", *(a+1), b[1]);
printf(" *(a+2) = %d y b[2] = %d\n", *(a+2), b[2]);
printf(" *(a+3) = %d y b[3] = %d, pero ya nos pasamos\n", *(a+3), b[3]);
printf(" *(a-1) = %d Y b[-1] = %d, pero estamos muy atras\n", *(a-1), b[-1]);
}
Mira el cdigo y ve como es lo mismo tratar con el arreglo que con el apuntador,
porque un apuntador y un arreglo son bsicamente lo mismo.
Otra forma de ver que un arreglo es lo mismo que un apuntador esta en este
cdigo.
#include<stdio.h>
void recorre(int []);
int main(int argc, char **args){
int arr[3] = {2, 5, 8};
printf(" Te voy a probar que un arreglo es un apuntador\n\n");
recorre(arr);
return 0;
}
void recorre(int b[]){
printf(" *b = %d\n", *b);
printf(" *(b+1) = %d\n", *(b+1));
83
PARTE V: APUNTADORES
printf(" *(b+2) = %d\n", *(b+2));
printf(" *(b+3) = %d, pero ya nos pasamos\n", *(b+3));
printf(" *(b-1) = %d, pero estamos muy atrs\n", *(b-1));
}
Es lo mismo, aqu es ms clara la relacin entre un arreglo y un apuntador, son
como gemelos todos los gemelos tienen sus diferencias, pero tienen mucho
parecido.
Ten cuidado en el uso de los parntesis, no es lo mismo *(b+1) que *b+1, *b+1
quiere decir que se le sume 1 a la variable que est en dicha direccin, y *(b+1)
es la variable que est una casilla despus de b.
Casi siempre se obtiene mejor desempeo cuando se usan punteros, espero te
acuerdes de lo que hacen las funciones gets y puts, porque las vamos a clonar
usando punteros.
#include<stdio.h>
void clon_de_gets(char *);
void clon_de_puts(char *);
int main(int argc, char **args){
char str[10];
clon_de_puts("Escribe tu cadena aqui: ");
clon_de_gets(str);
clon_de_puts(str);
return 0;
}
void clon_de_gets(char *a){
while((*a++ = getchar()) != '\n');
*--a = '\0';
}
84
PARTE V: APUNTADORES
PARTE V: APUNTADORES
imprime(str, posicion);
return 0;
}
int llena(char *a, int largo){
int i = 0;
while((*(a+i) = getchar()) != '\n' && i++ < largo);
return i;
}
void clon_de_puts(char *a){
while(*a != '\0'){
putchar(*a++);
}
}
void imprime(char *a, int p){
while(p >= 0){
putchar(*(a + --p));
}
putchar('\n');
}
Sencillo, la funcin llena va contando los caracteres que van entrando y vigila
que no se introduzcan ms caracteres de los que caben en la funcin, as se
corrige la falla del clon de gets, luego regresa el nmero de caracteres que
entraron a la funcin.
La funcin que imprime al revs recibe como parmetro el nmero de caracteres
que entraron a la cadena y a partir de ah empieza a imprimirlos en reversa
usando la notacin para los arreglos "*(a + --p)" as que lo que hace es restar
uno a p y luego sumarlo a la posicin de a para ir imprimiendo, puse --p en vez
de p-- porque el ltimo caracter que entr fue un enter, as que con --p el enter
86
PARTE V: APUNTADORES
no aparece, puedes cambiarlo por p-- para que veas la diferencia. Algo que se
me hizo muy interesante fue que la funcin se pudo escribir as.
void imprime(char *a, int p){
while(p >= 0){
putchar(a[--p]);
}
putchar('\n');
}
Puedes convertir arreglos para trabajarlos como apuntadores o puedes tratar
apuntadores como si fueran arreglos. Claro que esto lo puedes hacer solo hasta
cierto punto.
Arreglos de apuntadores.
Hace tiempo hice un juego que te responde tus preguntas acerca del futuro con
frases como s, no, seguramente, no me interesa, etc. haba respuestas muy
largas y otras muy cortas, todas esas cadenas de caracteres las tuve que
guardar en un arreglo para seleccionar la respuesta aleatoriamente, pero en las
respuestas muy cortas se desperdiciara mucho espacio ya que era un arreglo
de 20 por 30, as que en respuestas como si o no desperdiciara 28 espacios de
memoria. Funcionara bien, pero lo ptimo sera un arreglo de apuntadores.
El siguiente cdigo es el cdigo que hice, lo he mejorado un poquito, pero
bsicamente es lo mismo.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 20
char *respuesta(void);
87
PARTE V: APUNTADORES
int main(int argc, char **args){
do{
system("cls");
puts("\t\t\t
puts("
EL ORCULO DE LYNX\n");
printf("\t
>>>");
gets(NULL);
printf("\n
%s\a\n", respuesta());
printf("\n
getchar();
}while(1);
return 0;
}
char *respuesta(void){
char *resps[] = {
"Definitivamente s :D",
"S :)",
"Busca la respuesta en tu corazn :o",
"Es muy probable :)",
"Eso me parece bien :D",
"Es mejor cambiar de tema :\\",
"Concntrate y vuelve a hacer la pregunta :|",
"Cualquier cosa puede suceder :\\",
"Las cosas son inciertas :$",
"No te puedo contestar ahora :|",
"No s y no me importa :@",
"Los ngenles de Charlie fu un churro cinematogrfico :o",
"Hay cosas que es mejor ignorarlas :o",
"Sigue as y no habr problemas :)",
88
PARTE V: APUNTADORES
"Eso me parece mal :|",
"Las posibilidades son pocas :(",
"Prefiero no contestar :@",
"Tal vez no :(", "No :\\",
"Definitivamente no :b"
};
srand(time(NULL));
return (resps[rand() % N]);
}
Prueba el programa, a m me gust, para ser de menos de cincuenta lneas est
bien. Vmonos parte por parte para que cheques el cdigo.
char *respuesta(void);
Te has de preguntar por qu puse un asterisco en el nombre de la funcin, lo
que pasa es que esta funcin regresa un apuntador, creme, no es ningn error.
system("cls");
Ya la habamos visto antes, solo para recordar, la funcin system llama a los
comandos del sistema, aqu lo que se hace es limpiar la pantalla.
gets(NULL);
Recuerda que gets recibe como parmetro un arreglo de caracteres (char []),
aunque en realidad su declaracin es gets(char *), para el caso es lo mismo,
recibe un apuntador para poner las letras ah, pero en este caso le mandamos
un NULL, as agarra los datos del teclado, pero no los pone en ningn lado.
printf("\n
%s\a\n", respuesta());
89
PARTE V: APUNTADORES
char *resps[] = {
"Definitivamente s :D",
"S :)",
...
...
...
"Definitivamente no :b"
};
En estas lneas estoy declarando un arreglo, un arreglo de apuntadores a char
(char * []). Recuerda que declarar char a[] = "hola" es lo mismo que char *b =
"hola", aqu lo que hice fue hacer un "arreglo de apuntadores a char" o un
"arreglo de arreglos char" o un "arreglo de cadenas", como lo digas a mi parecer
est bien dicho.
srand(time(NULL));
return (resps[rand() % N]);
Acurdate de la funcin para generar nmeros aleatorios, lo que se hace es
seleccionar un puntero de entre el arreglo podra ser resps[1] o resps[6], pero es
al azar, luego lo mandamos con el return.
Para que te quede ms claro el asunto de los apuntadores y arreglos mira el
siguiente cdigo.
#include<stdio.h>
void pon_cadena(char *a){
while(*a != '\0'){
putchar(*a++);
}
}
90
PARTE V: APUNTADORES
int main(int argc, char **args)
{
int i = 0;
char *rollo[] = {
"Hola ",
"saltamontes, ",
"espero ",
"que ",
"todo ",
"este ",
"rollo ",
"te ",
"sirva ",
"de ",
"algo ",
'\0'
};
while(rollo[i] != '\0'){
pon_cadena(rollo[i++]);
}
pon_cadena("\n");
return 0;
}
Para que te sea ms fcil entenderle este cdigo es ms sencillo. La diferencia
es que el ltimo elemento del arreglo de apuntadores char es que el ltimo
elemento es '\0', se lo puse para que el ciclo donde imprime todo el rollo no se
pase, porque de lo contrario imprime el rollo este y luego se pone a imprimir la
marca del compilador. Si s de donde saca esos datos, pero no tiene caso
explicrtelo todo, solo que son cadenas que el programa tiene perdidas por ah.
91
PARTE V: APUNTADORES
PARTE V: APUNTADORES
tener cuidado. Ya estamos listos para pasar a la siguiente parte del libro, los
archivos, vamos a ver si podemos hacer una pequea agenda con la
informacin de tus amigos. Tambin vamos a hacer un programa que te haga un
test y guarde el resultado en un archivo para que lo leas despus. Tambin
vamos a hacer un programa que lea texto desde un archivo y lo vaya
imprimiendo en la pantalla.
93
"a+" Abre el archivo para lectura y escritura, pero todas las escrituras
del archivo se aaden al final.
Este programa explica un poco cmo funcionan los modos de cmo abrir un
archivo y algo acerca de ciertos archivos especiales.
99
#include<stdio.h>
int main(int argc, char **args){
FILE *archivo;
char c;
archivo = fopen("texto.txt", "w+");
fputs("Este archivo se supone que se abri como lectura escritura\n", archivo);
rewind(archivo);
while((c = fgetc(archivo)) != EOF){
putchar(c);
}
puts("Escribe lo que quieras y termina con un EOF (control + z en dos y control
+ d en linux)");
while((c = getchar()) != EOF){
putc(c, archivo);
}
rewind(archivo);
fputs("\nEste es el contenido del archivo\n", stdout);
while((c = fgetc(archivo)) != EOF){
putchar(c);
}
100
fclose(archivo);
archivo = fopen("texto.txt", "a+");
fputs("\n final del archivo\n", archivo);
fclose(archivo);
return 0;
}
archivo = fopen("texto.txt", "w+");
Abre el archivo para escribir sobre l (hasta el final del archivo) y para leerlo.
rewind(archivo);
La funcin rewind se regresa al principio del archivo para volverlo a leer o para
reescribirlo desde el principio.
puts("Escribe lo que quieras y termina con un EOF (control + z en dos y
control + d en linux)");
while((c = getchar()) != EOF){
putc(c, archivo);
}
En dos el EOF es control + z, en este ciclo se pueden introducir caracteres
directamente sobre el archivo hasta que se detecte un EOF. Te recomiendo que
estudies la funcin int fflush(FILE *nombre_de_archivo), te aseguro que te ser
de utilidad algn da.
fputs("\nEste es el contenido del archivo\n", stdout);
Existen tres archivos que siempre usamos y nunca nos damos cuenta, son
stdout, stderr y stdin, y se refieren a la salida estndar, el error estndar y la
entrada estndar, generalmente son el monitor (stdout y stderr) y el teclado
(stdin), pero se pueden re-direccionar a algn otro dispositivo. En esta lnea la
funcin fputs imprime la cadena en la pantalla.
101
DIRECTORIO\n\n");
printf("\tMenu\n");
printf("
a) Consultar\n");
printf("
b) Agregar persona\n");
printf("
c) Salir\n");
printf("
Tu opcion: ");
op = getchar();
103
104
Tu opcion: ");
op = getchar();
if(op != '\n'){
getchar();
}
switch(op){
case 'a':
poner(&j);
break;
case 'b':
quitar();
break;
case 'c':
recorre();
break;
111
Ahora con el casting implcito no es necesario, pero puede hacer el cdigo ms legible.
113
rboles binarios.
Ya llegamos a la recta final, el ltimo programa que te voy a ensear es uno de
los que ms me han gustado, es la versin de nuestro directorio que tiene
memoria dinmica, este programa va a ordenar todos los elementos en orden
alfabtico y va a poder eliminar elementos o actualizarlos. Antes que nada es
necesario explicarte los rboles binarios, un rbol binario es el rbol donde cada
nodo puede tener dos o menos hijos y solo un padre, aparte los elementos estn
ordenados de modo que los menores a la raz van en el subrbol izquierdo y los
mayores en el subrbol derecho. El recorrido en orden es en el cual se recorre el
subrbol izquierdo, luego la raz y al final el subrbol derecho.
Te recomiendo que antes de ver este programa repases lo que es la recursividad
y el uso de cadenas.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#define NOM 12
#define D 65
#define DAT "libro.dat"
struct binario{
char nombre[NOM];
char datos[D];
int valido;
struct binario *i;
struct binario *d;
116
}else{
printf(" El nombre %s no existe\n", nombre);
}
}
/*utiliza la funcion buscar para modificar los datos*/
void modificar(void){
struct binario *p;
char nombre[NOM];
printf(" Cual es el nombre que quieres actualizar? ");
fgets(nombre, NOM, stdin);
mayusculas(nombre);
if((p = buscar(raiz, nombre))){
printf(" Introduce los nuevos datos: ");
fgets(p->datos, D, stdin);
122
getchar();
*i = 0;
123
%s\n", hoja->nombre);
DIRECTORIO\n");
Menu\n");
printf(" a) Agregar\n");
printf(" b) Buscar\n");
printf(" c) Modificar\n");
printf(" d) Eliminar\n");
printf(" e) Recorrer el directorio\n");
124
Tu opcion: ");
op = getchar();
if(op != '\n'){
getchar();
}
switch(op){
case 'a':
agregar();
break;
case 'b':
ver();
break;
case 'c':
modificar();
break;
case 'd':
eliminar();
break;
case 'e':
recorre(raiz, &i, &j);
printf(" Hay %d personas en el directirio\n", j);
break;
case 'f':
continue;
default:
printf(" Tecla incorrecta\n");
}
printf("Pulsa enter para seguir");
getchar();
125
}else{
if((aux = fopen(DAT, "w")) != NULL){
printf(" El archivo %s no se puede abrir, se ha creado el archivo ", DAT);
printf("pero necesitas reiniciar el programa\n");
}else{
printf(" No se encuentra el archivo %s\n", DAT);
}
}
return 0;
}
Modestia aparte este programita me qued muy bien, lo he estado revisando y
no tiene bugs, tena uno, pero lo encontr. Prubalo y ve qu tal, es como una
base de datos muy (muchsimo) primitiva, pero los rboles se usan como no
tengas una idea y son lo que se usa en las bases de datos. Esto es lo ltimo que
vamos a ver, fue el programa de despedida de este pequeo curso. Te lo voy a
explicar con todo detalle para que sea tu graduacin, hay mucho ms del
lenguaje, pero solo son libreras que no vimos aqu, lo dems ya lo sabes y no te
costar mucho trabajo aprender lo que sigue. Te voy a explicar pues este
programa.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
Las libreras que se van a usar, como vamos a trabajar mucho con cadenas de
caracteres necesitamos la librera string.h, aunque solo se van a usar dos
funciones de aqu. Adems de esto incluimos la librera ctype.h, en la cual se
incluyen algunas funciones de manejo de caracteres.
126
131
}else{
printf(" El nombre %s no existe\n", nombre);
}
}
Esta funcin utiliza a la funcin buscar para que le diga la posicin del nombre
que busca, si la encuentra imprime la informacin, si no avisa que el nombre no
existe.
struct binario *buscar(struct binario *hoja, char *s){
if(hoja){
int i = strcmp(hoja->nombre, s);
if(i != 0){
132
getchar();
*i = 0;
}
if(hoja->valido){
(*j)++;
printf("
%s\n", hoja->nombre);
Archivos.
FILE *fopen(char *nombre, char *modo)
Abre un archivo con el nombre y el modo especificado, si el archivo se puede
abrir regresa el apuntador y si no se puede regresa un NULL, los modos son los
siguientes.
Aparte de estas llamadas existe la opcin b, esta opcin se usa para archivos
binarios, una llamada "w+b" o "wb+" creara un archivo para escribir y leer de el
en modo binario.
int fflush(FILE *nombre)
Escribe en el archivo de salida todos los datos que estn almacenados en el
buffer asociado, esto para dejar el buffer despejado. Regresa un EOF si existe
algn error o un 0 si todo sali bien.
int fclose(FILE *nombre)
Cierra el archivo especificado, si hay algn error regresa un EOF o 0 si todo est
bien.
int remove(char *nombre)
Elimina el archivo nombre del directorio. Regresa 0 cuando no hay error.
int rename(char *nombre, char nuevo_nombre)
Renombra un archivo segn las cadenas introducidas, regresa 0 si todo sale
bien.
FILE *freopen(const char *archivo, const char *modo, FILE *archivo2)
Reabre archivo con el modo estipulado y asocia al archivo2 con el, o sea que
freopen("archivo.txt", "w", stdout) re-direcciona la salida stdout a archivo.txt, as
que al poner printf("Hola a todos :)\n") la salida no se imprime en la pantalla sino
en archivo.txt. freopen regresa un apuntador a archivo.
d,i
x,X
s
char *, se imprime la cadena hasta encontrar un '\0' o hasta la
cantidad de caracteres indicados por la precisin.
f
double, notacin decimal, la precisin se puede estipular como %.2f
para limitar la salida a dos decimales, la precisin por defecto son seis
decimales.
Se imprime como %.
138
Funciones de error.
void clearerr(FILE *archivo)
Limpia los indicadores de error y de EOF para el archivo.
int feof(FILE *archivo)
Regresa un valor diferente de cero si encuentra un fin de archivo.
int ferror(FILE *archivo)
Igual que feof, pero para el error.
* NOTA: En el caso de mi compilador clearerr es clrerr y clreof, donde clrerr
limpia el error y clreof limpia el estado de EOF.
string.h
char *strcpy(char *destino, char *fuente)
Copia la cadena fuente en la cadena destino incluyendo el '\0', regresa destino.
char *strncpy(char *destino, char *fuente, size_t n)
Copia la cadena fuente en destino hasta n caracteres.
char *strcat(char *destino, char *fuente)
Concatena las cadenas destino y fuente en destino.
char *strncat(char *destino, char *fuente, size_t n)
Igual, pero concatena hasta n caracteres.
int strcmp(char *c1, char *c2)
Compara c1 con c2, si c1 es menor regresa un nmero negativo, si c1 es mayor
regresa un nmero positivo, si son iguales regresa cero.
141
math.h
Todas las funciones trigonomtricas estn en radianes.
double sin(double x)
Seno de x.
double cos(double x)
Coseno de x.
double tan(double x)
Tangente de x.
double asin(double x)
Inverso del seno en el rango de -pi/2 a pi/2.
double acos(double x)
Inverso del coseno de x en el rango de 0 a pi.
142
stdlib.h
int rand(void)
Devuelve un nmero pseudoaleatorio entre 0 y RAND_MAX, que suele ser
32767.
void srand(unsigned int seed)
Siembra una semilla para crear una nueva secuencia de nmeros
pseudoaleatorios usando a seed.
void *calloc(size_t nobj, size_t size)
Devuelve un apuntador al espacio para un arreglo de nobj objetos, cada uno de
tamao size. Regresa NULL si no puede encontrar el espacio, mismo que se
inicia con ceros.
void *malloc(size_t size)
Regresa un apuntador a un espacio de tamao size o NULL si no puede hacerlo.
void realloc(void *p, size_t size)
Cambia el tamao del objeto al que apunta p, si la llamada es efectiva realloc
regresa el apuntador al espacio nuevo, si no regresa NULL, en este caso p no
cambia.
void free(void *p)
Libera el espacio a donde apunta p, debe ser un espacio asignado por malloc,
calloc o realloc.
void exit(int estado)
Termina el programa y regresa al invocador mandndole el estado de salida, el
estado de salida depende del sistema.
int system(const char *s)
Pasa la cadena al entorno para que la ejecute, el valor de regreso depende de el
sistema.
144
assert.h
void assert(int exp)
Se usa para buscar errores en los programas, cuando la expresin exp vale 0
assert interrumpe el programa y luego imprime la expresin que fallo, el nombre
del archivo donde se encuentra dicha expresin y el nmero de linea donde se
interrumpi el programa.
time.h
La librera time.h tiene funciones para manipular la hora del sistema. La
estructura struct tm tiene los componentes del calendario.
int tm_sec; segundos despus del minuto (0-59)
int tm_min; minutos despus de la hora (0-59)
int tm_hour; horas despus del a medianoche (0-23)
int tm_day; dia del mes (1-31)
int tm_mon; meses desde enero (0-11)
int tm_year; aos desde 1900
int tm_wday; dias desde el domingo (0-6)
int tm_yday; dias desde enero 1 (0-365)
int tm_isdst; bandera de "daylight saving time"
time_t time(time_t *tp)
Regresa la hora y la fecha actual, regresa -1 si el tiempo no est disponible. Si
tp no es NULL el valor de retorno se le asigna a tp.
char *asctime(const struct tm *tp)
145
148
Se le
#endif
Fin del if.
/* fin de config.h */
/* archivo main.h */
#include "config.h"
Incluye el archivo de configuracin
#if N
Si N vale 1 incluye el archivo d.h y asigna
#include "d.h"
0 a SIS.
#define SIS 0
#else
De lo contrario incluye el archivo u.h y asigna
#include "u.h"
1 a SIS.
#define SIS 1
#endif
Fin del if.
151
152
153