Blag/content/posts/003-tipos-de-dato.md

5.7 KiB

title date draft weight
Tipos de dato. 2022-01-24T20:32:57+01:00 false 3

C es un lenguaje tipado, lo que implica que cada vez que quieras crear una variable tienes que especificar su tipo de dato.

Aquí veremos unos cuantos útiles en el día a día programando en C.

Tipos de datos básicos.

Considero tipos de datos básicos a aquellos que no se pueden usar para crear estructuras de datos:

int: Almacena un número de 32 bits.

long int: Varía entre arquitecturas y sistemas operativos, en GNU/Linux de 64bits almacena un número de 64 bits, en GNU/Linux de 32 bits almacena un número de 32 bits.

long long int: Almacena un número de 64 bits.

unsigned int: Almacena un número de 32 bits sin signo, lo que implica que tiene un bit más para poder extenderse hacia el lado de los números positivos.

unsigned long int: ...

size_t: Almacena un número tan grande como el tamaño máximo de las estructuras de datos en el sistema operativo. (En GNU/Linux unsigned long int);

char: Almacena un carácter. (8 bits) Los carácteres utf-8 que conocemos pueden extenderse por más de un char de C.

Tipos de datos compuestos.

array: Un array es una estructura de datos compuesta que te permite tener varios datos del mismo tipo dentro del mismo. Ejemplo:

#include <stdio.h>

int
main (int argc, char **argv) {
    char hola[] = { 'h', 'o', 'l', 'a', '\0' };
    printf ("%s\n", hola);
}

struct: Un struct te permite almacenar varios tipos de datos dentro de una única variable. Ejemplo:

#include <stdio.h>

struct prueba {
    int numero;
    char *string;
};

int
main (int argc, char **argv) {
    char hola[] = { 'h', 'o', 'l', 'a', '\0' };
    struct prueba prueba = {
        42,
        hola
    };
    printf ("%d %s\n", prueba.numero, prueba.string);
}

C nos otorga fácilidades para trabajar con structs por ejemplo si prueba fuese un puntero struct prueba * podríamos acceder a los tipos de datos internos con prueba->numero en lugar de tener que dereferenciar el puntero. Ejemplo:

#include <stdio.h>

struct prueba {
    int numero;
    char *string;
};

int
main (int argc, char **argv) {
    char hola[] = { 'h', 'o', 'l', 'a', '\0' };
    struct prueba prueba = {
        42,
        hola
    };
    struct prueba *pruebaPtr = &prueba;
    printf ("%d %s\n", (*pruebaPtr).numero, (*pruebaPtr).string);
}
#include <stdio.h>

struct prueba {
    int numero;
    char *string;
};

int
main (int argc, char **argv) {
    char hola[] = { 'h', 'o', 'l', 'a', '\0' };
    struct prueba prueba = {
        42,
        hola
    };
    struct prueba *pruebaPtr = &prueba;
    printf ("%d %s\n", pruebaPtr->numero, pruebaPtr->string);
}

Punteros

Cuando un tipo de dato compuesto va a vivir más que la función es muy conveniente que el mismo sea un puntero, veremos como alocar memoria para un puntero y como trabajar con el. Ejemplo:

#include <stdio.h>
#include <stdlib.h>

struct prueba {
    int numero;
    char *hola;
};

struct prueba *
create_struct_prueba_allocated (char *hola) {
    struct prueba *prueba = malloc (sizeof *prueba);

    prueba->numero = 42;
    prueba->hola = hola;

    return prueba;
}

char *
create_array_hola_allocated (size_t *hola_len) {
    char hola[] = { 'h', 'o', 'l', 'a', '\0' };
    size_t hola_to_return_len = sizeof hola;
    char *hola_to_return = malloc (hola_to_return_len * sizeof *hola_to_return);   

    for (size_t i = 0; i < hola_to_return_len; i++) {
        hola_to_return[i] = hola[i];
    }

    if (hola_len) {
        *hola_len = hola_to_return_len;
    }

    return hola_to_return;
}

int
main (int argc, char **argv) {
    size_t hola_len = 0;
    char *hola = create_array_hola_allocated (&hola_len);
    struct prueba *prueba = create_struct_prueba_allocated (hola);
    printf ("%d %s\n", prueba->numero, prueba->hola);

    free (hola);
    hola = NULL;
    free (prueba);
    prueba = NULL;
}

Notas:

  • sizeof solo se puede usar en un array en la función que ha sido creado, por eso exportamos su tamaño como un puntero aunque en este caso no lo usemos.

  • & Convierte una variable en un puntero.

  • * Detras de un puntero lo dereferencia.

  • free Para evitar malgastar memoria deallocamos la memoria tras usarla.

  • malloc Al allocar un array multiplicamos su tamaño por el tamaño del tipo de dato que contiene. Ejemplo:

char *array = malloc (42 * sizeof char);

O

char *array = malloc (42 * sizeof *array);

Enums

Un enum te permite darles nombres a listas de numeros, por ejemplo:

#include <stdio.h>
#include <stdlib.h>

typedef enum {
    COLOR_CYAN = 1,
    COLOR_VERDE = 2,
    COLOR_AMARILLO = 4
} Color;

struct prueba {
    int numero;
    char *hola;
    Color color;
};

struct prueba *
create_struct_prueba_allocated (char *hola) {
    struct prueba *prueba = malloc (sizeof *prueba);

    prueba->numero = 42;
    prueba->hola = hola;
    prueba->color = COLOR_CYAN;

    return prueba;
}

char *
create_array_hola_allocated (size_t *hola_len) {
    char hola[] = { 'h', 'o', 'l', 'a', '\0' };
    size_t hola_to_return_len = sizeof hola;
    char *hola_to_return = malloc (hola_to_return_len * sizeof *hola_to_return);   

    for (size_t i = 0; i < hola_to_return_len; i++) {
        hola_to_return[i] = hola[i];
    }

    if (hola_len) {
        *hola_len = hola_to_return_len;
    }

    return hola_to_return;
}

int
main (int argc, char **argv) {
    size_t hola_len = 0;
    char *hola = create_array_hola_allocated (&hola_len);
    struct prueba *prueba = create_struct_prueba_allocated (hola);
    printf ("%d %d %s\n", prueba->numero, prueba->color, prueba->hola);

    free (hola);
    hola = NULL;
    free (prueba);
    prueba = NULL;
}