domingo, 7 de noviembre de 2010

LENGUAJES IMPERATIVOS - Generalidades C

Laboratorio de Lenguajes de Programación - Semana 8

Todos conocemos a este lenguaje, considerado el mas importante hasta la fecha y quien a influenciado a una gran cantidad de lenguajes de programación.

A pesar de que es viejo, es muy apreciado por su la eficiencia del código que produce.
Se trata de un lenguaje débilmente tipificado de medio nivel pero con muchas características de bajo nivel. Dispone de las estructuras típicas de los lenguajes de alto nivel pero, a su vez, dispone de construcciones del lenguaje que permiten un control a muy bajo nivel. Los compiladores suelen ofrecer extensiones al lenguaje que posibilitan mezclar código en ensamblador con código C o acceder directamente a memoria o dispositivos periféricos.

Podemos mencionar entre sus principales caracteristicas:

* Un núcleo del lenguaje simple, con funcionalidades añadidas importantes, como funciones matemáticas y de manejo de archivos, proporcionadas por bibliotecas.
* Es un lenguaje muy flexible que permite programar con múltiples estilos. Uno de los más empleados es el estructurado "no llevado al extremo" (permitiendo ciertas licencias de ruptura).
* Un sistema de tipos que impide operaciones sin sentido.
* Usa un lenguaje de preprocesado, el preprocesador de C, para tareas como definir macros e incluir múltiples archivos de código fuente.
* Acceso a memoria de bajo nivel mediante el uso de punteros.
* Interrupciones al procesador con uniones.
* Un conjunto reducido de palabras clave.
* Por defecto, el paso de parámetros a una función se realiza por valor. El paso por referencia se consigue pasando explícitamente a las funciones las direcciones de memoria de dichos parámetros.
* Punteros a funciones y variables estáticas, que permiten una forma rudimentaria de encapsulado y polimorfismo.
* Tipos de datos agregados (struct) que permiten que datos relacionados (como un empleado, que tiene un id, un nombre y un salario) se combinen y se manipulen como un todo (en una única variable "empleado").

Con base a el han surgido otros lenguajes como C++, C#, Objective-C; que se consideran extensiones del mismo para proporcionarle programacion orientada a objetos.

PREPARACIÓN

El sistema operativo UBUNTU incluye el compilador de este lenguaje, su nombre es gcc, para verficar la existencia de este compilador podemos teclear en la terminal

gcc: lo que mostrara un mensaje como este, es una respuesta de la llamada que ejecutamos al compilador, lo que indica que esta instalado y preparado.



LO BÁSICO

En C, las variables se declaran de una forma clara y directa, algunas de ellas pueden ser de los tipos:

char: Caractér del ANSI C
int: Entero
float: Número con punto flotante
double: Número con precisión doble
bool: Lógico

Para su declaración se tiene la siguiente sintaxis:

TipoVariable nombre1, nombre2, ..., nombreN;

Por ejemplo:

char nombre;
int suma;
float pi;
double euler;

Existen también palabras reservadas que no podemos utilizar al momento de escribir nuestro código tales como if, for, while, do, else, break, main, void, return, etc.

Las variables pueden ser locales, y declararse dentro de la función donde vayan a ser utilizadas, con ello solo estaran disponibles para un solo proceso; sin embargo, tambien pueden ser globales y declararse fuera de una funcion, mas especificamente despues de declarar las librerias que han de anclarse al codigo.

ESTRUCTURA DEL CODIGO

Para estructurar un codigo en C, se sigue el siguiente esqueleto:
#include <stdio.h>
#include <libreria.h>
...
#define CONSTANTE
...

tipo variable global;

tipo funcion1 (tipo variable1, tipo variable2) {
  ...;
  procesos;
  ...;
  return;
}

tipo funcionn (...) {
 ...;
}

int main (int argc, char *argv[]) {
  ...;
  procesos;
  ...;
  return 0;
}


Esto es muy general, y algunas parte pueden omitirse o ampliarse dependiendo de la extensión de nuestro programa.

La funcion siempre lleva su tipo, su nombre y entre parentesis los argumentos que recibirá, posteriormente el alcance de la función se limita a un par de corchetes dentro de ellos va el proceso de la función, varias funciones pueden unirse y llamarse entre si para aumentar sus capacidades, el programa siempre terminará cuando se llegue al return 0 de la funcion main.

CICLOS

Son llamados tambien Secuencias de Control, un buen programa debe combinarlas de manera eficiente para lograr un objetivo, nos ayudan a:

- Ejecutar varias veces una secuencia de instrucciones
- Repetir una instruccion.
- Decidir entre alternativas.

Un ciclo if nos ayuda a evaluar una condición y alternar entre dos caminos o mas a seguir:


Su forma general:
...
if(expresion) {
  enunciado1;
} else {
  enunciado2
}
...

Cuando la expresión dentro del parentesis es evaluada como verdadera el enunciado 1 se ejecutara; se der falsa se procedera con la ejecucion del enunciado 2.

Un ciclo for nos sirve para repetir un bloque n cantidad de veces hasta alcanzar un limite determinado, hasta obtener un objetivo, encontrar un resultado, etc.


Es de la forma general:
...
for(expresion1; expresion2; expresion3) {
  ...
  proceso
  ...
}

En la expresion1 se declara el inicio del ciclo, en la expresion2 el limite a alcanzar, la expresion3 marcara si la expresion1 aumenta o disminuye su valor en n cantidad de pasos; mientras de alcanza el limite de la expresion3 el proceso se repetira.

Un ciclo while nos ayuda a evaluar un dato, y mientras ese dato no corresponda con la condicion predeclarada, el ciclo se repetira indefinidamente.


Es de la forma general:
...
while (condicion) {
  ...
  proceso
  ...
}
...

Son utilizadas paa generar pequenas pausas en el sistema, mientras se espera que el usuario proporcione determinada respuesta, tambien puede adaptarse y usarse indistintamente a un ciclo for.

Una sentencia switch nos ayuda a disernir entre varios caminos a seguir, a cada camino le corresponde un proceso completamente individual.


Son de la forma general:
...
switch(expresion entera) {
  case constante1:
      ...
      proceso1
      ...
  case constante2:
      ...
      proceso2
      ...
  case constanten:
      ...
      proceson
      ...
  default :
      ...
      predeterminado
      ...
}
...


Nos ayuda mas que nada a minimizar el uso de sentencias if... else... if lo que es un beneficio al momento de escribir codigos largos.

Dentro se las secuencias se pueden agregar las palabras reservadas continue y break

continue: causa que el resto de una iteración sea saltada y se prosiga con la ejecución de la siguiente.
break: causa la salida del ciclo para comenzar con la siguiente parte del programa.

EJEMPLOS

Para darle mas alcance a esta entrada, y suponiendo que ya todos entendemos lo basico de C, les voy a mostrar como funcionan los punteros en C.

Un puntero, valga la redundancia, apunta a otro dato de su mismo tipo y su valor es la direccion de memoria de la otra variable. Hay que recalcar que una direccion de memoria no es igual al contenido de esa direccion de memoria

Para trabajar con punteros se utilizan 2 operadores especificos:

Operador de direccion "&": Representa la direccion de memoria.
Operador de contenido "*": Representa el valor asignado a la variable apuntada.

int x = 25;


La direccion de la variable x (&x) es 1502.
El contenido de la variable es 25.

En la actualidad las computadoras utilizan muchisima memoria para ejecutar diversos procesos, seria muy complicado tratar de indicarle al programa que dirección de memoria queremos visitar, es su lugar a cada dirección de memoria se le da una etiqueta, esta etiqueta la conocemos como variable; ya que lo que nos interesa es almacenar los datos que usaremos y no dónde se localizan.

Un puntero se declara como cualquier otra variable, pero su identificador va precedido por un asterisco (*):

int *puntero;

Incluso los punteros tienen sus propias direcciones de memoria: &puntero

Hay tantos tipos de punteros, como tipos de variables y estos pueden declararse dentro se estructuras complejas, funciones, ect.
...
char dato;
char *puntero;
puntero = &dato;
...


en la variable puntero guardamos la direccion de memoria de la variable dato. puntero apunta a dato, ambos del mismo tipo.

Para entenderlo mejor podemos teclear un pequeno codigo, abrimos la terminal y escribimos

emacs -nw puntero.c

despues tecleamos el siguiente codigo:
#include<stdio.h>
int main(int argc, char *argv[]) {

  int a = 20;
  int *b;

  printf("Direccion de a: %p\n", a);      // aqui muestra la direccion donde se guardo el valor de "a"
  printf("\nDireccion de b: %p\n", b);    // aqui muestra la direccion donde se guardo el valor del apuntador "b"
  printf("\nValor de a: %d\n", a);        // lo que se almaceno en "a"
  printf("\nValor de b: %d\n", b);        // lo que hay en "b" (basura)
  printf("\nDireccion de apuntador b: %p\n", *b);  // aqui esta la direccion donde se guardo el apuntador "b"
  printf("\nMemoria de a: %p\n", &a);     // se muestra la direccion donde se almaceno "a"
  b = &a;                                 //aqui se igualan direcciones
  printf("\nNueva memoria de b: %p\n", b);
  printf("\nNueva direccion de apuntador b: %p\n", *b);
  printf("\nValor de b: %d\n", b);
  return 0;
}


Para compilar tecleamos la secuencia: gcc -o puntero puntero.c.


Se generaran algunos warnings, pero el archivo sera completamente funcional.

Para ejecutar tecleamos: ./puntero



Hay pueden ver los espacios que la computadora reserva para almacenar "a" y el puntero "b", en las ultimas líneas pueden ver como las direcciones y los bloques de memoria del puntero "b" se igualan a los de "a", pero el puntero "b" sigue conteniendo basura.
Aqui le demuestro como es que un puntero no almacena el valor del bloque de memoria, solo su dirección.

Espero les haya sido útil la información, pueden consultarme cualquier duda.

SALUDOS!!! ^_^

1 comentario: