Wprowadzenie do programowania w języku C



Podobne dokumenty
Podstawy programowania w języku C++

Tablice deklaracja, reprezentacja wewnętrzna

Podstawy programowania

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Języki programowania obiektowego Nieobiektowe elementy języka C++

Podstawy programowania w języku C i C++

Podstawy programowania w języku C++

ŁAŃCUCHY W JĘZYKU C/C++

DANE TEKSTOWE W JĘZYKU C/C++ - TABLICE ZNAKOWE

Podstawy programowania w języku C++

Podstawy programowania w języku C i C++

Podstawy programowania w języku C++

Podstawy programowania w języku C++

Wprowadzenie do programowania w języku C

Wprowadzenie do programowania w języku C

Tablice, funkcje - wprowadzenie

Programowanie w języku C++

Podstawy programowania w języku C++

1 Przetwarzanie tablic znakowych

Podstawy programowania w języku C++

int tab[5]; tab[1]; ciągły obszar pamięci, w którym umieszczone są elementy tego samego typu macierz [ ] - dwuargumentowy operator indeksowania

Ćwiczenie nr 6. Poprawne deklaracje takich zmiennych tekstowych mogą wyglądać tak:

Języki programowania. Tablice struktur, pliki struktur. Część ósma. Autorzy Tomasz Xięski Roman Simiński

Podstawy programowania 1

Języki programowania. Przetwarzanie plików amorficznych Konwencja języka C. Część siódma. Autorzy Tomasz Xięski Roman Simiński

Operacje na łańcuchach znaków

Podstawy programowania w języku C++

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Podstawy programowania w języku C++

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 2. Karol Tarnowski A-1 p.

Podstawy programowania w języku C++

Programowanie w języku C++

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Laboratorium 3: Tablice, tablice znaków i funkcje operujące na ciągach znaków. dr inż. Arkadiusz Chrobot dr inż. Grzegorz Łukawski

Tablice wielowymiarowe. Przykład tablica 2-wymiarowa. Przykład. Przykład 3-wymiarowy. Tak naprawdę nie istnieją w C! Rozważmy tablicę o rozmiarze 3x2

Podstawy Programowania

Stałe, znaki, łańcuchy znaków, wejście i wyjście sformatowane

Tablice i struktury. czyli złożone typy danych. Programowanie Proceduralne 1

Katedra Elektrotechniki Teoretycznej i Informatyki. wykład 9 - sem.iii. Dr inż. M. Czyżak

Języki programowania obiektowego Nieobiektowe elementy języka C++

Podstawy programowania

Języki programowania obiektowego Nieobiektowe elementy języka C++

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 12. Karol Tarnowski A-1 p.

iii. b. Deklaracja zmiennej znakowej poprzez podanie znaku

Programowanie Proceduralne

Wprowadzenie do programowania w języku C

Wykład IV PASCAL - łańcuch znaków, - procedury i funkcje, - sortowanie bąbelkowe

Katedra Elektrotechniki Teoretycznej i Informatyki. wykład 7- sem.iii. M. Czyżak

Informatyka 1. Plan dzisiejszych zajęć. zajęcia nr 11. Elektrotechnika, semestr II rok akademicki 2008/2009

Laboratorium 6: Ciągi znaków. mgr inż. Leszek Ciopiński dr inż. Arkadiusz Chrobot dr inż. Grzegorz Łukawski

tablica: dane_liczbowe

wykład III uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - zarządzanie pamięcią, struktury,

Inicjacja tablicy jednowymiarowej

Podstawy programowania skrót z wykładów:

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 2. Karol Tarnowski A-1 p.

Struktury czyli rekordy w C/C++

Tablice, funkcje, wskaźniki - wprowadzenie

Wykład 6. Operacje na łańcuchach znakowych

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 2. Karol Tarnowski A-1 p.

Wstęp do wskaźników w języku ANSI C

Podstawy programowania w języku C++

2 Przygotował: mgr inż. Maciej Lasota

Wskaźniki w C. Anna Gogolińska

main( ) main( void ) main( int argc, char argv[ ] ) int MAX ( int liczba_1, liczba_2, liczba_3 ) źle!

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 3. Karol Tarnowski A-1 p.

TABLICE W JĘZYKU C/C++ typ_elementu nazwa_tablicy [wymiar_1][wymiar_2]... [wymiar_n] ;

dr inż. Jarosław Forenc

Spis treści JĘZYK C - ŁAŃCUCHY ZNAKÓW. Informatyka 2. Instrukcja do pracowni specjalistycznej z przedmiotu. Numer ćwiczenia INF22

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Języki i metodyka programowania. Wprowadzenie do języka C

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Pętle i tablice. Spotkanie 3. Pętle: for, while, do while. Tablice. Przykłady

Tablice. Monika Wrzosek (IM UG) Podstawy Programowania 96 / 119

Struktura programu. Projekty złożone składają się zwykłe z różnych plików. Zawartość każdego pliku programista wyznacza zgodnie z jego przeznaczeniem.

Podstawy Programowania. Specyfikacja funkcji, operacje wejścia i wyjścia na plikach, rekurencja, tablice i wskaźniki

Tablice. int rozmiar; cout << Jaki ma być rozmiar tabeli? ; cin >> rozmiar; { int tablica[rozmiar]; /* TU JEST ŹLE */... }

KURS C/C++ WYKŁAD 6. Wskaźniki

Biblioteka standardowa - operacje wejścia/wyjścia

Ghost in the machine

Wykład 2 Składnia języka C# (cz. 1)

Wprowadzenie do programowanie obiektowego w języku C++

Język C, tablice i funkcje (laboratorium, EE1-DI)

1 P roste e t ypy p d a d n a ych c - c ąg ą g d a d l a szy 2 T y T py p z ł z o ł żo ż ne e d a d n a ych c : T BLICE

Plik jest reprezentowany przez strumień znaków (bajtów) o zmiennej długości. Koniec strumienia identyfikowany jest znacznikiem końca pliku EOF.

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

Wyklad 7 Funkcje (c.d.). Tablice jednowymiarowe znaków

Programowanie w C Typ wskaźnikowy do typu znakowego i operacje na łańcuchach

Podstawy programowania. Wykład 6 Złożone typy danych: struktury, unie. Krzysztof Banaś Podstawy programowania 1

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Laboratorium 6: Dynamiczny przydział pamięci. dr inż. Arkadiusz Chrobot dr inż. Grzegorz Łukawski

Programowanie strukturalne i obiektowe

Podstawy programowania. Wykład: 9. Łańcuchy znaków. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Spis treści JĘZYK C - ŁAŃCUCHY ZNAKÓW. Informatyka 1. Instrukcja do pracowni specjalistycznej z przedmiotu. Numer ćwiczenia INF10Z

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Reprezentacja symboli w komputerze. Znaki alfabetu i łańcuchy znakowe. Programowanie Proceduralne 1

Spis treści WSTĘP CZĘŚĆ I. PASCAL WPROWADZENIE DO PROGRAMOWANIA STRUKTURALNEGO. Rozdział 1. Wybór i instalacja kompilatora języka Pascal

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

Transkrypt:

Wprowadzenie do programowania w języku C Część piąta Tablice koncepcja, reprezentacja, przetwarzanie Autor Roman Simiński Kontakt siminski@us.edu.pl www.us.edu.pl/~siminski Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa. Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne. Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione.

Tablice deklaracja, reprezentacja wewnętrzna Co to jest tablica? Tablica jest zmienną złożoną z elementów tego samego typu. Obejmuje ona ciągły obszar pamięci operacyjnej dokładnie tak duży, aby zmieścić wszystkie jej elementy. Termin tablica w języku potocznym jest zmiennikiem sformułowania zmienna tablicowa. Po co się stosuje tablice? Tablice stosuje się wtedy, gdy trzeba zgromadzić wiele obiektów tego samego typu w jednej strukturze danych, i w sposób wygodny przetwarzać je według jednorodnego schematu. Dwie istotne własności tablic (wg. standardu C89): tablica zawsze składa się z ustalonej, i znanej na etapie kompilacji, liczby elementów, liczba elementów tablicy nie ulega zmianie w trakcie działania programu tablice są statyczne. Copyright Roman Simiński Strona : 2

Tablice deklaracja, reprezentacja wewnętrzna Deklaracja zmiennych tablicowych Ogólna postać deklaracji tablicy zmiennej tablicowej: typ_elemetu nazwa_tablicy[ <wyraż enie_ stałe> ] wyrażenie_ stałe wyrażenie określające liczbę elementów tablicy, wartość tego wyrażenia musi być znana na etapie kompilacji. Dziesięcioelementowa tablica liczb całkowitych Różne warianty deklaracji C C++ int tab[ 10 ]; poprawne poprawne #define N 10 int tab[ N ]; poprawne poprawne const int N = 10; niepoprawne poprawne int tab[ N ] Kwalifikator typu const może wystąpić z każdą specyfikacją typu. Zmienna z const powinna być zainicjowana ale potem nie może zmieniać wartości. Zmienna z kwalifikatorem const w języku C nie jest traktowana jako stała i nie może być wykorzystywana do określania rozmiaru tablicy. Copyright Roman Simiński Strona : 3

Tablice deklaracja, reprezentacja wewnętrzna Reprezentacja tablicy w pamięci operacyjnej Elementy tablicy numerowane są zawsze od 0. Zatem jeżeli N oznacza liczbę elementów tablicy, to ostatni jej element ma numer N - 1. #define N 10 int tab[ N ]; tab Dowoływanie się do elementów tablicy 10 elementów 0 1 2 3 4 5 6 7 8 9 tab[ 0 ] = 1; tab[ N - 1 ] = 5; a = 2 * tab[ 3 ]; int i = 0, j = N 1; a = tab[ i ] + tab [ j ]; W języku C i C++ nie ma żadnych wbudowanych mechanizmów zabezpieczających przed odwoływaniem się do elementów leżących poza zakresem indeksowym tablic! tab[ 12 ] = 10; tab 0 1 2 3 4 5 6 7 8 9?? 10 10 11 12 Obszar poza zakresem tablicy! Copyright Roman Simiński Strona : 4

Tablice deklaracja, reprezentacja wewnętrzna Tablice wolno inicjalizować na etapie deklaracji: Jeżeli inicjalizowana tablica nie posiada określonego rozmiaru, ostanie on określony na podstawie liczby elementów inicjalizujących. Jeżeli liczba wartości początkowych jest mniejsza od rozmiaru tablicy, to elementy o brakujących wartościach początkowych otrzymują wartość zero (zmienne zewnętrzne, statyczne i automatyczne). Podanie zbyt wielu wartości początkowych jest błędem. Nie ma sposobu na zainicjowanie środkowego elementu bez podania wszystkich wartości pośrednich. Typowa inicjalizacja int tab[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; Rozmiar określony liczbą wartości początkowych int dni_miesiecy[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };` Zbyt mało warości początkowych float przychody[ 12 ] = { 0, 0, 0 }; /* Za mało wartości początkowych */ Copyright Roman Simiński Strona : 5

Tablice przetwarzanie Typowe operacje na tablicach Przetwarzanie tablic realizowane jest zwykle z wykorzystaniem instrukcji iteracyjnych. Do przetwarzania tablic najczęściej wykorzystuje się iterację for. #define N 10 int tab[ N ]; int i; Ustawianie wartości wszystkich elementów tablicy, np. zerowanie: Wersja pierwsza: for( i = 0; i < N; i++ ) tab[ i ] = 0; Wersja druga: for( i = 0; i < N; tab[ i++ ] = 0 ) ; Ogólnie, wypełnianie pewnym wzorcem pattern: int pattern = -1; for( i = 0; i < N; tab[ i++ ] = pattern ) ; Copyright Roman Simiński Strona : 6

Tablice przetwarzanie Typowe operacje na tablicach, cd.... #define N 10 int tab[ N ]; int i; Wczytywanie danych ze strumienia stdin do tablicy: Wersja pierwsza: char linia[ 80 ]; for( i = 0; i < N; i++ ) { printf( "\n>" ); fgets( linia, 80, stdin ); tab[ i ] = atoi( linia ); } Copyright Roman Simiński Strona : 7

Tablice przetwarzanie Typowe operacje na tablicach, cd.... #define N 10 int tab[ N ]; int i; Wczytywanie danych ze strumienia stdin do tablicy: Wersja druga, z wykorzystaniem funkcji wczytaj_liczbe_int: for( i = 0; i < N; i++ ) tab[ i ] = wczytaj_liczbe_int( "\n>" ); Przykładowa realizacja funkcji wczytaj_liczbe_int: int wczytaj_liczbe_int( char komunikat[] ) { char bufor_tekstowy[ 80 ]; } printf( komunikat ); fgets( bufor_tekstowy, 80, stdin ); return atoi( bufor_tekstowy ); Copyright Roman Simiński Strona : 8

Tablice przetwarzanie Typowe operacje na tablicach, cd.... #define N 10 int tab[ N ]; int i; Wyprowadzanie danych z tablicy do strumienia stdout: Wersja pierwsza: for( i = 0; i < N; i++ ) printf( "\n%d", tab[ i ] ); Wersja druga: for( i = 0; i < N; printf( "\n%d", tab[ i++ ] ) ) ; Na marginesie... Uwaga na takie konstrukcje: x = tab[ ++i ] + tab[ i ]; tab[ ++i ] = a * ++i; Copyright Roman Simiński Strona : 9

Tablice przetwarzanie Typowe operacje na tablicach, cd.... #define N 10 int tab[ N ]; int i; Sumowanie liczb zapisanych w tablicy: Wersja pierwsza: int suma = 0; for( i = 0; i < N; i++ ) suma = suma + tab[ i ]; Wersja druga: int suma; for( i = 0, suma = 0; i < N; suma += tab[ i++ ] ) ; Copyright Roman Simiński Strona : 10

Tablice przetwarzanie Typowe operacje na tablicach, cd.... #define N 10 int tab[ N ]; int i; Przykładowe dziwactwo : Wyznaczanie sumy co drugiego, dodatniego elementu tablicy, podzielnego przez 3: int suma; for( i = 0, suma = 0; i < N; i+= 2 ) if( tab[ i ] > 0 ) if( tab[ i ] % 3 == 0 ) suma += tab[ i ]; Ponieważ wyrażenia logiczne w języku C nie są wartościowane kompletnie : int suma; for( i = 0, suma = 0; i < N; i+= 2 ) if( tab[ i ] > 0 && tab[ i ] % 3 == 0 ) suma += tab[ i ]; Copyright Roman Simiński Strona : 11

Tablice przetwarzanie Kopiowanie zawartości tablic #define N 5 int a[] = { 1, 2, 3, 4, 5 }; int b[ N ]; int i; Tak w języku C nie wolno: b = a; /* Nie wolno przypisywać do siebie tablic */ Trzeba: for( i = 0; i < N; i++ ) b[ i ] = a[ i ]; Uwaga na niejednakowe rozmiary tablic #define SIZE_A 30 #define SIZE_B 20 int a[ SIZE_A ]; int b[ SIZE_B ]; for( i = 0; i < SIZE_B; i++ ) b[ i ] = a[ i ]; Copyright Roman Simiński Strona : 12

Tablice przetwarzanie Kopiowanie zawartości tablic, cd.... Czasem warto napisać funkcję do kopiowania zawartości tablic: void copy_int_table( int d[], int s[], int n ) { int i = 0; for( i = 0; i < n; i++ ) d[ i ] = s[ i ]; } Lub krócej: void copy_int_table( int d[], int s[], int n ) { while( --n >= 0 ) d[ n ] = s[ n ]; } Z tymi parametrami formalnymi to coś nie gra... W języku C nazwy tablic są traktowane w specyficzny sposób. O tym już niedługo. Z tego powody wolno definiować tablicowe parametry formalne bez rozmiaru. Taki parametr przyjmuje do siebie tablicę o dowolnym rozmiarze. Tablice pozornie zachowują się tak, jakby były przekazywane przez zmienną. Copyright Roman Simiński Strona : 13

Tablice przetwarzanie Kopiowanie zawartości tablic, rozwiązania alteratywne Ponieważ z definicji tablice to spójne obszary pamięci operacyjnej, można do ich kopiowania użyć funkcji memmove lub memcpy (nagłówek mem.h, zgodne z ANSI C): memmove( b, a, N * sizeof( int ) ); Lub sprytniej: memmove( b, a, N * sizeof( b[ 0 ] ) ); Alternatywnie: memcpy( b, a, N * sizeof( int ) ); Lub sprytniej: memcpy( b, a, N * sizeof( b[ 0 ] ) ); memmove( dest, src, n ); Kopiuje blok n bajtów z lokalizacji src do dest. Lokalizacje te mogą się nakładać. memcpy( dest, src, n ); Kopiuje blok n bajtów z lokalizacji src do dest. Gdy lokalizacje te się nakładają, działanie funkcji jest niezdefiniowane. Na marginesie,alternatywa dla iteracyjnego zerowania tablicy Można do tego wykorzystać funkcję memset : memset( b, 0, N * sizeof( b[ 0 ] ) ); memset( s, c, n ); Wypełnia n pierwszych bajtów obszaru s bajtem o wartości c. Copyright Roman Simiński Strona : 14

Łańcuchy znakowe koncepcja, reprezentacja wewnętrzna Łańcuchy znakowe jako tablice znaków ze znacznikiem końca Do reprezentacji łańcuchów znakowych w języku C wykorzystuje się zwykłe tablice znakowe. Tablice takie nie różnią się od innych tablic w języku C, wprowadzono jedynie kilka udogodnień czyniących łatwiejszym manipulowanie takimi tablicami. Podstawowy problem zmienna długość łańcuchów znakowych W języku C przyjęto koncepcję łańcuchów ze znacznikiem końca (ang. null terminated strings). To jest napis a to jego reprezentacja wewnętrzna: T o j e s t n a p i s \0 Fizyczna długość napisu = liczba znaków + 1 Znacznik końca napisu \0 to znak o kodzie 0 Copyright Roman Simiński Strona : 15

Łańcuchy znakowe koncepcja, reprezentacja wewnętrzna Deklarowanie i inicjowanie zmiennych łańcuchowych Tablice znakowe można inicjować w zwykły sposób, przewidziany dla tablic: #define N 80 char imie[ N ] = { A, g, a }; /* \0??? */ char imie[] = { A, g, a, \0 }; /* \0!!! */ choć można wykorzystywać wygodniejszą formę: char imie[ N ] = "Aga"; Uwaga powyższe przypisanie wystąpić może jedynie przy definicji zmiennej! Reprezentacja wewnętrzna Literał łańcuchowy : Zmienna imie : A g a \0 0 1 2 3 A g a \0 0 1 2 3 4 5 78 79 Copyright Roman Simiński Strona : 16

Łańcuchy znakowe koncepcja, reprezentacja wewnętrzna Deklaracja łańcucha zainicjowanego napisem pustym char imie[ N ] = { \0 }; char imie[ N ] = ""; Reprezentacja wewnętrzna łańcucha pustego: Zmienna imie: \0 Ustawianie łańcucha pustym w po deklaracji 0 1 2 3 4 5 78 79 imie[ 0 ] = \0 ; imie = ""; /* Błąd,tak nie wolno */ Copyright Roman Simiński Strona : 17

Łańcuchy znakowe typowe operacje Ogólny schemat przetwarzania tablic znakowych Przetwarzanie tablic polega zwykle na przemaszerowaniu zmienna indeksową po tablicy, dopóki nie ma końca napisu oznaczanego znakiem \0 : int i; char s[ N ]; for( i = 0; s[ i ]!= \0 ; i++ ) < tu jakie ś operacje na każdym znaku s[ i ] > Wyprowadzanie napisu do stdout znak po znaku: int i; char s[ N ]; for( i = 0; s[ i ]!= \0 ; i++ ) putchar( s[ i ] ); Albo w krótszej postaci: int i; char s[ N ]; for( i = 0; s[ i ]!= \0 ; putchar( s[ i++ ] ) ) ; Copyright Roman Simiński Strona : 18

Łańcuchy znakowe typowe operacje Przetwarzanie z wykorzystaniem funkcji bibliotecznych string.h Do manipulowania tablicami znakowymi opracowano szereg funkcji bibliotecznych (plik nagłówkowy string.h),... większość z nich można łatwo napisać samemu! Funkcja strlen wyznaczanie długości łańucha Rezultatem funkcji strlen jest liczba znaków napisu, przekazanego tej funkcji parametrem. #define N 80 char napis[ N ] = ""; printf( "Liczba znaków w łańcuchu:%s wynosi:%d", napis, strlen( napis ) ); Liczba znaków w łańcuchu: wynosi:7 Alternatywny schemat przetwarzania napisów (z wykorzystaniem strlen): int i, len; char s[ N ]; Uwaga nigdy tak i < strlen( s ) for( i = 0, len = strlen( s ) ; i < len; putchar( s[ i++ ] ) ) ; Copyright Roman Simiński Strona : 19

Łańcuchy znakowe typowe operacje Funkcja strlen przykładowe realizacje Iteracja while int strlen( char s[] ) { int len = 0; while( s[ len ]!= '\0' ) len++; } return len; Iteracja for int strlen( char s[] ) { int len; for( len = 0; s[ len ]!= '\0'; len++ ) ; return len; } Copyright Roman Simiński Strona : 20

Łańcuchy znakowe typowe operacje Funkcje strupr i strlwr przykładowe realizacje Konwersja - małe litery na duże: strupr, duże litery na małe: strlwr. char a[] = "ALA"; char b[] = "ala"; strlwr( a ); /* Po wywołaniu strlwr zmienna a zawiera napis "ala" */ strupr( b ); /* Po wywołaniu strupr zmienna a zawiera napis "ALA" */ Funkcja strupr void strupr( char s[] ) { int i; for( i = 0; s[ i ]!= '\0'; i++ ) s[ i ] = toupper( s[ i ] ); } Konwersja elementu tablicy, toupper zamienia znak będący parametrem na literę dużą, o ile był literą małą. Funkcja strlwr void strlwr( char s[] ) { int i; for( i = 0; s[ i ]!= '\0'; i++ ) s[ i ] = tolower( s[ i ] ); } Konwersja elementu tablicy, tolower zamienia znak będący parametrem na literę małą, o ile był literą dużą. Copyright Roman Simiński Strona : 21

Łańcuchy znakowe typowe operacje Funkcja strcpy koncepcja kopiowania napisów Pamiętamy, że w języku nie można kopiować zawartości tablic wykorzystując operator przypisania. char s1[ 80 ] = ""; char s2[ 20 ]; s2 = s1; /* Tak nie wolno!!! */ Do kopiowania zawartości tablic znakowych używamy funkcji strcpy: strcpy( s2, s1 ); Funkcja strcpy kopiuje zawartość tablicy znakowej s1 do tablicy s2. Kopiowaniu podlegają wszystkie znaki łańcucha s1 (aż do \0), zakłada się, że tablica s2 ma rozmiar wystarczający na pomieszczenie kopiowanych znaków. Funkcja strcpy służy również do kopiowania literałów łańcuchowych: strcpy( s1, "Programowanie " ); strcpy( s2, "w języku C" ); Copyright Roman Simiński Strona : 22

Łańcuchy znakowe typowe operacje Funkcja strcpy przykładowe realizacje Funkcja strcpy wersja pierwsza, iteracja for char s1[ 80 ] = ""; char s2[ 20 ]; strcpy( s2, s1 ); s i++ s1 J ę z y k C \0 0 1 2 3 4 5 6 79 d s2 J ę z y k C \0 0 1 2 3 4 5 6 19 void strcpy( char d[], char s[] ) { int i; for( i = 0; s[ i ]!= '\0'; i++ ) d[ i ] = s[ i ]; d[ i ] = '\0'; } Ta wersja funkcji strcpy przepisuje znacznik końca napisu z tablicy s do d, jednak dzieje się to poza iteracją, tuż po jej zakończeniu: d[ i ] = '\0'; Copyright Roman Simiński Strona : 23

Łańcuchy znakowe typowe operacje Funkcja strcpy przykładowe realizacje, cd.... Funkcja strcpy wersja druga, iteracja for void strcpy( char d[], char s[] ) { int i = 0; while( ( d[ i ] = s[ i ] )!= '\0' ) i++; } Jak to działa? W języku C operator przypisania jest lewostronnie łączny. Pozwala to na pisanie następujących konstrukcji, np.: d[ 0 ] = d[ 1 ] = d[ 2 ] = 0; Konstrukcja: ( d[ i ] = s[ i ] )!= '\0' przypisuje i-ty element tablicy s do i-tego elementu tablicy d. Przypisana wartość jest następnie porównywana (operator!=) ze znacznikiem końca napisu '\0'. Ta wersja funkcji strcpy przepisuje znacznik końca napisu z tablicy s do d w iteracji while. Copyright Roman Simiński Strona : 24

Łańcuchy znakowe typowe operacje Co się stanie, gdy tablica docelowa jest za krótka? void main() { char s1[ 5 ] = "AAAA"; char c1 = 'A'; char c2 = 'B'; char s2[ 5 ] = "BBBB"; } strcpy( s2, "XXXXXXXXXXXXXXXXXXXX" ); printf( "\ns1 : %s\nc1 : %c\nc2 : %c\ns2 : %s", s1, c1, c2, s2 ); Gdzie oryginalna zawartość tablicy s1? Co się stało ze zmienną c2? Dlaczego zmienna c1 jest OK? Nigdy nie należy zakładać, że się uda, czyli że tablica docelowa jest wystarczająco długa. Należy szacować, przewidywać, jeszcze raz przewidywać programować defensywnie. Copyright Roman Simiński Strona : 25

Łańcuchy znakowe typowe operacje Funkcja strcat przykładowa realizacja Funkcja strcat dołącza zawartość tablicy znakowej s1 do tablicy s2. Kopiowaniu podlegają wszystkie znaki łańcucha s1 (aż do \0), zakłada się, że tablica s2 ma rozmiar wystarczający na pomieszczenie kopiowanych znaków. strcpy( s1, "Programowanie " ); strcpy( s2, "w języku C" ); strcat( s1, s2 ); puts( s1 ); Programowanie w języku C Jak to działa? void strcat( char d[], char s[] ) { int i = 0, j = 0; Znajdź znacznik końca napisu docelowego, zapamiętaj jego pozycje w zmiennej i. } while( d[ i ]!= \0 ) i++; while( ( d[ i++ ] = s[ j++ ] )!= \0 ) ; Przepisz elementy tablicy s do tablicy d. Maszeruj zmienną j od początku tablicy s, zmienną i od pozycji znalezionego wcześniej znacznika końca napisu. Copyright Roman Simiński Strona : 26

Łańcuchy znakowe typowe operacje Jak nie dopuszczać do przepełnienia bufora? Biblioteka funkcji operujących na tablicach znaków zawiera funkcje wykonujące operacje analogiczne do przedstawionych uprzednio, pozwalające na kontrolę liczby znaków biorących udział np. w kopiowaniu. Są to np. funkcje: strncpy, strncat, strnset. #define N 10 #define M 80 char s1[ N ]; char s2[ M ] = " jest świetny lecz pełen pułapek"; strncpy( s1, s2, N - 1 ); strncpy( s1, s2, sizeof( s1 ) - 1 ); s1[ N - 1 ] = '\0'; s1[ sizeof( s1 ) - 1 ] = '\0'; puts( s1 ); puts( s1 ); Ciekawostka Funkcja strncpy nie zawsze przekopiuje \0! Często rezultatem funkcji operujących na tablicach są one same. Rezultatem funkcji strncpy jest tablica będąca pierwszym parametrem a więc, w naszym przypadku, s1. strncpy( s1, s2, N - 1 ) [ N - 1 ] = '\0'; s1 Skrócona wersja kopiowania i dopisywania znacznika końca napisu Copyright Roman Simiński Strona : 27

Łańcuchy znakowe typowe operacje Funkcja strncpy przykładowa, bezpieczniejsza realizacja Wersja z iteracją while void strncpy_while( char d[], char s[], int n ) { int i = 0; while( ( d[ i ] = s[ i ] )!= '\0' && i < n ) i++; while( i <= n ) d[ i++ ] = '\0'; } Wersja z iteracją for void strncpy_for( char d[], char s[], int n ) { int i = 0; for( ; ( d[ i ] = s[ i ] )!= '\0' && i < n ; i++ ) ; for( ; i <= n ; d[ i++ ] = '\0' ) ; } Copyright Roman Simiński Strona : 28