19 de febrero de 2018

Tipo de Datos.

Cada tipo de datos es un álgebra que consta de dos elementos:

  • Un conjunto de posibles valores que el tipo de datos puede tomar.
    • Por ejemplo, el tipo de dato char toma valores numéricos enteros entre 0 y 255.
  • Un conjunto de operaciones aplicables al tipo de datos en cuestión.
    • Por ejemplo, para char tenemos definidas las operaciones aritméticas (+,-,*,/,…), además de otras funciones como lo son printf y scanf.

Formalmente:

Formalmente, un tipo de datos es la pareja \(\langle V, O \rangle\) donde

  • \(V = \{x | x \text{ es un valor válido }\}\)
  • \(0 = \{f | f \text{ es un operador (o función) definida sobre }V\}\)

Tipo de Dato Abstracto.

Usando los tipos de datos primitivos como base, C (y otros lenguajes de programación) nos dan la opción de definir nuevo tipos de datos. Estos son llamados tipo de dato abstracto (TDA, abstract data type (ADT)) y son, en pocas palabras nuevos data types definidos por el programador.

Al definir un TDA, el programador tiene la responsabilidad de definir los valores que este puede tomar, así como las funciones para poder operar en el.

  • "Un tipo de dato abstracto (TDA) es un conjunto de datos u objectos creado de manera personalizada por un prograamador para un fin específico". (Guía práctica de estudio 03, Tipo de dato abstracto).

Estructuras.

En el lenguaje C, la declaración de tipo de datos abstractos se da por medio de estructuras (struct). Estas tienen la forma

  struct nodo{
       tipo1 elemento1;
       tipo2 elemento2;
       ...
       tipoN elementoN;
  };

Una véz definido el nuevo tipo, este se puede usar al declarar una variable de tipo de la estructura de la siguiente forma:

  struct nodo nombreVariable;

Ejemplo:

La forma correcta de programar una función que regrese varias variables de diferentes tipo es por medio de una estructura.

#include <stdio.h>

struct alumno{
    int noCuenta;
    char *nombre;
    float promedio;
};

struct alumno leeAlumno(int noCuenta);

void imprimeAlumno(struct alumno al);
    

Ejemplo, pt. 2:

int main()
{
    int noCu = 0;
    char *hola;
    struct alumno almn; 

    almn = leeAlumno(noCu);
    
    imprimeAlumno(almn);
    
    return 0;
}

Ejemplo, pt. 3:

struct alumno leeAlumno(int noCuenta){

    struct alumno salida;
   
    salida.noCuenta = noCuenta;
    salida.nombre = "Santiago Hernandez Orozco\0";
    salida.promedio = 8.49;
    
    return salida;
}

void imprimeAlumno(struct alumno al){
    printf("El alumno %s saco %.2f\n", al.nombre, al.promedio);
}

Ejemplo, Salida:

Estructuras, punteros y memoria.

El operador -> se usa para acceder a los miembros de una estructura usando un puntero a esta.

Analicemos el siguiente código:

#include <stdio.h>

struct arreglo{
    char n1;
    char n2;
    int n3;
    int n4;
};

Parte 2

int main(){
    char *c;
    int *i;
    struct arreglo foo, *bar;
    foo.n1 = '@';
    foo.n2 = 'A';
    foo.n3 = 256;
    foo.n4 = 512;
    
    bar = &foo;
    
    printf("%c, %c\n",(*bar).n1, bar ->n2);
    printf("%p, %p, %p\n", &foo, &(foo.n1), &(bar->n2));  
    
    c = bar;
    
    printf("%c\n", *(c+1));

Parte 3

    i = &foo.n3;
    
    //'Pading' o relleno de + 4.
    printf("%p, %p, %d\n", i, c+4, *i);
    
    printf("%p, %d\n", (i+1), *(i+1));
    
    return 0;
}

Salida: