C/Napisy: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Lethern (dyskusja | edycje)
m usunięcie zaciemnienia kodu
Lethern (dyskusja | edycje)
Nie podano opisu zmian
Linia 334:
</source>
 
Zawsze możemy też użyć łańcucha typu [[#WłasnaNapisy - własna implementacja|linked list]]:
<source lang="c">
#include <stdio.h>
Linia 447:
}
</source>
Takich wad nie ma [[#WłasnaNapisy - własna implementacja|łańcuch typu linked-list]].
 
== Unicode ==
Linia 514:
}
</source>
==Własna implementacja==
Ponieważ tablice znaków mają ograniczenia, możemy zaimplementować łańcuch typu [[wikipedia:linked list|linked list]].
===Typ danych===
Typ zdefiniujemy jako [[C/Wskaźniki#Do czego można użyć wskaźników na funkcje?|klasę]].
<source lang="c">
typedef struct _string
{
/* aktualny znak */
char c;
/* następny znak */
struct _string *next;
} *string;
</source>
Zauważmy, że łańcuch automatycznie oznaczamy jako wskaźnik. W ten sposób zabezpieczamy się przed kopiowaniami.
 
===Metody===
Na początek zajmiemy się wypisywaniem łańcucha:
<source lang="c">
static string str;
static struct string_data
{
char c;
struct string_data *next;
};
typedef struct _string
{
FILE *(*wypisz)(FILE*);
} *string;
FILE *wypisz_str(FILE *strum)
{
string wsk = str;
for(;wsk != NULL;wsk = wsk->next)
fputc(strum, wsk->c);
}
</source>
Teraz zajmijmy się przypisaniem:
<source lang="c">
static string str;
static struct string_data
{
char c;
struct string_data *next;
};
typedef struct _string
{
FILE *(*wypisz)(FILE*);
void (*wpisz)(const char*);
} *string;
void wpisz_do_str(const const char *new_string)
{
for(;new_string && *new_string;++new_string)
{
string new_char = create_string("");
new_char->c = *new_string;
new_char->next = NULL;
str->next = new_char;
}
}
</source>
 
Dla uproszczenia zapisu skorzystaliśmy z konstruktora klasy <tt>string</tt>. Tego jeszcze nie mamy, więc czas na niego:
<source lang="c">
struct string_data create_string_data(const const char *initial)
{
struct string_data new_string;
struct string_data *tmp = &new_string;
for(;initial && *initial;++initial)
{
struct string_data new_char;
new_char->c = *new_string;
new_char->next = NULL;
tmp->next = new_char;
}
return new_string;
}
 
string create_string(const const char *initial)
{
string new_string = malloc(sizeof *new_string);
new_string.wypisz = wypisz_str;
new_string.wpisz = wpisz_do_str;
return new_string;
}
 
void free_string(string *s)
{
if(*s == NULL)return;
if((*s)->next)free_string(s->next);
free(*s);
*s = NULL;
}
</source>
 
=== Porównywanie ===
<source lang="c">
int porownaj_str(string porownywany)
{
int is_equal;
string wsk = str;
for(;wsk != NULL;wsk = wsk->next)
for(;porownywany != NULL;porownywany = porownywany->next)
if(wsk->c == porownywany->c)
is_equal = 1;
else
is_equal = 0;
return is_equal;
}
</source>
 
===Konwersje===
Pora na konwersje. Można je zaimplementować analogicznie do <tt>sprintf</tt> i <tt>sscanf</tt>.
 
===Jak komputer przechowuje w pamięci listę znaków?===
W pamięci komputera najpierw stoi "głowa" łańcucha (pierwszy znak).
 
Sytuacja taka jest przedstawiona poniżej (łańcuch "Hello"):
0x0329adf9382 c 'H'
0x0329adf9382 next 0x0329adf9383
0x0329adf9383 c 'e'
0x0329adf9383 next 0x0329adf9384
0x0329adf9384 c 'l'
0x0329adf9384 next 0x0329adf9385
0x0329adf9385 c 'l'
0x0329adf9385 next 0x0329adf9386
0x0329adf9386 c 'o'
0x0329adf9386 next 0x00000000
{{Uwaga|Powyższe adresy to tylko przykład, lista (inaczej niż tablica!) nie gwarantuje, że kolejne elementy będą umieszczone obok siebie!}}
 
Na samym końcu stoi "ogon" (ostatni znak).
 
<noinclude>
Ideą listy znaków jest to, że może się rozszerzać, bez specyfikowania żadnego wymiaru "na sztywno". Inną jej cechą jest to, iż nie możemy jej indeksować.
== Zobacz też ==
* [[Napisy - własna implementacja]]
<noinclude>