V kapitole Řetězce pro pokročilé jsme si ukázali práci s řetězci. Pro řetězce jsme měli tři proměnné. První byl samotný řetězec char *. Druhá proměnná byla číslo, které udržovalo maximální možnou délku řetězce. Třetí proměnná byla číslo, které udržovalo aktuální délku řetězce. Tyto proměnné patří logicky k sobě. Proto bychom je mohli dát do jedné struktury. Ta by mohla vypadat následovně

typedef struct { int max_delka; int delka; char * data; } string;

Pak bychom mohli s danou strukturou pracovat následovně

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

#define BLOK_PAMETI 4

typedef struct { int max_delka; int delka; char * data; } string;

string * inicializace() {
    string * retezec = malloc(sizeof(string));

    if (retezec == NULL) {
        printf("Chyba alokace\n");
        return NULL;
    }

    retezec->delka = 0;
    retezec->max = BLOK_PAMETI;
    retezec->data = malloc(sizeof(char)*BLOK_PAMETI);

    if (retezec->data == NULL) {
        printf("Chyba alokace\n");
        free(retezec);
        return NULL;
    }

    retezec[0] = '\0';

    return retezec;
}

char * pridej_pamet(string * retezec, int novy_max) {
    char * novy_retezec = realloc(retezec, novy_max);
    if (novy_retezec == NULL) {
        printf("Chyba realokace\n");
        return NULL;
    }

    retezec->data = novy_retezec;
    retezec->max_delka = novy_max; 

    return novy_retezec;
}

int main() {
    char * retezec = inicializace();
    if (retezec == NULL) {
        return 1;
    }

    // ...

    free(retezec->data);
    free(retezec);

    return 0;
}

Zde si můžeme všimnout několika věcí. Pokud pracujeme s ukazatelem na strukturu, můžeme použít ->. Tyto dva zápisy jsou stejné (obecně se používá zápis se šipkou)

retezec->delka = 0;
(*retezec).delka = 0;

Další věc, na kterou je potřeba si dávat pozor je, že když uvolňujeme paměť, tak je potřeba uvolni nejdříve paměť dat uvnitř struktury a až nakonec samotnou strukturu. Pokud bychom nejdříve uvolnili strukturu a až následně data

free(retezec);
free(retezec->data);

Dostaneme chybu, protože na druhém řádku přistupujeme k proměnné retezec, která ale už má nedostupnou paměť (byla uvolněna).

Poslední věci, které bychom si měli všimnout je, že pokud potřebujeme rozšířit data, tak se realokuje paměť jenom pro char * data a není potřeba realokovat paměť pro string * retezec. Je to proto, že struktura zůstává pořád stejné velikosti. Mění se jenom paměť řetězce, na kterou ukazujeme a ta není součástí struktury. Ve struktuře je uložena pouze adresa paměti dat řetězce. Tzv. děláme realloc pouze pro retezec->data a nikoliv pro retezec.

Rekurzivní struktury

Struktury můžou být i rekurzivní. To znamená, že odkazují samy na sebe. Mějme strukturu, která reprezentuje člověka a má odkaz na jeho rodiče.

struct clovek { struct clovek * matka; struct * clovek otec; };
typedef struct clovek clovek;

Mohli bychom simulovat data jednoho člověka, jeho rodičů a rodičů jeho maminky

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

struct clovek { struct clovek * matka; struct clovek * otec; };
typedef struct clovek clovek;

int main() {
    clovek * ja = malloc(sizeof(clovek));
    clovek * mamka = malloc(sizeof(clovek));
    clovek * tatka = malloc(sizeof(clovek));
    clovek * babicka = malloc(sizeof(clovek));
    clovek * dedecek = malloc(sizeof(clovek));

    ja->matka = mamka;
    ja->otec = tatka;
    ja->matka->matka = babicka;
    ja->matka->otec = dedecek;

    return 0;
}

Pro zjednodušení jsme nevolali free ani nekontrolovali, zda se paměť podařilo alokovat.

XXX

Odkazy

Následující kapitola: Přesměrování

GitHub diskuze k této kapitole

Zpátky na přehled

Předchozí kapitola: Moduly