Edytuj stronę Odnośniki Fold/unfold all ODT export Ta strona jest tylko do odczytu. Możesz wyświetlić źródła tej strony ale nie możesz ich zmienić. ====== Łańcuchy znaków (stringi) ===== * **napis** lub **łańcuch znakowy** to tablica zawierająca ciąg znaków zakończony wartością 0 (znak '' '\0' '') \\ {{zajecia:pp1_2021_1:string.png?600|}} * dowolny ciąg znaków w cudzysłowach jest stałym napisem, np.: napis ''"Ala ma kota"'' * funkcja ''printf()'' posiada specyfikator formatu ''%s'' służący do wyświetlania zmiennych napisowych **Przykład 1:**\\ Poniższy program oblicza ilość znaków w napisie "Ala ma kota". <file C str2.c> #include <stdio.h> int main() { char napis[] = "Ala ma kota"; int i = 0; while(napis[i] != '\0') { i++; } printf("Napis \"%s\" zawiera %d liter\n", napis, i); return 0; } </file> Po uruchomieniu programu na ekranie pojawi się: <code> Napis "Ala ma kota" zawiera 11 liter </code> **Przykład 2:**\\ Poniższy program wypisuje napis "Ala ma kota" w kolejnych liniach. W każdej kolejnej linii wypisywany komunikat jest skracany o jeden, początkowy znak. <file C str3.c> #include <stdio.h> int main() { char *napis = "Ala ma kota\n"; while(*napis != '\0') { printf(napis); napis++; } return 0; } </file> Po uruchomieniu programu na ekranie pojawi się: <code> Ala ma kota la ma kota a ma kota ma kota ma kota a kota kota kota ota ta a </code> W powyższym przykładzie zmienna ''napis'' jest zmienną wskaźnikową, która zawiera adres początku napisu, czyli adres pierwszego znaku. Operacja ''napis++'' zwiększa adres zapisany w zmiennej ''napis'', co powoduje, że wskaźnik pokazuje na kolejny element napisu. ===== Tablice a wskaźniki ===== Wskaźniki można wykorzystać do pokazywania elementów tablicy. Kolejne elementy tablicy umieszczone są w pamięci pod kolejnymi adresami, dzięki czemu zwiększając wartość zmiennej wskaźnikowej możemy przemieszczać się do kolejnych elementów tablicy. Obrazuje to poniższa grafika, gdzie kolejne elementy tablicy ''t'' wskazywane są przez zmienną wskaźnikową ''p'', która ustawiona jest na adres początku tablicy. <code C> int t[10]; // tablica 10-cio elementowa int* p; // zmienna wskaźnikowa p = t; // wartość t jest adresem początku tablicy &(t[0]) </code> {{zajecia:pp1_2020_1:wskaznik-tab.png?600}} Adres początku tablicy (pierwszego elementu) zawarty jest w zmiennej tablicowej, to znaczy, że adres ''&(t[0])'' jest wartością zmiennej ''t''. W konsekwencji **Tablica jest zmienną wskaźnikową** * Zmienna tablicowa zawiera adres początku tablicy, tzn. ''tab'' to to samo co ''&(tab[0])'' * Adres ''i''-tego elementu tablicy ''&(tab[i])'' to ''tab+i'' * Dostęp do ''i''-tego elementu tablicy ''tab[i]'' to ''*(tab+i)'' * Adresu przypisanego do zmiennej tablicowej nie można modyfikować, tzn. niedozwolona jest operacja ''tab%%++%%'' ===== Ćwiczenie - Czytaj linię ==== W języku C mamy do dyspozycji funkcję ''gets()'', która czyta linię tekstu ze standardowego wejścia (zobacz [[https://pl.wikibooks.org/wiki/C/gets|gets()]]). Jednak użycie tej funkcji jest niebezpieczne, gdyż nie jest zabezpieczona przed przepełnieniem bufora, tzn. taką sytuacją, gdy linia testu jest dłuższa niż ilość miejsca w tablicy, do której wczytujemy znaki. Napiszmy własną wersję funkcji ''gets()'', która będzie pozbawiona tej wady. **Opis funkcji**\\ Funkcja o nazwie ''czytaj_linie()'' czyta pojedynczą linię tekstu ze standardowego wejścia ale nie więcej niż ''n'' znaków. Kolejne znaki odczytane z wejścia umieszczane są w tablicy znakowej wskazywanej przez ''str'' tworząc napis (łańcuch znakowy), tzn. za ostatnim znakiem umieszczane jest zero (znak '''\0'''). Przy czym znak nowego wiersza ''\n'' nie jest umieszczany w napisie ''str''. Do wczytywania kolejnych znaków ze standardowego wejścia użyj funkcji ''[[http://pl.wikibooks.org/wiki/C/getchar|getchar()]]''. Jeżeli pierwszym odczytanym znakiem jest ''EOF'' (koniec strumienia) to funkcja kończy swoje działanie zwracając wartość ''EOF''. W przeciwnym wypadku funkcja zwraca liczbę przeczytanych znaków. **Argumenty funkcji:** tablica znakowa ''str'' oraz liczba całkowita ''n'' określająca maksymalną liczbę znaków jaka może zostać wczytana do tablicy ''str''\\ **Wartość zwracana:** funkcja zwraca liczbę całkowitą równą ilości przeczytanych znaków (długość linii tekstu) lub wartość ''EOF'', jeżeli pierwszym znakiem w strumieniu jest koniec pliku (''EOF''). Wykorzystaj funkcje ''czytaj_linię()'' do napisania programu, który ponumeruje linie wczytane ze standardowego wejścia. Tekst wejściowy czytany jest linia po linii aż do końca strumienia (do wystąpienia ''EOF'''). **Przykład:** Jeżeli na standardowym wejściu powyższego programu podamy tekst <code> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </code> wówczas na ekranie powinien pojawić się taki tekst: <code> 1: Lorem ipsum 2: dolor sit amet, 3: consectetur adipiscing elit. </code> ===== Ćwiczenie: odwracanie napisu ===== Napisz funkcję o nazwie ''odwroc()''', która odwraca kolejność znaków w napisie. Zaimplementuj funkcję zgodnie z poniższą specyfikacją: **Argumenty funkcji**: funkcja posiada jeden argument, jest to napis (tablica znakowa) **Wartość zwracana**: adres napisu podanego w argumencie, w którym znaki zostały odwrócone. Korzystając z funkcji ''odwroc()'' napisz program, który odwróci znaki każdej wczytanej linii tekstu. Program czyta kolejne linie tekstu ze standardowego wejścia aż do końca strumienia (końca pliku ''EOF''). Do odczytu linii możesz wykorzystać funkcję ''czytaj_linie'' z poprzedniego ćwiczenia. Każda kolejno wczytana linia tekstu jest następnie przekształcana za pomocą funkcji ''odwroc()'' i wypisywana na ekranie. **Przykład:** jeżeli na standardowym wejściu pojawi się linia tekstu <code> Lorem ipsum dolor sit amet, </code> to program wypisze <code> ,tema tis rolod muspi meroL </code> ===== Biblioteka string.h ===== W bibliotece standardowej znajduje się szereg funkcji związanych z operacjami na łańcuchach znakowych. Zadeklarowane są one w pliku [[http://www.cplusplus.com/reference/cstring/|string.h]]. Oto lista kilku wybranych funkcji: * [[https://pl.wikibooks.org/wiki/C/strlen|strlen]] - wyznacza długość napisu \\ <code C>int strlen(char *napis)</code> * [[https://pl.wikibooks.org/wiki/C/strcpy|strcpy]] - kopiowanie napisu z ''src'' do ''dest'' \\ <code C>char* strcpy(char *src, char* dest)</code> * [[https://pl.wikibooks.org/wiki/C/strcmp|strcmp]] - porównywanie napisów w porządku alfabetycznym \\ <code C>int strcmp(char *napis1, char* napis2)</code> * [[https://pl.wikibooks.org/wiki/C/strcat|strcat]] - łączenie napisów, dodaje ''src'' na końcu ''dest'' \\ <code C>char* strcat(char *src, char* dest)</code> * [[https://pl.wikibooks.org/wiki/C/strstr|strstr]] - znajduje ''wzor'' w napisie \\ <code C>char* strstr(char *napis, char* wzor)</code> ===== Ćwiczenie: unikatowe linie ===== Napisz program, który usuwa powtarzające się po sobie linie tekstu. Program czyta tekst ze standardowego wejścia aż do napotkania końca pliku (''EOF'') i wypisuje kolejne linie, z pominięciem tych, które się powtarzają. Do realizacji ćwiczenia wykorzystaj funkcje z biblioteki ''string.h''. Przykładowo, jeżeli na wejściu programu podamy następującą treść: <code> Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, consectetur adipiscing elit. consectetur adipiscing elit. </code> na wyjściu otrzymamy unikatowe linie <code> Lorem ipsum dolor sit amet, consectetur adipiscing elit. </code> ===== Zadnie - Szyfr cezara ===== Napisz program, który szyfruje tekst za pomocą (uogólnionego) szyfru Cezara. W tym celu zadeklaruj w programie funkcję o nazwie ''szyfr()'', która szyfruje tekst zawarty w tablicy znakowej zamieniając kolejne znaki alfabetu angielskiego na znaki stojące o ''n'' pozycji dalej w alfabecie. Przykładowo dla ''n=3'' litera ''a'' zamieniana jest na ''d'', litera ''b'' na ''e'', z kolei litera ''x'' zamieniana jest na ''a'', ''y'' na ''b'', ''z'' na ''c''. Zamianie ulegają wyłącznie znaki alfabetu angielskiego (małe litery ''a-z'' i duże ''A-Z''). Pozostałe znaki znajdujące się w napisie pozostają niezmienione. **Argumenty funkcji.** Funkcja ''szyfr()'' ma 2 argumenty: * tablica znakowa ''t'' zawierająca napis do zaszyfrowania * liczba całkowita ''n'' określająca o ile pozycji w alfabecie przesuwamy litery **Wartość zwracana funkcji:** adres tablicy ''t'' zawierającej zaszyfrowany napis w którym litery zostały zamienione na litery położone o ''n'' pozycji dalej w alfabecie. Wykorzystaj funkcję ''szyfr()'' do napisania programu służącego do szyfrowania tekstu za pomocą szyfru Cezara. Program na początku działania pobiera liczbę całkowitą ''n'' a następnie czyta kolejne linie tekstu aż do końca strumienia (''EOF''). Każda kolejna linia tekstu jest szyfrowana za pomocą funkcji ''szyfr()'' zgodnie z podaną wcześniej wartością przesunięcia ''n'' a wynik jest wypisywany na standardowym wyjściu. Zakładamy, że tekst nie będzie zawierał linii dłuższych niż 1000 znaków. **Przykłady działania.** \\ Dla danych wejściowych: <code> 3 Ala ma kota </code> na ekranie pojawi się Dkd pd nsxd Gdy podamy ujemną wartość ''n'' to możemy odszyfrować wcześniej zakodowaną wiadomość. <code> -3 Dkd pd nsxd Ala ma kota </code> Inny przykład: <code> 5 Ala ma kota Fqf rf ptyf a Ewa ma psa f Jcf rf uxf </code>