Programming-C

Tasks studies - laboratory

View project on GitHub

Lab08 - Unie, dynamiczna alokacja pamięci

Pytania

  • Czym jest enum?
  • Czym różni się struktura od uni?
  • W jaki sposób/ do czego możemy wykorzystać dynamiczne alokowanie pamięci?

Przykłady

Unie

Unie definiujemy za pomocą słówka kluczowego union:

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

union union_name {
    int a;
    char b;
    char c[5];
    struct asd{
        float d;
    } struct_name;
} Tmyname;

int main(int argc, char const *argv[])
{ 
    union union_name x = {4};
    printf("%d\n", x);
    x.b = 'd';
    printf("%c\n", x);  
    x.struct_name.d = 4.5;

    printf("Po zmianie ktoregos z pol struktury inne wartosci tez sa zmienione:\n");
    printf("x.a = %d", x.a);

    return 0;
}

Unie mają rozmiar równy największemu z przechowywanych typów. W pamięci wartości pól uni będą przechowywane we wspólnym bloku pamięci podczas gdy struktury będą miały zalokowane miejsca w pamieci dla poszczeólnych pól.

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

union myunion
{
    char a;
    int b;
    double c;
};

struct mystruct {
    char a;
    int b;
    double c;
};


int main(int argc, char const *argv[])
{
    union myunion myunion;
    struct mystruct mystruct;

    printf("ilosc bajtow ktore zajmuje unia = %i (max_zmienna=%i)\n", sizeof(myunion), sizeof(double));
    // Jeśli zmienne w strukturze posortujemy malejąco według zajmowanego miejsca w pamięci rozmiar struktury będzie mniejszy
    printf("ilosc bajtow ktore zajmuje struktura = %i (%i+%i+padding+%i)\n", sizeof(mystruct), sizeof(char), sizeof(int), sizeof(double));
    return 0;
}

Za pomocą słówna kluczowego typedef można zadeklarować krótką nazwę struktury lub uni.

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

typedef union myunion
{
    char a;
    int b;
    double c;
} shortname;

int main(int argc, char const *argv[])
{
    union myunion x; // deklaracja uni za pomocą pełnej definicji
    shortname x1; // seklaracja uni za pomocą krótkiej definicji

    x.a = 'a';
    x1.a = 'a';
    return 0;
}

Enum

Typ wyniliczeniowy jest to struktura która może przyjmować pewne z góry ustalone wartości. Nazwy tych wartości zazwyczaj wskazują jakiś stan aplikacji lub nazwę obiektu która pozwala w czytelny sposób określic co dany kawąłek kodu robi. Pod daną nazwą kryje się liczba. Np. definicje kolorów w instrukcji switch czy menu.

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

typedef enum Color
{
    RED, // odpowiada liczbie 0
    GREEN, // odpowiada liczbie 1
    BLUE // odpowiada liczbie 2
} Color;

int main(int argc, char const *argv[])
{

    Color x = GREEN;

    switch (x)
    {
    case RED:
        printf("Wybrano czerwony");
        break;
    case GREEN:
        printf("Wybrano zielony");
        break;
    case 2: // Wartości tak naprawdę są liczbammi
        printf("Wybrano niebieski");
        break;
    default:
        break;
    }

    return 0;
}

malloc i calloc

Funkcje malloc() i calloc() rezerwują w pamięci określoną ilość miejsca. Mijesce jest zwalniane po użyciu funkcji free()

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

int *alocateTabMalloc(int a)
{
    int rozmiar_tablicy = a * sizeof(int); // ilość elementów * rozmiar jednego elementu
    int *ptr = malloc(rozmiar_tablicy);
    return ptr;
}

int *alocateTabCalloc(int a)
{
    int *ptr = calloc(a, sizeof(int)); // alokuje określoną ilość w pamięci danego typu i ustawia wartości w pamięci na 0.
    return ptr;
}

int main(int argc, char const *argv[])
{
    int *tab = alocateTabMalloc(4); // utworzenie tablicy na 4 zmienne typu int
    for (size_t i = 0; i <= 5; i++)
    {
        if (i > 3)
        {
            printf("tab[%d] = %d (poza tablica)\n", i, tab[i]);
            continue;
        }
        printf("tab[%d] = %d\n", i, tab[i]);
    }

    int *tab2 = alocateTabCalloc(4); // utworzenie tablicy na 4 zmienne typu int
    for (size_t i = 0; i <= 5; i++)
    {
        if (i > 3)
        {
            printf("tab2[%d] = %d (poza tablica)\n", i, tab2[i]);
            continue;
        }
        printf("tab2[%d] = %d\n", i, tab2[i]);
    }

    // kopiuje wskaźnik do tablicy tab2
    int *ptr2 = tab2;
    // zwalniam pamięć
    free(tab2);
    // Wypisuję zawartość pamięci
    for (size_t i = 0; i <= 5; i++)
    {
        printf("ptr2[%d] = %d (zwomnione miejsce)\n", i, ptr2[i]);
    }

    return 0;
}

Zadania

Chcemy utworzyć tablicę która przyjmuje wartości różnego typu. Następnie funkcję która będzie wypisywała zawartość tablicy.

Zadanie 1

Utwórz typ wyliczeniowy var_type zawierający wartości INT, FLOAT, CHAR.

Zadanie 2

Utwórz struktórę var która będzie przechowywać typ zmiennej. Oraz wartość zmiennej. Typ zmiennej jest typem wyliczeniowym natomiast na przehcoywanie wartoścu utwórz unie o typach takich jak w poprzednim zadaniu.

Zadanie 3

Utwórz funckję setInt() setFloat() setChar() które przyjmują dwa arumenty, wskaźnik do zmiennej var i wartość zmiennej. Funkcje ustawiają odpowienio wartości zmiennej var.

Zadanie 4

Utwórz tablicę zawierającą 10 wartości typu var. Wypełnij tablicę wartości najpierw liczbami od 1 do 10. Wypełnij tablicę wartościami A, B, C, D …

Zadanie 5

Utwóz funkcję varToString() która zwraca wskaźnik do łańcucha znaków. Np. jeśli var przechowuje wartość 100 to varToString() pwoinna zwrócić wskaźnik na tablicę przechowującą napis “100”. Wykorzystaj funkcję sprintf()

Zadanie 6

Wypisz zawartość tablic wykorzystując stworzone funkcje.