Katedra Elektrotechniki Teoretycznej i Informatyki wykład 9 - sem.iii Dr inż. M. Czyżak
Język ANSI C tablice znaków Tablice znaków (łańcuchy) Tablice znaków stanowią specjalny rodzaj tablic o budowie ułatwiającej przetwarzanie tekstów. Przetwarzanie obejmuje szereg operacji takich jak tworzenie, modyfikację i przeszukiwanie. Tablice znakowe mogą być definiowane w sposób następujący: char s1[5]; char s2[5]="abcd"; char s3[ ]="abcd"; Definicje tablic s2 i s3 zawierają też inicjalizację. Tablice znaków zakończone są znakiem \0. Znak ten umożliwia wykrycie końca tablicy, a tym samym umożliwia traktowanie tablic znaków w nieco inny sposób niż zwykłych tablic.
Budowa tablicy znaków Przykładowo, tablica s2 ma następującą budowę: 'A' 'B' 'C' 'D' '\0' Tak więc definiując tablicę znakową należy przewidzieć jedną komórkę na znak końcowy \0.
Stałe łańcuchowe i wskaźniki do znaków cz. 1 Stałe łańcuchowe ( stałe typu tablica znaków), np. "Tekst", są przechowywane w pamięci jako tablice znaków z ostatnim elementem równym \0. Stała "Tekst" jest typu char *, czyli wskaźnik do znaku. Wskaźnik do znaku może więc zostać zainicjowany stałą łańcuchową char *ps="tekst"; // sposób 1 Inicjalizacja taka jest równoważna parze instrukcji char *ps;// sposób 2 ps="tekst"; W przypadku sposobu 1 do wskaźnika ps jest przypisywany wskaźnik do tablicy znaków, a nie do *ps ( czyli nie do miejsca wskazywanego przez ps).
Stałe łańcuchowe i wskaźniki do znaków cz. 2 Warto też zauważyć, że przy definicji tablicy znakowej char s2[5]; nie jest możliwa realizacja przypisania w programie s2="abcd" ;// przypisanie błędne Wynika to z faktu, że s2 jako nazwa tablicy jest typu stały wskaźnik do znaku, który to wskaźnik nie może być zmieniony poprzez przypisanie.
Wczytywanie i drukowanie tablic znakowych cz.1 W języku C istnieje specjalny deskryptor formatu %s umożliwiający wczytywanie i drukowanie tablic znakowych przy użyciu funkcji scanf i printf, istnieją też inne funkcje biblioteczne realizujące te operacje. Jeśli zdefiniowano tablicę znakową char s1[5]; można ją wczytać i wydrukować w poniższy sposób: printf("\n Podaj lancuch :"); scanf("%s",s1); // nie stosuje się znaku & przed // s1, gdyż s1 jest wskaźnikiem. printf("\n Wczytany lancuch to :%s ", s1);
Wczytywanie i drukowanie tablic znakowych cz.2 Jednak wczytywanie łańcuchów przy użyciu funkcji scanf nie pozwala na wczytanie łańcuchów zawierających spacje, gdyż wczytywanie łańcucha jest przerywane po napotkaniu spacji. Dla takich łańcuchów należy zastosować funkcję gets lub też funkcję fgets. Funkcja gets ma następujący prototyp: char* gets(char *s);
Wczytywanie i drukowanie tablic znakowych cz.3 Opis działania funkcji gets: Funkcja wczytuje znaki ze standardowego wejścia ( stdin) aż do momentu napotkania znaku nowej linii (Enter). Wczytywane znaki są wyświetlane na ekranie i zapamiętywane począwszy od miejsca wskazywanego przez argument funkcji, s. Znak nowej linii jest zastępowany w łańcuchu znakiem końca łańcucha '\0'. Ciąg wejściowy może zawierać pewne białe znaki (np. spacje lub znaki tabulacji poziomej). Funkcja zwraca s, gdy operacja się powiodła lub NULL w przypadku wystąpienia błędu.
Wczytywanie i drukowanie tablic znakowych cz.4 Długość wczytywanego ciągu znaków nie jest ograniczana, co przy ciągach dłuższych niż to wynika z argumentu funkcji gets, może powodować uszkodzenie sąsiednich obszarów pamięci. Przykład. char lan [20]; printf ("\n Podaj lancuch:"); gets(lan); Bardziej uniwersalną funkcją służącą do wczytywania łańcuchów jest fgets..
Wczytywanie i drukowanie tablic znakowych cz.5 Funkcja fgets ma nastepujący prototyp: char *fgets(char *s, int n, FILE *stream); Funkcja ta czyta do łańcucha s znaki ze strumienia wejściowego (pliku) określonego przez wskaźnik stream. Funkcja kończy wczytywanie znaków po przeczytaniu n - 1 znaków lub też po pojawieniu się znaku nowej linii i wpisuje znak nowej linii do do łańcucha. Zwraca łańcuch lub NULL w przypadku pojawienia się końca pliku lub błędu. Przykład. Wczytywanie ze standardowego strumienia wejściowego. char lan [20]; printf ("\n Podaj lancuch:"); fgets(lan,15,stdin);
Wczytywanie drukowanie tablic znakowych cz.6 Do drukowania tablic znakowych poza funkcją printf można zastosować funkcje puts i fputs. Prototyp funkcji puts ma postać int puts (const char *s); Funkcja wyprowadza łańcuch na wyjście standardowe (stdout) i dołącza znak nowej linii. W przypadku pomyślnej realizacji funkcja zwraca wartość nieujemną, w przeciwnym przypadku EOF. int fputs(const char *s, FILE *stream); Funkcja zapisuje łańcuch s do do strumienia wyjściowego określonego przez wskaźnik stream. Funkcja nie zapisuje do pliku znaku '\0'. W przypadku powodzenia operacji funkcja zwraca wartość nieujemną, w przypadku błędu wartość EOF.
Przykład. Zastosowanie funkcji fputs do wydruku w standardowym strumieniu wyjściowym (stdout). #include <stdio.h> #include <string.h> int main(int argc, char **argv) } { char s1[10]="abcde"; char s2[10]="abcde"; fputs(s1,stdout); fputc('\n',stdout);// dodanie znaku nowej linii fputs(s2,stdout); fputc('\n',stdout);// wyprowadzenie znaku nowej linii system ("pause");
Standardowe funkcje łańcuchowe cz. 1 Poniżej omówione zostaną wybrane najczęściej spotykane funkcje związane z przetwarzaniem łańcuchów (pełny zestaw w <string.h> i <stdlib.h>, opisano je też w materiale TabliceZnakowe.pdf. Funkcje te to: strlen, strcpy, strcat, strcmp, strlwr, strupr, atoi, itoa, strchr, strstr. Funkcja strlen size_t strlen(const char *s); Funkcja oblicza długość łańcucha s bez końcowego znaku '\0'. Przykład. Zastosowanie funkcji strlen do wyznaczania długości łańcucha. char s[10]="12345678"; int dl; dl=strlen(s);// dl będzie równe 8
Funkcja strcpy Standardowe funkcje łańcuchowe cz. 2 char *strcpy(char *dest, const char *src); Kopiuje łańcuch src do łańcucha dest. Kopiowanie ulega zakończeniu po skopiowaniu znaku '\0' kończącego łańcuch src. Funkcja zwraca wskaźnik dest. Przykład. #include <stdio.h> #include <string.h> int main(void) { char lan1[10="abc"; char lan2[ ]= "12345"; strcpy(lan1, lan2);// kopiowanie łańcuchów printf("%s", lan1); return 0; }
Funkcja strcat char *strcat(char *dest, const char *src); Dołącza łańcuch src do końca łańcucha dest. Funkcja zwraca wskaźnik dest. Długość połączonego łańcucha jest równa strlen(dest)+strlen(src). Przykład. #include <stdio.h> #include <string.h> int main(void) { char lan1[20]="abcde"; char lan2[ ]= "123456789"; strcat(lan1, lan2); printf("%s", lan1); return 0; } Standardowe funkcje łańcuchowe cz. 3
Standardowe funkcje łańcuchowe cz. 4 Funkcja strcmp int strcmp(const char *s1, const char *s2); Porównuje łańcuch s1 z łańcuchem s2, porównując kody znaków (np. kody ASCII) obu łańcuchów. Porównanie kończy się, gdy w jednym z łańcuchów zostanie napotkany znak o większym kodzie lub też zostanie osiągnięty koniec jednego z łańcuchów ( wtedy dłuższy łańcuch uważany jest za większy). Funkcja zwraca - wartość <0, gdy s1<s2, -wartość 0, gdy s1==s2, -wartość >0, gdy s1>s2.
Standardowe funkcje łańcuchowe cz. 5 Przykład. Zastosowanie funkcji strcmp. #include <stdio.h> #include <string.h> int main(void) { char lan1[10]="abcde",lan2[10 ]; int p; printf(" Podaj lancuch:"); scanf("%s", lan2); p= strcmp(lan1,lan2); if (p<0) printf(" lan1<lan2"); else printf("\n lan1=lan2"); else printf("\n lan1>lan2"); getchar(); return 0; } if ( p==0)
Standardowe funkcje łańcuchowe cz. 6 Funkcja strlwr char *strlwr(const char *s); Zamienia w łańcuchu duże litery na małe, innych znaków nie zmienia. Łańcuch lan1 ma postać char lan1[ ]="String ABC"; strlwr(lan1); Po wykonaniu instrukcji, lan1 ulega zmianie na łańcuch "string abc".
Standardowe funkcje łańcuchowe cz. 7 Funkcja strlupr char *strupr(char *s); Zamienia w łańcuchu małe litery na duże, innych znaków nie zmienia. Łańcuch lan2 ma postać char lan2[ ]="lancuch abc"; strupr(lan2); Po wykonaniu instrukcji, lan2 ulega zmianie na łańcuch "LANCUCH ABC".
Funkcja atoi int atoi(const char *s); Funkcja atoi zamienia lańcuch będący argumentem funkcji na liczbę całkowitą, rozpoznaje ona (w zadanym porządku) - opcjonalny łąńcuch znaków tabulacji i spacji - opcjonalny znak - łąńcuch cyfr Łańcuch musi mieć następującą postać: [ws] [sn] [ddd] // ws - białe znaki,sn - znak liczby Pierwszy nierozpoznany znak kończy konwersję. Nadmiar nie jest rozpoznawany ( wynik jest wtedy nieokreślony). Wartość zwracana Standardowe funkcje łańcuchowe cz. 8 atoi zwraca liczbę całkowitą odpowiadającą łańcuchowi wejściowemu.
Standardowe funkcje łańcuchowe cz. 9 Funkcja itoa char *itoa(int value, char *string, int radix); Funkcja zamienia liczbę będącą pierwszym argumentem funkcji ( value) na łańcuch znaków umieszczany w tablicy znakowej (string) będącej drugim argumentem. Konwersja odbywa się dla podstawy systemu liczbowego podanej jako trzeci argument funkcji (radix). Podstawa systemu musi należeć do przedziału [2,36]. Jeśli liczba jest ujemna i podstawa systemu jest równa 10, pierwszym znakiem łańcucha znaków jest znak '-'.
Standardowe funkcje łańcuchowe cz. 10 Funkcja strchr char *strchr(const char *s, int c); Funkcja wyszukuje w łańcuchu znaków s znak c. Funkcja zwraca wskaźnik do pierwszego wystąpienia znaku c. Jeśli znaku nie ma, funkcja zwraca zerowy wskaźnik null. Funkcja strstr char *strstr(const char *s1,const char *s2 ); Funkcja wyszukuje w łańcuchu znaków s1 łańcuch s2. Funkcja zwraca wskaźnik do pierwszego wystąpienia łańcucha s2 (do pierszego znaku łańcucha s2). Jeśli łańcucha s2 nie ma, funkcja zwraca zerowy wskaźnik null.
Przykład. Wczytywanie dwuwymiarowej tablicy znaków (tablicy łańcuchów) oraz sortowanie niemalejąco. (cz.1) // cz. 1 programu #include <stdio.h> #include <conio.h> #include <string.h> int main(int argc, char* argv[]) { char stab[5][10]; char spom[10]; int i,zam; for(i=0;i<5;i++) { printf("\n lan%d :",i); scanf("%s",stab[i]); // wczytywanie tablicy znaków // będącej wierszem tablicy dwuwymiarowej } for(i=0;i<5;i++) printf("\n lan %s",stab[i]);
Cz. 2 programu do { zam=0; for (i=0;i<4;i++) if (strcmp(stab[i],stab[i+1])>0) { strcpy(spom, stab[i]); strcpy(stab[i], stab[i+1]); strcpy( stab[i+1],spom ); zam=1; } } while (zam); printf("\n\n Tablica po sortowaniu"); for(i=0;i<5;i++) printf("\n lan %s",stab[i]); getch(); return 0;}