Listy jednokierunkowe (wersja uniwersalna)
-- Sebastian Pawlak, 2003.
Węzeł listy jest strukturą zawierającą wskaźnik do informacji oraz wskaźnik na następny węzeł listy.
typedef struct wezel {
void *obj;
wezel *nastepny;
} wezel;
Zaprezentowana wersja biblioteki umożliwia przechowywanie w węzłach listy
dowolnych danych, o strukturze zdefiniowanej przez użytkownika. Wadą tego
rozwiązania jest konieczność indywidualnego zaprogramowania kilku funkcji
operujących na strukturze danych (patrz: test.c).
Kod źródłowy pliku "lista.h":
/* lista.h: plik naglowkowy biblioteki z implementacja operacji na
* listach jednokierunkowych (wersja uniwersalna)
* Sebastian Pawlak, 2003-12-11
*/
#ifndef _LISTA_H_
#define _LISTA_H_
#include <stdarg.h>
typedef struct wezel {
void *obj;
struct wezel *nastepny;
} wezel;
enum {
POPRAWNIE = 0,
BRAK_PAMIECI = -1,
BLAD_IO = -2,
BLAD_POZYCJI = -3
};
int wstawPocz(wezel **L, void *obj);
int wstaw(wezel **L, int p, void *obj);
int usun(wezel **L, int p, void (*fn)(void *obj));
int zwroc(wezel *L, int p, void **obj);
int znajdz(wezel *L, int *p, int (*fn)(void *obj1, va_list *ap), ...);
void wyczysc(wezel **L, void (*fn)(void *obj));
void wypisz(wezel *L, void (*fn)(void *obj));
int zapisz(wezel *L, char *nazwaPliku, int (*fn)(FILE *f, void *obj));
int wczytaj(wezel **L, char *nazwaPliku, int (*fn)(FILE *f, void **obj));
#endif
Kod źródłowy pliku "lista.c":
/* lista.c: biblioteka z implementacja operacji na
* listach jednokierunkowych (wersja uniwersalna)
* Sebastian Pawlak, 2003-12-11
*/
#include <stdio.h>
#include <stdlib.h>
#include "lista.h"
/* wstawPocz: tworzy i wstawia nowy element na poczatek listy */
int wstawPocz(wezel **L, void *obj)
{
wezel *Q;
if ((Q = (wezel *)malloc(sizeof (wezel))) == NULL)
return BRAK_PAMIECI;
Q -> obj = obj;
Q -> nastepny = *L;
*L = Q;
return POPRAWNIE;
}
/* wstaw: tworzy i wstawia nowy element na p-ta pozycje na liscie;
* pozycja liczona jest od 0
*/
int wstaw(wezel **L, int p, void *obj)
{
wezel *Q, *S = NULL, *T = *L;
while (T && (p > 0)) {
S = T;
T = T -> nastepny;
p--;
}
if (p != 0)
return BLAD_POZYCJI;
if ((Q = (wezel *)malloc(sizeof (wezel))) == NULL)
return BRAK_PAMIECI;
Q -> obj = obj;
Q -> nastepny = T;
if (S == NULL)
*L = Q;
else
S -> nastepny = Q;
return POPRAWNIE;
}
/* usun: usuwa element z p-tej pozycji na liscie;
* pozycja liczona jest od 0
*/
int usun(wezel **L, int p, void (*fn)(void *obj))
{
wezel *S = NULL, *T = *L;
while (T && (p > 0)) {
S = T;
T = T -> nastepny;
p--;
}
if ((p != 0) || (T == NULL))
return BLAD_POZYCJI;
if (S == NULL)
*L = T -> nastepny;
else
S -> nastepny = T -> nastepny;
(*fn)(T -> obj); /* funkcja uzytkownika: kasuje pola "obj" */
free(T -> obj);
free(T);
return POPRAWNIE;
}
/* zwroc: przypisuje wskaznikowi "obj" p-ty element z listy */
int zwroc(wezel *L, int p, void **obj)
{
while (L && (p > 0)) {
L = L -> nastepny;
p--;
}
if ((p != 0) || (L == NULL))
return BLAD_POZYCJI;
*obj = L -> obj;
return 0;
}
/* znajdz: przypisuje zmiennej "p" numer elementu listy, dla ktorego
* funkcja porownujaca "fn" zwroci wartosc 1;
* przeszukiwanie listy rozpoczyna sie od p-tego elementu
*/
int znajdz(wezel *L, int *p, int (*fn)(void *obj1, va_list *ap), ...)
{
va_list ap;
int i = *p;
/* przesuniecie sie na p-ta pozycje, aby od tej pozycji rozpoczac
* poszukiwanie
*/
while (L && (i > 0)) {
L = L -> nastepny;
i--;
}
while (L) {
va_start(ap, fn); /* "fn" - ostatni nazwany argument */
if ((*fn)(L -> obj, &ap)) /* funkcja uzytkownika: porownanie */
return POPRAWNIE;
va_end(ap);
(*p)++;
L = L -> nastepny;
}
return BLAD_POZYCJI;
}
/* wyczysc: usuwa wszystkie elementy z listy */
void wyczysc(wezel **L, void (*fn)(void *obj))
{
wezel *Q;
while (*L) {
Q = *L;
*L = (*L) -> nastepny;
(*fn)(Q -> obj); /* funkcja uzytkownika: kasuje pola "obj" */
free(Q -> obj);
free(Q);
}
}
/* wypisz: wypisuje wszystkie elementy z listy;
* funkcji tej mozna uzyc takze do zaaplikowania danej operacji
* na wszystkich elementach listy
*/
void wypisz(wezel *L, void (*fn)(void *obj))
{
while (L) {
(*fn)(L -> obj); /* funkcja uzytkownika: wypisanie */
L = L -> nastepny;
}
}
/* zapisz: zapisuje wszystkie elementy z listy do pliku tekstowego */
int zapisz(wezel *L, char *nazwaPliku, int (*fn)(FILE *f, void *obj))
{
FILE *f;
if ((f = fopen(nazwaPliku, "w")) == NULL)
return BLAD_IO;
while (L) {
if ((*fn)(f, L -> obj) < 0) /* funkcja uzytkownika: zapis */
return BLAD_IO;
L = L -> nastepny;
}
fclose(f);
return POPRAWNIE;
}
/* wczytaj: wczytuje z pliku tekstowego elementy i wstawia je na liste
* w odwrotnej kolejnosci
*/
int wczytaj(wezel **L, char *nazwaPliku, int (*fn)(FILE *f, void **obj))
{
wezel *Q, *T = *L;
FILE *f;
void *obj;
if ((f = fopen(nazwaPliku, "r")) == NULL)
return BLAD_IO;
/* odnalezienie konca listy */
while (T && (T -> nastepny))
T = T -> nastepny;
while ((*fn)(f, &obj) != EOF) { /* funkcja uzytkownika: odczyt */
if ((Q = (wezel *)malloc(sizeof (wezel))) == NULL)
return BRAK_PAMIECI;
Q -> obj = obj;
Q -> nastepny = NULL;
if (T == NULL)
*L = T = Q;
else {
T -> nastepny = Q; /* dopisywanie elementow do konca listy */
T = T -> nastepny;
}
}
fclose(f);
return POPRAWNIE;
}
Kod źródłowy pliku "test.c":
/* test.c: ilustracja dzialania biblioteki lista.c
* Sebastian Pawlak, 2003-12-11
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lista.h"
/* struktura definiujaca element danych
* umieszczany w wezle listy
*/
typedef struct dana {
char *nazwisko;
int wiek;
} dana;
void *nowy(char *nazwisko, int wiek);
void usunDana(void *obj);
int znajdzDana(void *obj1, va_list *ap);
void wypiszDana(void *obj);
int zapiszDana(FILE *f, void *obj);
int wczytajDana(FILE *f, void **obj);
int main(void)
{
wezel *L = NULL;
dana *d;
int p;
wstawPocz(&L, nowy("Kernighan", 55));
wstawPocz(&L, nowy("Ritchie", 57));
wstaw(&L, 1, nowy("Stroustrup", 61));
wstawPocz(&L, nowy("Kernighan", 44));
wstaw(&L, 2, nowy("Nikt", 10));
usun(&L, 2, usunDana);
wypisz(L, wypiszDana);
printf("----------\n");
zwroc(L, 1, (void *)&d);
printf("> nazwisko: %s, wiek: %d\n", d -> nazwisko, d -> wiek);
printf("----------\n");
p = 0;
while (znajdz(L, &p, znajdzDana, "Kernighan") == POPRAWNIE)
printf("znaleziono \"Kernighan\" pod numerem: %d\n", p++);
printf("----------\n");
zapisz(L, "lista", zapiszDana);
wyczysc(&L, usunDana);
wczytaj(&L, "lista", wczytajDana);
wczytaj(&L, "lista", wczytajDana);
wypisz(L, wypiszDana);
return 0;
}
/* nowy: tworzy w pamieci nowy element danych */
void *nowy(char *nazwisko, int wiek)
{
dana *d = NULL;
if ((d = (dana *)malloc(sizeof (dana))) == NULL)
perror("nowy: Brak pamieci 1!");
if ((d -> nazwisko = (char *)malloc(strlen(nazwisko) + 1)) == NULL)
perror("nowy: Brak pamieci 2!");
strcpy(d -> nazwisko, nazwisko);
d -> wiek = wiek;
return (void *)d;
}
/* usunDana: usuwa z pamieci pola elementu danych */
void usunDana(void *obj)
{
free(((dana *)obj) -> nazwisko);
/* free(obj) przesunieta do lista.c */
}
/* znajdzDana: porownuje odpowiednie pola z "obj1" z podanymi jako
* argumenty;
* w niniejszej funkcji porównywane są nazwiska
*/
int znajdzDana(void *obj1, va_list *ap)
{
char *nazwisko = va_arg(*ap, char *);
if (!strcmp(((dana *)obj1) -> nazwisko, nazwisko))
return 1;
return 0;
}
/* wypiszDana: wypisuje odpowiednie pola elementu danych */
void wypiszDana(void *obj)
{
printf("nazwisko: %s, wiek: %d\n",
((dana *)obj) -> nazwisko, ((dana *)obj) -> wiek);
}
/* zapiszDana: zapisuje do pliku odpowiednie pola elementu danych */
int zapiszDana(FILE *f, void *obj)
{
return fprintf(f, "%s %d\n",
((dana *)obj) -> nazwisko, ((dana *)obj) ->wiek);
}
/* wczytajDana: wczytuje z pliku dane i tworzy w pamieci element danych */
int wczytajDana(FILE *f, void **obj)
{
char nazwisko[20];
int wiek;
int ret;
ret = fscanf(f, "%s %d", nazwisko, &wiek);
*obj = nowy(nazwisko, wiek);
return ret;
}





