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

Podobne dokumenty
Podstawy programowania w języku C++

Podstawy programowania w języku C++

Podstawy programowania w języku C++

Wprowadzenie do programowania w języku C

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

Podstawy programowania

Podstawy programowania w języku C++

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

Podstawy programowania w języku C++

Tablice deklaracja, reprezentacja wewnętrzna

Programowanie w języku C++

Podstawy programowania w języku C++

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

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

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

Lab 9 Podstawy Programowania

DYNAMICZNE PRZYDZIELANIE PAMIECI

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

ZASADY PROGRAMOWANIA KOMPUTERÓW

Wskaźniki w C. Anna Gogolińska

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

Wprowadzenie do programowania w języku C

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Wskaźniki. Informatyka

Podstawy programowania w języku C++

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

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Wykład 1: Wskaźniki i zmienne dynamiczne

Struktury czyli rekordy w C/C++

// Liczy srednie w wierszach i kolumnach tablicy "dwuwymiarowej" // Elementy tablicy są generowane losowo #include <stdio.h> #include <stdlib.

Laboratorium nr 9. Temat: Wskaźniki, referencje, dynamiczny przydział pamięci, tablice dynamiczne. Zakres laboratorium:

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

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

Wskaźniki. Programowanie Proceduralne 1

Stałe, tablice dynamiczne i wielowymiarowe

Podstawy programowania w języku C++

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

Podstawy programowania komputerów

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

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

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

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Podstawy programowania w języku C i C++

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

Techniki Programowania wskaźniki

Języki i metodyka programowania. Wskaźniki i tablice.

utworz tworzącą w pamięci dynamicznej tablicę dwuwymiarową liczb rzeczywistych, a następnie zerującą jej wszystkie elementy,

Tablice, funkcje, wskaźniki - wprowadzenie

Podstawy programowania w języku C++

Programowanie w C++ Wykład 4. Katarzyna Grzelak. 19 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 37

dr inż. Paweł Myszkowski Wykład nr 8 ( )

Programowanie komputerowe. Zajęcia 4

Powyższe wyrażenie alokuje 200 lub 400 w zależności od rozmiaru int w danym systemie. Wskaźnik wskazuje na adres pierwszego bajtu pamięci.

Struktury, unie, formatowanie, wskaźniki

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Dla każdej operacji łącznie tworzenia danych i zapisu ich do pliku przeprowadzić pomiar czasu wykonania polecenia. Wyniki przedstawić w tabelce.

Tablice, funkcje - wprowadzenie

Język C++ Różnice między C a C++

Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

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

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

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

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

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Zmienne i struktury dynamiczne

Wykład nr 3. Temat: Wskaźniki i referencje. Edward Morgan Forster

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

1 Przetwarzanie tablic znakowych

Podstawy programowania. Wykład: 8. Wskaźniki. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

W dowolnym momencie można zmienić typ wskaźnika.

Konstruktor kopiujacy

Wykład 4: Klasy i Metody

Uzupełnienie dot. przekazywania argumentów

część 8 wskaźniki - podstawy Jarosław Gramacki Instytut Informatyki i Elektroniki Podstawowe pojęcia

Materiał Typy zmiennych Instrukcje warunkowe Pętle Tablice statyczne Wskaźniki Tablice dynamiczne Referencje Funkcje

Programowanie i struktury danych

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

Jak Windows zarządza pamięcią?

Język C zajęcia nr 11. Funkcje

iii. b. Deklaracja zmiennej znakowej poprzez podanie znaku

Algorytmy i złożoności. Wykład 3. Listy jednokierunkowe

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Programowanie w języku C++

Podstawy programowania 1

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

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

PARADYGMATY PROGRAMOWANIA Wykład 4

Typy wyliczeniowe Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Wykład II. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Programowanie obiektowe W3

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

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

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

tablica: dane_liczbowe

1 Wskaźniki. 1.1 Główne zastosowania wskaźników

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Stałe i zmienne znakowe. Stała znakowa: znak

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

Transkrypt:

Języki programowania obiektowego Nieobiektowe elementy języka C++ Roman Simiński roman.siminski@us.edu.pl www.programowanie.siminskionline.pl Tablice a zmienne wskaźnikowe

Nazwa tablicy jako wskaźnik na jej początek Nazwa tablicy jest interpretowana jako ustalony wskaźnik na jej początek (pierwszy element). int tab[ 10 ]; 10 elementów 0 1 2 3 4 5 6 7 8 9 tab Pierwszy element: tab[ 0 ] 2

Nazwa tablicy jako wskaźnik na jej początek, cd.... int tab[ 10 ]; int * p; p = tab; 10 elementów 0 1 2 3 4 5 6 7 8 9 p tab Pierwszy element: tab[ 0 ] Przypisanie: p = tab; Jest równoznaczne z: p = &tab[ 0 ]; 3

Nazwa tablicy jako wskaźnik na jej początek, cd.... tab[ 0 ] = 5; tab[ 1 ] = 1; tab[ 2 ] = 10; tab[ i ] = 22; Odwołania równoważne *p = 5 *( p + 1 ) = 1 *( p + 2 ) = 10 *( p + i ) = 22 0 1 2 3 i 8 9 p tab p + 0 p + 1 p + 2 p + 3 p + i 4

Nazwa tablicy jako wskaźnik na jej początek, cd.... Nazwa tablicy z indeksem Wskaźnik z przesunięciem Odwołania równoważne 0 1 2 3 i 8 9 p tab Odwołanie: *( p + i ) Odwołanie: tab[ i ] 5

Nazwa tablicy jako wskaźnik na jej początek, cd.... Wyrażenie p + i jest wyrażeniem wskaźnikowym, wskazuje ono na obiekt oddalony o i obiektów danego typu od p. Wartość dodawana do wskaźnika jest skalowana rozmiarem typu obiektu wskazywanego. Każde odwołanie: tab[ i ]; można zapisać tak: *( tab + i ) A także: Każde odwołanie: *( p + i ) można zapisać tak: p[ i ]; 6

Uwaga, wskaźnik to nie tablica! int tab[ 10 ]; int * p = tab; Czy to jest to samo? Nie! int tab[ 10 ] obszar danych + wskaźnika na jego początek Nazwa tablicy 10 elementów tab 0 1 2 3 4 5 6 7 8 9 p int * p = tab wskaźnik zakotwiczony o początek tablicy 7

Nazwa tablicy to ustalony wskaźnik na jej początek Nazwa tablicy jest ustalonym (niemodyfikowalnym) wskaźnikiem na pierwszy jej element. Nazw tablic nie wolno modyfikować! Zwykłe wskaźniki można. int tab[ 10 ]; int * p = tab; tab = p; tab++; Źle p = tab + 8; p++; OK 8

Ciekawostka Wiemy, że odwołanie: Oraz, że odwołanie tab[ i ] można zapisać tak: *( tab + i ) *( tab + i ) można zapisać tak: tab[ i ] Wiemy również, że dodawanie jest przemienne, zatem każde odwołanie: *( tab + i ) można zapisać tak: *( i + tab ) Czy zatem odwołanie: *( i + tab ) można zapisać tak: i[ tab ]? 9

Ciekawostka, cd.... Tak, można, dla kompilatora nie ma to większego znaczenia. char napis[] = "język c"; cout << napis << endl; 0[ napis ] = 'J'; // Zamiast napis[ 0 ] 6[ napis ] = 'C'; // Zamiast napis[ 6 ] język c Język C cout << napis << endl; 10

Dlaczego nie wolno przypisywać tablic, posługując się ich nazwami? int a[ 10 ]; int b[ 10 ]; b = a; // Nie wolno przypisywać do siebie tablic! Gdyby przypisywanie było możliwe... a b 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8 9 6 7 8 9 To po wykonaniu tej linii: b = a; gubimy obszar danych tablicy b! 0 1 2 3 4 5 a 6 7 8 9 b 0 1 2 3 4 5 6 7 8 9 11

Arytmetyka na wskaźnikach podsumowanie Dozwolone operacje wskaźnikowe to: przypisywanie wskaźników do obiektów tego samego typu, przypisywanie wskaźników do obiektów innego typu po konwersji, dodawanie lub odejmowanie wskaźnika i liczby całkowitej, odejmowanie lub porównanie dwóch wskaźników (zwykle związanych z tą samą tablicą), przypisanie wskaźnikowi wartości zero (lub wskazania puste NULL) lub porównanie ze wskazaniem pustym. 12

Pod lupą tablice jako parametry funkcji Załóżmy, że funkcja putstring wyprowadza zawartość tablicy znaków do strumienia wyjściowego programu. char napis[] = "C++"; putstring( napis ); Co jest parametrem aktualnym wywołania funkcji putstring? Tablica o nazwie napis. Czy napewno? No, właściwie parametrem jest napis, a to nazwa tablicy.... A czym jest nazwa tablicy? Nazwa tablicy to ustalony wskaźnik na jej pierwszy element.... Co z tego wynika? 13

Pod lupą tablice jako parametry funkcji Jak zdefiniujemy parametr formalny funkcji putstring? void putstring( char s[] ) Ale co naprawdę przekazujemy funkcji putstring? Nazwę tablicy, czyli ustalony wskaźnik na jej pierwszy element.... A zatem definicja parametru formalnego może wyglądać tak: void putstring( char * s ) Zrozumiałe? Jeżli tak, to czas wyjaśnić do końca sprawę przekazywania tablic jako parametrów funkcji.... 14

Naga prawda o tablicach przekazywanych do funkcji Uwaga to nie same tablice są przekazywane jako parametry do funkcji! Do wnętrza funkcji przekazywane są wskaźniki na tablice. Dzięki temu wnętrze funkcji ma dostęp do elementów tablicy. Paramterem aktualnym wywołania funkcji jest wskaźnik a nie sama tablica! Paramterem formalnym funkcji jest wskaźnik a nie tablica! char napis[] = "C++"; putstring( napis ); void putstring( char * s ) 15

Naga prawda o tablicach przekazywanych do funkcji char napis[] = "C++"; putstring( napis ); void putstring( char * s ) Na etapie wywołania funkcji putstring następuje klasyczne przekazanie parametrów przez wartość. Parametr aktualny wywołania to napis, który jest wskaźnikiem na pierwszy element tablicy. Kopiowany jest on do paramteru formalnego s, który od tego momentu wskazuje na to samo co napis. napis C + + \0 s We wnętrzu funkcji można dowolnie modyfikować wartość wskaźnika s, jest on bowiem kopią oryginalnej lokalizacji początku tablicy. 16

Wskaźniki w akcji metamorfoza funkcji putstring char napis[] = "C++"; putstring( napis ); void putstring( char s[] ) int i; for( i = 0; s[ i ]!= '\0'; i++ ) putchar( s[ i ] ); Wersja pierwotna void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Przechodzimy na wskaźniki Eliminujemy zmienną i Jak to działa...? 17

Wywołanie funkcji putstring char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Kopiowanie parametru aktualnego napis do parametru s napis C + + \0 s 18

Parametr s jest kopią wskaźnika napis char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Kopiowanie parametru aktualnego napis do parametru s napis C + + \0 s 19

Czy obiekt wskazywany przez s jest znacznikiem końca napisu? char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na pierwszy element tablicy napis napis C + + \0 s? *s!= '\0'? 20

Znak wskazywany przez s wyprowadzamy jest do stdout char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na pierwszy element tablicy napis *s C napis C + + \0 s 21

Wskaźnik s przesuwamy na następny znak char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis C napis s C + + \0 s++ 22

Czy obiekt wskazywany przez s jest znacznikiem końca napisu? char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis C napis C + + \0 s? *s!= '\0'? 23

Znak wskazywany przez s wyprowadzamy jest do stdout char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis *s C+ napis C + + \0 s 24

Wskaźnik s przesuwamy na następny znak char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis C+ napis s C + + \0 s++ 25

Czy obiekt wskazywany przez s jest znacznikiem końca napisu? char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis C+ napis C + + \0 s? *s!= '\0'? 26

Znak wskazywany przez s wyprowadzamy jest do stdout char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis *s C++ napis C + + \0 s 27

Wskaźnik s przesuwamy na następny znak char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis C++ napis s C + + \0 s++ 28

Czy obiekt wskazywany przez s jest znacznikiem końca napisu? char napis[ 80 ] = "C++"; putstring( napis ); void putstring( char * s ) for( ; *s!= '\0'; s++ ) putchar( *s ); Parametr s wskazuje na kolejny element tablicy napis C++ napis C + + \0 s? *s!= '\0'? Koniec napisu, koniec iteracji. 29

Wskaźniki w akcji koniec metamorfozy void putstring( char * s ) for( ; *s!= '\0' ; putchar( *s++ ) ) ; Kompresja iteracji for Najpierw pobierz znak wskazywany przez s, użyj go. *s ++ Potem zwiększ o jeden wartość wskaźnika s będzie on wtedy wskazywał na następny element tablicy. void putstring( char * s ) while( *s ) putchar( *s++ ); Iteracja while nie jest taka zła... Znak '\0' to bajt o wartości 0 30

Wskaźniki pod lupą funkcja strcpy w wersji klasycznej void strcpy( char d[], char s[] )) int i = 0; while( s[ i ]!= '\0' ) d[ i ] = s[ i ]; i++; d[ i ] = '\0'; char s1[ 80 ] = "C/C++"; char s2[ 20 ]; strcpy( s2, s1 ); s s1 0 1 2 3 4 5 78 79 C / C + + \0 s2 d C / C + + \0 0 1 2 3 4 5 20 31

Wskaźniki pod lupą metamorfoza funkcji strcpy,, wersja naiwna void strcpy( char * d, char * s ) while( *s!= '\0' ) *d = *s; d++; s++; *d = '\0'; char s1[ 80 ] = "C/C++"; char s2[ 20 ]; strcpy( s2, s1 ); s s1 s2 d C / C + + \0 C 32

Wskaźniki pod lupą metamorfoza funkcji strcpy,, wersja naiwna void strcpy( char * d, char * s ) while( *s!= '\0' ) *d = *s; d++; s++; *d = '\0'; char s1[ 80 ] = "C/C++"; char s2[ 20 ]; strcpy( s2, s1 ); s s1 s2 s++ C / C + + \0 C d d++ 33

Wskaźniki pod lupą metamorfoza funkcji strcpy,, wersja naiwna void strcpy( char * d, char * s ) while( *s!= '\0' ) *d = *s; d++; s++; *d = '\0'; char s1[ 80 ] = "C/C++"; char s2[ 20 ]; strcpy( s2, s1 ); s s1 s2 s++ C / C + + \0 C / d d++ 34

Wskaźniki pod lupą metamorfoza funkcji strcpy,, wersja naiwna I tak dalej, aż do przepisania ostatniego znaku... 35

Wskaźniki pod lupą metamorfoza funkcji strcpy,, wersja naiwna void strcpy( char * d, char * s ) while( *s!= '\0' ) *d = *s; d++; s++; *d = '\0'; char s1[ 80 ] = "C/C++"; char s2[ 20 ]; strcpy( s2, s1 ); s s1 s2 d C / C + + \0 C / C + + \0 36

Wskaźniki pod lupą metamorfoza funkcji strcpy,, wersja naiwna void strcpy( char * d, char * s ) while( *s!= '\0' ) *d = *s; d++; s++; *d = '\0'; char s1[ 80 ] = "C/C++"; char s2[ 20 ]; strcpy( s2, s1 ); s Dlaczego wersja naiwna? Wprowadzono odwołania wskaźnikowe, ale to właściwie niewiele zmienia, poza wyeliminowaniem zmiennej i. s1 s2 d C / C + + \0 C / C + + \0 37

Wskaźniki pod lupą metamorfoza funkcji strcpy void strcpy( char * d, char * s ) while( *s!= '\0' ) *d++ = *s++; *d = '\0'; *d = *s; d++; s++; Kompresja krok pierwszy void strcpy( char * d, char * s ) while( ( *d++ = *s++ )!= '\0' ) ; Kompresja krok drugi Wartością tego wyrażenia jest znak (bajt) przepisany z obszaru wskazywanego przez s do obszaru wskazywanego przez d. Operator = jest lewostronnie łączny ( *d++ = *s++ )!= '\0' Pobierz znak wskazywany, wykorzystaj go, zwiększ wskaźnik tak, by pokazywał na następny element tablicy. 38

Wskaźniki pod lupą metamorfoza funkcji strcpy void strcpy( char * d, char * s ) while( *d++ = *s++ ) ; ( *d++ = *s++ )!= '\0' Kompresja krok trzeci Znak '\0' to bajt o wartości 0 Często spotykaną praktyką w funkcjach bibliotecznych jest udostępnianie wskaźnika do tablicy (jednej z tablic) będącej parametrem: char * strcpy( char * d, char * s ) while( *d++ = *s++ ) ; return d; Tablica d jako rezultat funkcji Uwaga, opuszczenie!= '\0' może powodować powstanie ostrzeżenia ze strony kompilatora może on podejrzewać, że pomyliliśmy operatory = i ==. 39

Wskaźniki pod lupą dlaczego strcpy udostępnia d jako rezultat? Pozwala to na skrócenie kodu, załóżmy następujące definicje tablic s1, s2, s3: char s1[ 80 ] = "C i C++"; char s2[ 80 ]; char s3[ 80 ]; Następujący fragment kodu: strcpy( s2, s1 ); strcpy( s3, s2 ); cout << s3; Można zapisać krócej: cout << strcpy( s3, strcpy( s2, s1 ) ); Rezulat funkcji operujących na napisach bardzo często wydaje się mało użyteczny, jednak jego wykorzystanie pozwala na stosowanie sztuczek i trików. 40

Wskaźniki pod lupą użycie modyfikatora const, przypomnienie W dotychczasowych realizacjach funkcji strcpy, funkcja może modyfikować zawartość tablicy źródłowej: char * strcpy( char * d, char * s ) *s = 'A'; Modyfikacja tablicy źródłowej dozwolona, choć merytorycznie niepoprawna Aby temu zaradzić, można zadeklarować parametr reprezentujący tablicę źródłową w specyficzny sposób: char * strcpy( char * d, const char * s ) *s = 'A'; Tablica źródłowa jest chroniona 41

Wyznaczanie długości napisu funkcja strlen klasycznie Realizacja w wykorzystaniem iteracji while: int strlen( char s[] ) int len = 0; Wyznaczenie długości napisu polega na odnalezieniu znacznika końca napisu, jego indeks określa, ile jest przed nim znaków. while( s[ len ]!= '\0' ) len++; return len ; Realizacja w wykorzystaniem iteracji for: int strlen( char s[] ) int len; for( len = 0; s[ len ]!= '\0'; len++ ) ; return len ; 42

Wyznaczanie długości napisu funkcja strlen wskaźnikowo Realizacja w wykorzystaniem iteracji while: int strlen( char * s ) char * ptr = s; while( *ptr!= '\0' ) ptr++; Wyznaczenie długości napisu polega na wyznaczeniu róznicy pomiędzy adresem znacznika końca a adresem pierwszego elementu tablicy. return ( int )( ptr s ) ; Realizacja w wykorzystaniem iteracji for: int strlen( char * s ) char * ptr; for( ptr = s; *ptr!= '\0'; ptr++ ) ; return ( int )( ptr s ) ; 43

Odwracanie kolejności znaków w napisie strrev klasycznie char * strrev( char s[] ) int begin, end; // Szukanie konca napisu for( end = 0; s[ end ]!= '\0'; end++ ) ; // Zamiana znakow miejscami for( begin = 0, end--; begin < end; begin++, end-- ) char c = s[ begin ]; s[ begin ] = s[ end ]; s[ end ] = c; return s; Jak to działa? To już było przy omawianiu tablic znaków. 44

Odwracanie kolejności znaków w napisie strrev wskaźnikowo char * strrev( char * s ) char * begin, * end; // Szukanie znacznika konca for( end = s; *end ; end++ ) ; // Zamiana znakow miejscami for( begin = s, end--; begin < end; begin++, end-- ) char c = *begin; *begin = *end; *end = c; return s; Jak to działa? Analiza na zadanie domowe..., ta funkcja to fajne zadanie na egzamin :) 45

Dynamiczna alokacja tablic konwencja języka C Na tablicach alokowanych dynamicznie na stercie, można wykonywać takie same operacje, jak na tablicach statycznych. Należy tylko uważnie przydzielać i zwalniać pamięć. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamiętanie w zmiennej n s = new char [ n ]; // A właściwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; Zobaczmy, jak wyglądają kolejne etapy definiowania i wykorzystania takiej tablicy... 46

Dynamiczna alokacja tablic etap 1-szy Definicja wskaźnika typ obiektu wskazywanego taki, jak typ elementów tablicy jakich potrzebujemy. Zerowanie wskaźnika to dobra praktyka. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s Pamięć operacyjna Sterta 47

Dynamiczna alokacja tablic etap 2-gi Zwykle korzystamy ze zmiennej, która pozwoli zapamiętać ilu elementowej tablicy potrzebujemy. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s Pamięć operacyjna Sterta 48

Dynamiczna alokacja tablic etap 3-ci Przed utworzeniem tablicy musimy ustalić konkretną liczbę elementów tablicy. Jak ustalimy tę liczbę zależy od konkretnego zastosowania. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s Pamięć operacyjna Sterta 49

Dynamiczna alokacja tablic etap 4-ty Przydział pamięci dla tablicy operator new otrzymuje typ elementów tablicy oraz ich liczbę, w tym przypadku n. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s Pamięć operacyjna Sterta???...? Pamięć operacyjna 50

Dynamiczna alokacja tablic etap 5-ty Kontrola poprawności przydziału pamięci (dla operatora w wersji nie generującej wyjątków). Przydzielony obszar pamięci ma przypadkową zawartość. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s Pamięć operacyjna Sterta???...? Pamięć operacyjna 51

Dynamiczna alokacja tablic etap 6-ty Tak utworzona tablicę można używać tak samo, jak każdą inną tablicę w języku C/C++ Wszystkie funkcje do manipulowania np. napisami, działają bez problemu. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s Pamięć operacyjna Sterta Język C++ fajny Pamięć jest! operacyjna 52

Dynamiczna alokacja tablic etap 7-ty Gdy tablica nie jest już potrzebna, zwalniamy przydzieloną pamięć i oddajemy do puli wolnych bloków. Uwaga, wskaźnik pokazuje dalej na zwolniony obszar pamięci! char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; Ta wersja operatora delete [] odpowiedzialna jest za bezpieczne usunięcie całej tablicy elementów. s Pamięć operacyjna Sterta Język C fajny Pamięć jest! operacyjna 53

Dynamiczna alokacja tablic zerowanie wskaźnika Zerowanie wskaźnika po zwolnieniu pamięci jest dobrą praktyką. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamię tanie w zmiennej n s = new char [ n ]; // A właś ciwie: new (nothrow) char [ n ] if( s!= 0 ) strcpy( s, "Język C++ " ); strcat( s, "fajny jest!" ); cout << s; delete [] s; s = 0; s Pamięć operacyjna Sterta 54

Dynamiczna alokacja tablic new generujący wyjątki Wersja zakładająca, że operator new generuje wyjątek w przypadku braku wolnej pamięci: char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamiętanie w zmiennej n try s = new char [ n ]; strcpy( s, "Język C " ); strcat( s, "fajny jest!" ); puts( s ); delete [] s; catch(... ) // Wersja uproszczona, dokładniej catch( std::bad_alloc & e ) cout << "Brak pamięci dla wykonania tej operacji"; 55

Dynamiczna alokacja tablic zerowanie wskaźnika Zerowanie wskaźnika po zwolnieniu pamięci jest zawsze dobrą praktyką. char * s = 0; int n; // Tu ustalenie liczby potrzebnych elementów i zapamiętanie w zmiennej n try s = new char [ n ]; strcpy( s, "Język C " ); strcat( s, "fajny jest!" ); puts( s ); delete [] s; s = 0; catch(... ) // Wersja uproszczona, dokładniej catch( std::bad_alloc & e ) cout << "Brak pamięci dla wykonania tej operacji"; 56

Dynamiczna alokacja tablic konwencja języka C W języku C dynamiczny przydział pamięci nie jest częścią języka. Przydział ten realizują funkcje biblioteczne malloc, calloc, realloc, free. char * s = NULL; int n; /* Tu ustalenie liczby potrzebnych elementów i zapamiętanie w zmiennej n */ s = malloc( n * sizeof( char ) ); if( s!= NULL ) strcpy( s, "Język C " ); strcat( s, "fajny jest!" ); puts( s ); free( s ); Nie należy mieszać operatorów new i delete z funkcjami malloc, calloc, realloc i free. Należy trzymać się jednej konwencji zarządania pamięcią. 57

Ważna sprawa ostrożnie z parametrami wskaźnikowymi! W funkcjach bibliotecznych języka C i C++ stałą praktyką jest deklarowanie parametrów tablicowych z wykorzystaniem wskaźników, np: int strlen( char * s ); zamiast int strlen( char s[] ); Wymaga to dokładnego przeczytania dokumentacji, bowiem programiści często się mylą. Rozważmy następujący przykład (fragment systemu pomocy firmy Borland): Prototype Prototype char *gets(char *s); char *gets(char *s); Description Description Gets a string from stdin. Gets a string from stdin. gets collects a string of characters terminated by a new line from the standard input stream stdin and gets collects a string of characters terminated by a new line from the standard input stream stdin and puts it into s. The new line is replaced by a null character (\0) in s. puts it into s. The new line is replaced by a null character (\0) in s. gets allows input strings to contain certain whitespace characters (spaces, tabs). gets returns when it gets allows input strings to contain certain whitespace characters (spaces, tabs). gets returns when it encounters a new line; everything up to the new line is copied into s. encounters a new line; everything up to the new line is copied into s. 58

Ważna sprawa ostrożnie z parametrami wskaźnikowymi! Niedokładna lektura dokumentacji może sugerować, że funkcji należy użyć tak: char * imie; printf( "Podaj imie: " ); gets( imie ); Pamięć operacyjna imie??? Ewa Pamięć operacyjna gets( imie ) Gdyby wskaźnik był wyzerowany, kompilator czasem pomoże: char * imie = NULL; imie Pamięć operacyjna printf( "Podaj imie: " ); gets( imie ); gets( imie ) Pamięć operacyjna Stare kompilatory firmy Borland: Null pointer assignment Niektóre implementacje funkcji gets przerywają działanie gdy parametr jest wskaźnikiem pustym. 59

Ważna sprawa ostrożnie z parametrami wskaźnikowymi! A trzeba np. tak: char imie[ 80 ]; printf( "Podaj imie: " ); gets( imie ); Pamięć operacyjna imie Ewa Pamięć operacyjna gets( imie ) Lub tak: char * imie = 0; imie = new (nothrow) char[ 80 ]; if( imie!= 0 ) printf( "Podaj imie: " ); gets( imie ); delete [] imie; Pamięć operacyjna imie Ewa Pamięć operacyjna gets( imie ) 60

Można tworzyć dynamicznie tablice dowolnych typów Tablica elementów typu double, liczba elementów określona przez użytkownika. double * dochody = 0; int liczbamiesiecy; do cout << endl << "Podaj liczb ę miesiecy okresu rozrachunkowego: "; cin >> liczbamiesiecy; if( liczbamiesiecy <= 0 liczbamiesiecy > 12 ) cout << "Okres rozrachunkowy to od 1 do 12 miesię cy" ; while( liczbamiesiecy <= 0 liczbamiesiecy > 12 ) dochody = new (nothrow) double [ liczbamiesiecy ]; if( dochody!= 0 ) for( int miesiac = 0; miesiac < liczbamiesiecy; miesiac++ ) dochody[ miesiac ] = 0; // Tutaj operacje na tablicy dochody delete [] dochody; 61

Można tworzyć dynamicznie tablice dowolnych typów Załóżmy, że mamy wykonać operację na bitmapie w 256 kolorach. typedef unsigned char byte; byte * bitmapa = 0; int liczbapikseli; // Tu ustalenie liczby pikseli rysunku bitmapowego bitmapa = new (nothrow) byte [ liczbapikseli ]; if( bitmapa!= 0 ) // Załaduj bitmapę for( int nrpiksela = 0; nrpiksela < liczbapikseli; ++nrpiksela ) // Jaka ś operacja na pikselu bitmapy: bitmapa[ nrpiksela ] // Gdy bitmapa ju ż niepotrzebna delete [] bitmapa; 62

Czy to są dynamiczne tablice? W C i C++ na razie nie ma tablic dynamicznych. W standardzie C99 występują tablice o zmiennej długości rozmiar tablicy może być ustalany na etapie wykonania programu, jednak po ustaleniu liczby elementów tablicy, nie może być już ona zmieniana. Przedstawiony wcześniej mechanizm dynamicznego tworzenia tablic zastępuje mechanizm tablic dynamicznych i w zupełności wystarcza w C. Wystarcza również w C++, jednak istnieje tendencja do wykorzystywania klas pojemnikowych oferowanych np. przez bibliotekę STL. Klasy te pozwalają na wygodne, skuteczne i elestyczne manipulowanie kolekcjami obiektów. Są też bezpieczniejsze. Jest to jednak okupione sporym narzutem kodu biblioteki pojemnikowe są dość złożone. 63