Dynamiczne listy w C i funkcja malloc()

W języku C nie ma czegoś takiego jak zdefiniowana Lista obiektów, ale można sobie samemu stworzyć coś przypominającego listę używając struktur, wskaźników i funkcji malloc() oraz free(). Aby lepiej zrozumieć ten problem przedstawię program w którym pokaże jak stworzyć strukturę w strukturze i połączyć różne struktury ze sobą. Następnie poszerzę ten program o dynamiczne przydzielanie pamięci za pomocą funkcji malloc().

Program statycznej listy oraz jej wyświetlenie zaprezentowałem poniżej:

#include <stdio.h>
#include <stdlib.h>
typedef struct czlowiek {
 const char *nazwa;
 int wiek;
 struct czlowiek *nastepny;
}czlowiek;
void wyswietl_wszystko(czlowiek *cz)
{
 czlowiek *i=cz;
 for(;i!=NULL;i=i->nastepny)
 {
 printf("Nazwa: %s, wiek: %i \n",i->nazwa,i->wiek);
 }
 
}
int main(int argc, char *argv[]) {
 //tworzenie struktur
 czlowiek pierwszy = {"Rysio",49};
 czlowiek drugi = {"Misio",33};
 czlowiek trzeci = {"Zuzia",21};
 //tworzenie kolejnosci
 pierwszy.nastepny=&drugi;
 drugi.nastepny=&trzeci;
 trzeci.nastepny=NULL;
 //wyswietlanie listy
 wyswietl_wszystko(&pierwszy);
 return 0;
}

Jak można zauważyć struktura "czlowiek" ma 3 wartości "nazwe", "wiek" i "nastepny", gdzie pole "nastepny" wskazuje na strukturę "czlowiek". Dzięki takiemu rozwiązaniu możemy przypisać jedną strukturę do drugiej.

W programie stworzyliśmy na sztywno 3 struktury o nazwach pierwszy, drugi i trzeci, a następnie przypisaliśmy je do siebie ustalając tym samym kolejność. Niestety w tym programie wszystkie struktury tworzone są statycznie w kodzie, w ten sposób kompilator wie ile miejsca trzeba zarezerwować. Aby program przydzielał dynamicznie pamięć w czasie działania programu należy użyć funkcji malloc().

W następnym przykładzie pokazałem kod, który pyta się użytkownik o ilość zmiennych, które będą wprowadzane. W tym przykładzie pamięć jest rezerwowana dynamicznie w trakcie działania programu za pomocą malloc() w funkcji stworz(). Dobrym zwyczajem jest zwalnianie pamięci, gdy już jej nie potrzebujemy, dlatego utworzyłem także funkcje czysc().

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

typedef struct czlowiek {
 const char *nazwa;
 int *wiek;
 struct czlowiek *nastepny;
}czlowiek;

void wyswietl_wszystko(czlowiek *cz)
{
 czlowiek *i=cz;
 for(;i!=NULL;i=i->nastepny)
 {
 printf("Nazwa: %s, wiek: %i \n",i->nazwa,i->wiek);
 }    
}
czlowiek* stworz(char *nazwa, int wiek)
{
 czlowiek *i=malloc(sizeof(czlowiek));
 i->nazwa = strdup(nazwa);
 i->wiek = wiek;
 i->nastepny = NULL;
}
void czysc(czlowiek *cz)
{
 czlowiek *i=cz;
 czlowiek *nastepny=NULL;
 for(;i!=NULL;i=nastepny)
 {
 nastepny=i->nastepny;
 free(i->nazwa);
 free(i->wiek);
 free(i);
 }
}

int main(int argc, char *argv[]) {
 //tworzenie struktur
 char nazwa[80];
 int wiek;
 int j=0;
 int k=0;
 czlowiek *start=NULL;
 czlowiek *next=NULL;
 czlowiek *reka=NULL;
 printf("ile zmiennych chcesz wprowadzic: ");
 scanf("%i",&k);
 for(j = 0; j < k ; j++){
 printf("Podaj nazwę i po spacji wiek: ");
 scanf("%s %i",&nazwa,&wiek);
 next=stworz(nazwa,wiek);
 if(start==NULL){
 start=next;
 reka = start;
 }            
 if(reka!=NULL){
 reka->nastepny=next;
 reka=next;
 }
 }

 //wyswietlanie listy
 wyswietl_wszystko(start);
 
 //zwalnianie pamieci
 czysc(start);
 return 0;
}

Po odpaleniu programu powinniśmy uzyskać taki efekt:

ile zmiennych chcesz wprowadzic: 3
Podaj nazwe i po spacji wiek: Rysio 43
Podaj nazwe i po spacji wiek: Maria 23
Podaj nazwe i po spacji wiek: Zuzia 22
Nazwa: Rysio , wiek: 43
Nazwa: Maria , wiek: 23
Nazwa: Zuzia , wiek: 22

Użytkownik podaje ile osób chce wprowadzić, a następnie wpisuje nazwy i wiek tych osób. Gdy wpiszemy wszystkie osoby, to program wyświetli je, a następnie usunie za pomocą funkcji czysc() w której jest użyta funckcja free(). Następnie zakończy działanie programu. Oczywiście, gdy program zostanie zamknięty, to system operacyjny sam zwolni pamięć, która była wykorzystywana przez dany program.