0x08 PROGRAMACIÓN en C (I)
0x08
===============================================================
Numero del articulo: 08-1
A cargo de: Ghe Rivero <gherivero@cycjak.com>
Titulo: PROGRAMACIÓN en C (I)
Nivel de Hack: Bajo
===============================================================
Pos como el mismo título lo indica, vamos a empezar un pequeño cursillo sobre la programación en C. Muchos de vosotros diréis que es un poco básico, pero por algo hay que empezar.
Tras los primeros capítulos (unos tres o cuatro) nos meteremos en temas más serios, y analizaremos tantos nukes existentes, como firewalls, bugs, virus, y como programar todas esas cosas por nosotros mismos (Los que quieran avanzar más rápidamente hasta llegar a esa parte, que envíen mails con sus propios programas ya comentados).
Y como no tengo nada más que deciros, vamos allá.
1.- Introducción.
Durante este cursillo, vamos a tomar como estándar el Turbo C, programa que todo el mundo debería haber llegado a usar. Todos los ejemplos y códigos estarán en base a ese entorno. Más adelante, haremos referencias a las diferencias entre el resto de entornos como Visual C++ y Borland C++ principalmente (Y programaremos en C++, por supuesto).
2.- "Hola mundo".
Y como no iba a ser menos, empezamos como siempre se ha hecho, con el programa hola mundo, quizá esta parte sea la má pesada, pero en algún sitio tenía que meter toda la teoría de funcionamiento (Cosa que nunca está mal saber).
////////////////////HOLA.C\\\\\\\\\\\\\\\\\\\\
#include <stdio.h>;
void main (void)
{
printf("Hola mundo"); /*Comentarios*/
}
///////////////////////\\\\\\\\\\\\\\\\\\\\\\\
Y ahora viene toda la explicaión teórica...
-#include <stdio.h>
La síntasix #include <loquesea.h>, indica al compilador que debe utilizar las librerías indicas para la obtención del código (No voy a explicar que son las librerías ni como funcionan)
-void main (void)
Esta función no debe de faltar nunca en ningún programa de C, pues es la función principal. El primer void indica que la función no devue´lve ningún parámetro, y el segundo void, el que está encerrado, indica los parámetros que se le pasan a la función. (Esto se verá más adelante)
-{....}
Las llaves sirven para encerrar bloques de programa que tienen algo que ver entre sí
-printf("Hola mundo");
Indica que se imprima la línea "hola mundo" en pantalla.
Dada una pequeña introducción, indicaremos lo que vamos a hacer en este artículo.
Constantes y variables.
- 1.2) Tipos de datos en C.
- 2.2.I) Simples.
- 2.2.II) Conversion de tipos.
- 2.2.III) Estructuras de datos.
- 1.3) Entrada y salida por consola.
- 1.3.I) La funcion printf()
- 1.3.II) la funcion scanf()
- 1.3.III) Otras funciones de entrada-salida.
- 1.4) Tipos de variables
- 1.4.I) Variables locales globales.
- 1.4.II) Variables y variables de registro.
- 1.5) Sentencias de asignacion.
- 1.5.I) Operadores.
- 1.5.II) Orden de evaluacion de los operadores.
1.1) Constantes y variables.
Las constantes, como su nombre indica, son objetos cuyo valor permanece invariable a lo largo la ejecucion de un programa. Los ejemplos mas comunes son los valores de PI y de e.
Por el contrario son variables aquellos objetos cuyo valor puede cambiar a lo largo de un programa. El lenguaje C utiliza estos objetos para realizar todo tipo de operaciones tanto aritmeticas como logicas o de caracteres, antes de ser usadas las variables deben necesariamente ser declaradas.
Para denominar a las variables en C se pueden utilizar los numeros, las letras, tanto mayusculas como minusculas, y algunos caracteres especiales estan admitidos aunque no se recomienda usar mas que el de subrayado (_). El nombre de la variable esta limitado a 8 caracteres aunque Turbo C puede permitir hasta 32 caracteres (se puede programar esta longitud).
1.2) Tipos de datos en C.
Las constantes y variables son los objetos basicos que se manipulan en un programa en C. En las declaraciones se indican las variables que se van a utilizar y establecen su tipo y en algunos casos se fija un valor inicial.
1.2.I) Simples.
Los tipos de datos basicos en C son:
- Char Capaz de contener un caracter del juego de caracteres.
- int Un entero.
- float Un numero en coma flotante de precision normal.
- double Un numero en coma flotante de doble precision
En C es obligatorio que todas las variables se declaren antes de ser utilizadas, en la declaracion se especifica el tipo de variable pudiendo poner detras una lista de una o mas variables de ese tipo, por ejemplo:
int a, pepito, x, contador;
char m, pepe[50];
float valor1, valor 2;
Ademas de los tipos basicos, existen unos calificadores que se aplican a los enteros: short, long y unsigned. Los dos primeros se refieren a tama¤o de los numeros y el ultimo especifica que el numero no tendra signo y por lo tanto sera positivo, por ejemplo:
short int a, b, c;
long int x, y, z;
unsigned int m, n, o;
En estas ultimas declaraciones se puede omitir la palabra int, aunque nunca debemos olvidar terminar la sentencia con el punto y coma ;
El tamaño de estos tipos de variables en la memoria depende del tipo de ordenador con el que trabaje, en general el tamaño de una variable int se corresponde con el tamaño de la palabra hardware del ordenador. Asi si utilizamos un microprocesador de 16 bits el tamaño sera de 16 bits.
En el cuadro que se ve al lado, podemos apreciar el tamaño de los tipos basicos para el IBM PC. Asi como el rango de valores que pueden tomar estas variables.
Char 8 bits Un caracter.
int 16 bits -32768 a +32767
short 16 bits -32768 a +32767
long 32 bits -2* 109 a 2 * 109
float 32 bits ñ 10-37 a ñ 10+38
double 64 bits ñ 10-307 a ñ 10+308
Si queremos conocer el tamaño de una variable para un ordenador especifico se puede utilizar el operador de C sizeof() incluyendo entre los parentesis el nombre de la variable.
Ademas de lo anterior es posible definir punteros a una variable de un tipo. Un puntero es una variable que contiene una direccion de memoria. Para declarar los punteros se indica el tipo de variable al que apuntara y el nombre del puntero precedido del simbolo asterisco (*), por ejemplo:
int *pun; /* Es un puntero a un entero */
int var; /* Es una variable entera */
En C todos los caracteres incluidos entre /* y */ son tomados como comentarios.
Cuando el contenido de un puntero es la direccion de una variable, se dice que el puntero apunta a la variable. Para conocer la direccion de memoria de una variable se utiliza el operador &. De forma para hacer que punt apunte a var se haria:
Punt = &var;
1.2.II) Conversion de tipos.
A) Conversiones implicitas.
Si en un programa C nos encontramos con los siguiente:
int x, y;
float z;
y = x + z
¿Como se comportaria el programa en cuanto a los valores a considerar?. La respuesta es simple el compilador realizara una conversion de tipos. Y en este caso el operador de tipo mas peque¤o se convierte al mayor antes de ejecutar la operacion, por lo tanto el resultado sera del tipo float. A este tipo de conversion se la conoce como conversion implicita.
Ademas de la conversion implicita hay que tener en cuenta:
- Todos los valores float de una expresion se convierten en double, por lo que toda la aritmetica de coma flotante en C se realiza en doble precision.
- No estan permitidas las expresiones que van contra la sintaxis del lenguaje; por ejemplo utilizar como subindice una variable de tipo float.
- Los operandos de tipo char de una expresion aritmetica se convierten automaticamente en int.
Las conversiones tambien pueden realizarse en las asignaciones. En este caso, el valor de la parte derecha se convierte al tipo de la izquierda, que es el tipo del resultado.
Cuando en una asignacion, la conversion ha de hacerse entre dos tipos numericos, puede ocurrir:
- De float a int se produce el truncamiento de la parte fraccionaria.
- De double a float se produce un redondeo (depende del compilador).
- Los enteros long se convierten tipo short o en caracteres (char) eliminando los bits de orden superior.
B) Conversiones explicitas.
Se puede realizar una conversion explicita de tipo, es decir, forzar una conversion a los valores deseados por nosotros, mediante un sentencia denominada casting, y que tiene la siguiente sintaxis:
(Nombre_de_tipo) expresion;
Donde la expresion se convierte al tipo expresado entre parentesis.
1.2. III) Estructuras de datos.
Ademas de los tipo basicos, podemos necesitar de tipos mas complejos. Para ello se utiliza la palabra reservada struct . Podemos definir estructura como una agrupacion de variables que pueden ser de igual o distinto tipo bajo un nombre unico. A las diferente variables que constituyen la estructura se les denominan miembros o campos.
Ejemplo:
struct fecha {
Int dia;
Int mes;
Int anno;
};
La mayor ventaja de las estructuras de datos es la facilidad de manejo. Para acceder a cada una de las variables se pone:
nombre de la variable + "." + nombre del miembro
Ejemplos:
struct fecha cumple;
cumple.dia = 15;
cumple.mes = 8;
Las declaraciones de estructura pueden estar anidadas, por ejemplo:
struct agenda {
char nombre[25];
struct fecha cumple;
};
El acceso a los miembros se realiza de la misma forma que en la estructura simple, indicando mediante puntos los diferentes campos.
1.3) Entrada y salida por consola.
1.3.I) La funcion printf().
Esta funcion permite imprimir una cadena de caracteres sobre la pantalla del ordenador. Esta funcion esta definida en la biblioteca stdio (standard input output), por lo que hay que incluir el archivo stdio.h mediante la directiva de precompilacion #include <stdio.h> si se desea utilizar en un programa. La forma generica de printf() es:
printf("formato de argumentos", lista de argumentos);
La cadena con el formato de argumentos es una expresion encerrada entre comillas donde se pueden incluir:
- a) Mensajes que queremos que salgan por pantalla.
- b) Conversion de variables que iran precedidas por el signo %.
- c) Caracteres de control. (Precedidos por el simbolo \)
En la lista de los argumentos, estos apareceran separados por comas.
Algunos de los comandos admitidos en la funcion printf() son:
Comando Tipo de argumento
%c Caracter
%d Decimal
%e Notacion cientifica.
%f Decimal en coma flotante
%g Usar %e %f, el que resulte mas corto
%o Octal
%s Cadena de caracteres
%u Decimal sin signo
%h Hexadecimal
%i Entero
Caracteres Significado
\n Produce un retorno de linea.
\t Produce una tabulacion horizontal.
\0 Nulo. Para fin de cadena.
\\ Indica la barra invertida.
\' Para escribir una comilla.
En la cadena de formato se pueden incluir tanto caracteres a imprimir como comandos. Los comandos de formato pueden ir en cualquier parte dentro de la primera cadena de caracteres, por ejemplo:
("Hoy es %i de Octubre de %i ", 30, 1998)
1.3.II) La funcion scanf().
La funcion scanf() es la contraria a printf(): permite leer los datos desde la entrada estandar, generalmente el teclado y según el formato que sigue:
scanf ("formato", lista de argumentos);
La diferencia esta en que printf() recibe los valores de los argumentos por valor, es decir, que al terminar la ejecucion siguen igual, mientras que scanf() los debe recibir por referencia para poder rellenarlos con los valores leidos.
Hasta que veamos el paso de parametros mas adelante podemos decir que una variable se pasa por referencia cuando va precedida del operador &. Por ejemplo:
scanf ("%i", &numero);
Igual que ocurria con printf(), cada elemento de la lista de argumentos debe tener su especificacion en el formato y se utilizan las mismas especificacion que para print() salvo %h que se utilizara ahora para indicar el valor de los enteros short.
1.3.III) Otras funciones de entrada y salida.
La funcion getchar() es mucho mas sencilla que las anteriores, devuelve el caracter leido en forma de entero sin signo.
La funcion putchar() es simetrica a getchar(), tiene un solo argumento que es el caracter que se imprimira.
La funcion getch() lee un caracter sin que aparezca en pantalla.
La funcion getche() lee un caracter visualizandolo en pantalla.
La funcion gets() lee una cadena de caracteres.
La funcion puts() escribe una cadena de caracteres.
Sin que sea una funcion del grupo clrscr() borra la pantalla del ordenador.
Los ejercicios 7 y 8 de este articulo repasan estas funciones.
1.4) Tipos de variables.
1.4.I) Variables locales, globales.
Las variables declaradas en la parte principal del programa, la funcion main, son privadas de esa función, es decir son variables locales de la funcion main, por lo que ninguna otra funcion del programa puede tener acceso a ellas.
Las variables locales, tambien llamadas automaticas, comienzan a existir cuando se llama a la funcion, y desaparecen cuando se acaba la funcion. Para asegurar el contenido de una variable se deben inicializar, darle un valor inicial, ya que si no es así tomaran un valor indeterminado.
Al contrario que las anteriores, se pueden definir variables globales, externas a todas las funciones. Cualquier funcion del programa puede utilizarla sin mas que usar su nombre. Usar en los programas muchas variables globales va en contra de la programacion estructurada.
1.4.II) Variables estaticas y variables de registro.
Las variables estaticas son aquellas que permanecen y siguen manteniendo su valor cuando se pasa de una funcion a otra. Puede ser locales o globales, las primeras son privadas de una funcion mientras que a las segundas se puede acceder desde cualquier parte del programa en que fueron declaradas.
Si una variables es estatica, local o global, se especifica en la declaracion con la palabra static. La variables es estatica global si se define fuera de las funciones y estatica local si se define dentro de una funcion.
Las variables de registro se declaran mediante la palabra reservada register. Las variables asi declaradas son consideradas como muy utilizadas. Por ello el compilador las situara en los registro de la maquina para que el acceso a las mismas sea muy rapido.
1.5) Sentencias de asignacion.
Hasta ahora y para los ejemplos anteriores hemos utilizado sentencias de asignacion en su formato mas sencillo. Estas sentencias tiene un significado diferente al sentido matematico que podria desprenderse de la formula. Asi:
b = b + c
No tiene sentido logico desde el punto de vista de las matematicas sin embargo si lo tiene en programacion, y significa que el resultado de la parte derecha de la formula debe asignarse a la variable que hay en la parte izquierda.
C utiliza mas practicas para asignar valores por ejemplo cuando en una asignacion el miembro izquierdo se repite en la derecha se puede suprimir el miembro repetido y juntar los dos operadores matematicos.
Por ejemplo:
b = b + c; es lo mismo que b += c;
a = a * (b + 2); es lo mismo que a *= (b + 2);
Con la asignacion en muchos casos lo que hace es inicializar una variable, o sea darle un valor inicial en el programa, pues bien, sobre este tema podemos decir que si no se inicializa expresamente una variable el lenguaje C garantiza que las externas y estaticas tendran inicialmente el valor cero. Sin embargo las variables automaticas y las de tipo registro toman valores indeterminados.
Las variables simples se inicializan (no vectores ni estructuras) con una sentencia de asignacion como las vistas, las externas se inicializan una sola vez, las automaticas y las de registro se inicializan cada vez que se ejecuta la funcion en la que estan declaradas.
Las variables pueden definirse y despues inicializarse o inicializarse en el mismo momento de la definicion (abreviado). Por ejemplo:
int var1, var2;
var1 = 15;
var2 = 20;
O en forma más abreviada:
int var1 = 15;
int var2 = 20;
1.5.I) Operadores.
En los ejercicios de los apartados anteriores hemos utilizado operadores sin definirlos previamente. Los vamos a agrupar en categorias:
A) Operadores aritmeticos.
Los operadores tradicionales son los que utilizan para la suma +, resta -, multiplicacion * y division /. Ademas se puede utilizar en C el operador modulo representado por el simbolo %. Este ultimo calcula el resto de la division entera de sus dos argumentos y no puede logicamente utilizarse mas que con variables enteras, nunca con float o double.
Ademas se puede utilizar el operador unario -, que se utiliza para indicar que un valor es negativo.
Para resolver el tema de la precedencia, o sea, en que orden se evaluaran los operadores se pueden utilizar en C los parentesis, ejecutandose en primer lugar los mas internos.
B) Operadores relacionales y logicos.
Los operadores relacionales y logicos son los que evaluan las siguientes expresiones:
> mayor < menor = = igual
>= mayor o igual <= menor o igual != distinto
&& conjuncion || disyuncion ! negacion
C) Operadores de incremento y decremento.
Los operadores de incremento y decremento son los que permiten aumentar o disminuir una variable contador. El lenguaje C dispone de dos operadores de este tipo:
- El operador de incremento ++ que aumenta uno a su operando.
- El operador de decremento -- que resta uno a su operando.
Los dos operadores se pueden operar como sufijos o como prefijos. Si se pone como sufijo, primero debe evaluar la expresion y despues incrementar la variables, mientras que si se usa como prefijo primero se incrementa la variables y despues se evalua la expresion:
int a, b; int a, b;
a = 1; a = 1;
b = a ++; b = ++ a;
printf ("a = %i b = %i" , a , b);
printf ("a = %i b = %i" , a , b);
En ambos casos la variable a toma el valor 2 pero en el primer caso lo se imprime es b = 1 y en segundo caso b = 2. El ejercicio 9 muestra el resultado.
D) Operadores para el manejo de bits.
Para el manejo de bits el lenguaje C cuenta con los siguientes operadores:
& AND logico para bits.
| OR a nivel de bits.
^ XOR (OR exclusivo) a nivel de bits.
<< Desplazamiento a la izquierda.
>> Desplazamiento a la derecha.
~ Complemento a uno.
El manejo de estos operadores lo veremos mas adelante.
E) Operador condicional.
Es este un operador que simplificando la escritura del programa fuente, su sintaxis hace difíciles las correcciones de los programas. La sintaxis es:
expresion1 ? expresion2 : expresion3
Se evalua la expresion1, y si el resultado es distinto de cero (TRUE), se evalua la expresion2 y el resultado de esta segunda evaluacion sera el resultado del operador. Si por el contrario el resultado de la primera evaluacion es igual a cero (FALSE) el resultado del operador sera el que se obtenga al evaluar expresion3.
maximo=(a>b) ? a : b ; /* equivale a que a es el máximo de a y b */
minimo=(a<b) ? a : b ; /* equivale a que a es el mínimo de a y b */
Comprobar el resultado en el ejercicio 10.
1.5.II) Orden de evaluacion de los operadores.
En el cuadro que viene a continuacion pueden observarse todos los operadores que reconoce el lenguaje C (algunos todavia no vistos) y estan ordenados segun su precedencia, o sea, segun el orden de ejecucion de los mismos cuando aparecen juntos en una expresion.
( ) [ ] -> . De izquierda a derecha.
! ~ ++ -- (tipo) * & sizeof De derecha a izquierda.
* / % De izquierda a derecha.
+ - De izquierda a derecha.
<< >> De izquierda a derecha.
< <= > >= De izquierda a derecha.
== != De izquierda a derecha.
& De izquierda a derecha.
^ De izquierda a derecha.
| De izquierda a derecha.
&& De izquierda a derecha.
| | De izquierda a derecha.
?: De derecha a izquierda.
= += -= *= /= De derecha a izquierda.
, De izquierda a derecha.
Como puede observarse el operador de maxima prioridad son los parentesis. Esto implica que en cualquier expresion se puede cambiar el orden natural de evaluacion sin mas que colocar parentesis en los lugares deseados.
No obstante a lo anterior y aunque no las hemos visto, C no garantiza el orden de evaluacion si los operandos son funciones, en muchos casos sera conveniente reescribir el codigo fuente separando en lineas diferentes los operandos que puedan estar interrelacionados.
Ahora, llegamos a la parte practica. Eso para que digais que todo esto no se esta explicando facil. Espero que los ejercicios que hay a continuacion os ayuden a practicar toda la teoria.
EJERCICIOS
Ejercicio 1.
/* Esto es un comentario */
#include<stdio.h>
main ()
{
printf("Este es mi primer programa");
}
Ejercicio 2.
/* Segundo ejercicio del primer articulo */
#include<stdio.h>
main()
{
int n1;
float n2;
n1=35;
n2=24.678;
printf("%i es un numero entero y %f uno con decimales", n1, n2);
}
Ejercicio 3.
Modificar el ejercicio 2 cambiando los comandos de presentacion de los datos.
Ejercicio 4.
/* programa que calcule el area de un triangulo */
#include<stdio.h>
float entero1, entero2, entero3;
main()
{
printf("\n Dame un numero por favor: ");
scanf("%f", &entero1);
printf("\n Dame un segundo numero: ");
scanf("%f", &entero2);
entero3 = entero1 * entero2;
entero3 = entero3 / 2;
printf("\n El area del triangulo es: %f\n",entero3);
}
Ejercicio 5.
Hacer un programa que calcule la longitud de una circunferencia partir del tamaño del radio que se pedira por teclado. Definir como una constante el valor de PI = 3.14159
Ejercicio 6.
Hacer un programa que calcule la media aritmetica de 3 numeros que se introducen por teclado. Borrar pantalla antes de empezar y detener el programa al final para poder ver el resultado.
Ejercicio 7.
/* prueba de las funciones getchar, putchar, getch y getche */
#include <stdio.h>
main()
{
char x, cadena;
clrscr();
printf("Pulsa una tecla y enter .. despues la veras \n");
x = getchar();
putchar (x);
printf("\nPulsa una tecla.. no la veras \n");
getch();
printf("Pulsa una tecla.. esta vez si la veras\n");
getche();
/* esto es solo una pausa hasta que pulses una tecla */
getch();
}
Ejercicio 8.
/* prueba de gets y puts */
#include <stdio.h>
main()
{
char x, cadena;
clrscr();
printf("\nPulsa una cadena.. \n");
gets (cadena);
printf("La cadena es .. : ");
puts (cadena);
/* esto es solo una pausa hasta que pulses una tecla */
getch();
}
Ejercicio 9.
/* Uso de ++ */
#include <stdio.h>
main()
{
int a, b;
clrscr();
a = 1;
b = a ++;
printf ("a = %i b = %i" , a , b);
a = 1;
b = ++ a;
printf ("\na = %i b = %i" , a , b);
/* pausa */
getch();
}
Ejercicio 10.
/* Uso del operador condicional */
#include <stdio.h>
main()
{
int a, b, maximo, minimo;
clrscr();
printf ("\n Dame un numero por favor: ");
scanf("%i", &a);
printf ("\n Dame otro numero: ");
scanf("%i", &b);
maximo = (a > b) ? a : b ; /* equivale a que a es el maximo de a y b*/
minimo = (a < b) ? a : b ; /* equivale a que a es el minimo de a y b*/
printf ("\n maximo = %i minimo = %i" , maximo ,minimo);
/* pausa */
getch();
}
Bueno, esto es todo por ahora. Siento no haber sido todo lo claro posible, pero estoy liado con un manual serio sobre C, que espero poder daros en un par de meses. Hasta otra.