podstawy programowania (język ANSI C) (język C++)
ogólna charakterystyka języka C: 1972 - Bell Laboratories, Dennis M. Ritchie, Unix 1988 - ANSI, ANSI C strukturalność blokowość rekurencyjność niezależność od architektury maszyny zwięzłość kodu brak procedur preprocesor dynamiczna alokacja pamięci możliwość umieszczenia kodu w wielu plikach
typy danych: typy całkowite: char (zakres od 128 do 127) unsigned char (zakres od 0 do 255) int (zakres od 2147483648 do 2147483647) short int long int long long int (zakres od 9.2 10 18 do 9.2 10 18 ) unsigned int unsigned short int (zakres od 0 do 65535) unsigned long int unsigned long long int (zakres od 0 do 9.2 10 19 ) typy rzeczywiste zmiennoprzecinkowe: (zapis w postaci m p c ) float (zakres od 3.4 10 38 do 3.4 10 38 ) double (zakres od 1.8 10 308 do 1.8 10 308 ) long double (zakres od 1.2 10 4932 do 1.2 10 4932 )
nazwy zmiennych: tworzone są z liter i cyfr oraz znaku podkreślenia pierwszym znakiem musi być litera rozróżniane są duże i małe litery co najmniej 31 pierwszych znaków nazwy zmiennej ma znaczenie słowa kluczowe (np: int, double itd.) są zarezerwowane typy tablicowe: przykłady: int big_table[200]; long int Big_table[200]; long int Big_Table[2000]; indeks od 0 do n-1, gdzie n jest wielkością tablicy
operatory arytmetyczne: dwuargumentowe operatory: + - * / dzielenie modulo: % jednoargumentowe operatory: + - operatory logiczne: operatory relacji: > >= < <= operatory przyrównania: ==!= (równy, nierówny) operatory iloczynu i sumy: && operator negacji:! operatory bitowe: operatory przesunięcia: << >> (w lewo, w prawo) operator dopełnienia jedynkowego: ~ (negacja) inne operatory bitowe: & ^ (AND, OR, XOR)
operatory inkrementacji i dekrementacji: operator zwiększania: ++ (np: i++) operator zmniejszania: -- (np: --i) operator wyrażenie i przypisanie: zasada: a=aopb jest równoważne aop=b operatory arytmetyczne: += -= *= /= %= operatory bitowe: <<= >>= &= = ^=
inne operatory: operator wywołania funkcji: () operatory dostępu do elementów struktur: ->. operator indeksowania: [] operator rzutowania typu: (typ ) operator wyznaczania rozmiaru w bajtach: sizeof operator warunkowy:?: operator przecinkowy:, operator zwracania adresu zmiennej: & operator zwracania zmiennej spod adresu: * operator przypisania: =
instrukcje sterujące: if else if(wyrażenie1) instrukcja1 else instrukcja2 if(n>0) if(a>b) z=a; else z=b;
instrukcje sterujące: konstrukcja else if if(wyrażenie1) instrukcja1 else if(wyrażenie2) instrukcja2 else if(wyrażenie3) instrukcja3 else instrukcja4
instrukcje sterujące: switch switch(zmienna){ case stała1: instrukcja1 return; case stała2: instrukcja2 break; } default: instrukcja3
pętle: for for(wyrażenie1; wyrażenie2; wyrażenie3){ }... break;... continue; int sum, i; for(i=1, sum=0; i<10; i++){ } sum+=i;
pętle: while while(wyrażenie){ }... break;... continue; int sum, i; i=1; sum=0; while(i<10){ } sum+=i++;
pętle: do while do{... break;... continue; } while(wyrażenie); int sum, i; i=1; sum=0; do{ sum+=i++; } while(i<10);
instrukcje sterujące: goto i etykiety... if(a==0) goto etykieta1; else return (double)1/a;... etykieta1: dzielenieprzezzero();...
funkcje: definicja funkcji typ_powrotu nazwa_funkcji(parametry){ deklaracje instrukcje... return zmienna1_typ_powrotu;... } return zmienna2_typ_powrotu;
funkcje: wywołanie funkcji: typ_powrotu zmienna1; double zmienna1=2.3; char zmienna2= q ; zmienna1=nazwa_funcji(zmienna1, zmienna2); cechy funkcji: parametry są przekazywane przez wartość pominięcie typu powrotu powoduje, że funkcja zwraca wartość typu int jeśli funkcja nie ma zwracać żadnej wartości, stosuje się typ void
preprocesor języka C: wstawianie plików: #include "nazwa pliku" #include <nazwa pliku> makrorowinięcia: #define nazwa zastępowany tekst #define mean(a,b,c) ((a)+(b)+(c))/3 #define min(a,b) (a)<(b)?(a):(b) #undef min(a,b) argumenty makr w stałych napisowych: #define makro(argm) fun(#argm"koniec") makro(początek) fun("początek""koniec"); fun("początekkoniec");
preprocesor języka C: operarator ##: sklejanie argumentów aktualnych podczas rozwijania makra przykłady: #define paste(a, b) a ## b f(paste("sklej", "one")); f("sklejone"); #define paste(a, b) #a ## #b f(paste(sklej, one)); f("sklejone");
preprocesor języka C: kompilacja warunkowa: sterowanie procesem tłumaczenia wlączanie odpowiednich fragmentów kodu podczas kompilacji w zależności od architektury, platformy i innych czynników przykład: #if defined(arg) / #if! defined(arg) #define ARG #endif #ifdef ARG / #ifndef ARG #define ARG #endif
preprocesor języka C: kompilacja warunkowa część dalsza: przykład: #if ARG==WART1... #elif ARG==WART2... #elif ARG==WART3... #else #endif...
rodzaje zmiennych: zmienne zewnętrzne: definiowane poza wszystkimi funkcjami dostępne dla wielu funkcji alternatywa dla argumentów funkcji i zwracanych przez funkcje wartości przykład: typ1 zmienna1; void funkcja1(typ1 arg1, typ2 arg2){... zmienna1=arg1; } void funkcja2(typ2 arg1, typ1 arg2){... zmienna1=arg2; }
rodzaje zmiennych: zmienne automatyczne: definiowane w momencie wywołania bloku programu (funkcji, pętli itp.) tuż po nawiasie { otwierającym ten blok dostępne tylko dla tego bloku programu, w którym zostały zdefiniowane przykład: void funkcja1(typ1 arg1, typ2 arg2){ } int zmienna1=arg1;... void funkcja2(typ2 arg1, typ1 arg2){ } int zmienna1=arg2;...
rodzaje zmiennych: zmienne rejestrowe, deklaracja register: zastosowanie dla intensywnie używanych zmiennych zmienna jest umieszczana w rejestrach maszyny przyspieszenie i zmniejszenie programu stosowana wyłącznie do zmiennych automatycznych i do parametrów funkcji przykłady: register int zmienna1; int zmienna2; f(register unsigned int a){ } register int c;
wskaźniki i adresy: deklaracja obiektów wskaźnikowych: int *wskaźnik1 int *wskaźnik2, zmienna1 odwołania do obiektów wskaźnikowych: int zmienna2=*wskaźnik1 int *wskaźnik3=&zmienna1 typ wskaźnika ogólnego void*: void *wskv; int *wski; char *wskc; wski=wskv; //dobrze wskv=wskc; //dobrze wski=wskc; //źle
wskaźniki i argumenty funkcji: deklaracje: void zamień1(int, int) //źle void zamień2(int*, int*) //dobrze przykład: void zamień(int *a, int *b){ } int tmp; tmp=*a; *a=*b; *b=tmp;
wskaźniki i tablice: zmienne tablicowe: int table1[10]; int table2[300]; dynamiczny przydział pamięci: int *table1, *table2; table1=(int*)malloc(sizeof *table1 *10); table2=(int*)calloc(300, sizeof *table2); free(table1); równoważności: *table1 table1[0] *(table1+i) table1[i] table1 &table1[0] table1+i &table1[i]
wskaźniki i tablice: indeksowanie: int *table1, *reftable1; table1=(int*)malloc(sizeof *table1 *10); int i; for(i=0; i< 10; i++) *(table1+i)=i; reftable1=table1+5; for(i=-5; i< 5; i++) *(reftable1+i)=i+5;
arytmetyka na adresach: jeżeli ptr jest wskaźnikiem do pewnego obszaru danych, to: ptr++ - wskaźnik na następny element ptr+=i - wskaźnik na element oddalony o i elementów od początku danych relacje dla wskaźników: dla wskaźników odwołujących się do elementów tej samej tablicy: <=, >, ==,!= itd. - liczba elementów pomiędzy tymi wskaźnikami brak operacji dodawania dla dowolnych wskaźników: przyrównanie do NULL
napisy i znaki: przykład: void funkcja1(char* a, char b){ }... funkcja1("napis", a ); właściwości: każdy napis zakonczony jest znakiem \0 do funkcji funkcja1 przekazywany jest tylko wskaźnik do napisu, a nie cały napis (pierwszy argument) język C dostarcza tylko operacji dla wskaźników, brak jest zdefiniowanych operacji dla ciągów znaków
napisy i znaki: przykład: char napis1[]="text"; char *napis2="text"; komentarz: napis1 - tablica (zawiera cały napis oraz znak końca napisu ( \0 )) napis2 - wskaźnik (przetrzymuje adres napisu "text", który nie musi być naszą własnością) wyrażenia idiomatyczne: *wskaźnik++=zmienna zmienna=*--wskaźnik
tablice wielowymiarowe: przykład: int table2d[2][5]={ {3, 5, 7, 13, 17}, {3, 1, 4, 1, 6}} fun1(int table2d[2][5]){... } fun1(int table2d[][5]){... } fun1(int (*table2d)[5]){... } komentarz: do funkcji przekazywany jest wskaźnik, nie ma obowiązku podawania rozmiaru tablic w argumentach funkcji w argumencie funkcji tablicę elementów danego typu możemy zamienić wskaźnikiem do tych elementów
tablice wielowymiarowe: przykład: int **tab1; int i,j; int tab2[10][20] table=(int**)malloc(10*sizeof *tab1) for(i=0; i<10; i++) *(tab1+i)=(int*)calloc(20, sizeof **tab1); for(i=0; i<10; i++) for(j=0; j<20; j++){ *(*(tab1+i)+j)=i*j; tab2[i][j]=i-j; }
wskaźnik do funkcji: funkcja zwracająca wskaźnik do int: int* funkcja(void){... } wskaźnik funkcji zwracającej typ int: int (*funkcja)(void){... } wskaźnik funkcji zwracającej wskaźnik do int: int* (*funkcja)(void){ }...
argumenty wywołania programu: funkcja main void main(int argc, char** argv){ }... opis parametrów funkcji main: argv[0] - nazwa pliku programu argc==1 - brak argumentów char *argv[] - tablica wskaźników do char int (*argv)[] - wskaźnik do tablic typu char
rzutowanie wskaźników: przykład: void funkcja(char* table1){ int *table2, i, j; table2=malloc(4*10); for(i=0; i<10; i++) for(j=0; j<4; j++) *((char*)table2+i*4+j)= *(table1+i*4+j); for(i=0; i<10; i++) *(table2+i)= *((int*)table1+i);
nietypowy dynamiczny przydział pamięci: przykład: void funkcja2(int* a){... } int* funkcja1(void){ int *table1, i; table1=malloc(4*10); for(i=0; i<10; i++) *(table1+i)=i; return table1; } void main(void){ int* tmp=funkcja1(); funkcja2(tmp); free(tmp); }
struktury: definicja typu strukturalnego: struct pracownik{ char* nazwisko; unsigned char wiek; unsigned short int zarobki; }; deklaracja zmiennej strukturalnej: struct pracownik szef; struct pracownik kierowca, dozorca; deklaracja zmiennej strukturalnej (sposób 2): struct { char *nazwisko; unsigned char wiek; unsigned short int zarobki; } szef, kierowca, dozorca;
struktury: dostęp do pól struktury (zapis): szef.zarobki=2000; szef.wiek=50; szef.nazwisko="kowalski"; dostęp do pól struktury (odczyt): unsigned char wiek; char *nazwisko; wiek=szef.wiek; nazwisko=szef.nazwisko; dostęp do pól struktury (odczyt/zapis): kierowca.zarobki= (int)((double)szef.zarobki/2);
struktury: zagnieżdżanie: struct nazwa{ char *imię; char *nazwisko;}; struct pracownik{ struct nazwa id; unsigned char wiek; unsigned short int zarobki;}; dostęp do pól struktury zagnieżdżonej: struct pracownik szef; szef.id.imię="jan"; szef.id.nazwisko="kowalski"; szef.wiek=50; szef.zarobki=2000;
struktury i funkcje: definicja funkcji zwracającej strukturę: struct pracownik nowy(char *imię, char *nazwisko, unsigned char wiek, short int zarobki){ } struct pracownik tmp; tmp.id.imię=imię; tmp.id.nazwisko=nazwisko; tmp.wiek=wiek; tmp.zarobki=zarobki; return tmp; użycie funkcji przy przypisaniu pól strukturze: struct pracownik sprzedawca; sprzedawca=nowy("maria","nowak", 22, 1000);
operacje na strukturach: pobranie adresu struktury wyłuskanie struktury spod adresu kopiowanie struktur dostęp do składowych -> i. przykład: struct pracownik kierowca, *wsk1; struct pracownik *wsk2, tokarz; unsigned char wiek; unsigned short int zarobki; wsk1=&kierowca; wiek=(*wsk1).wiek; zarobki=wsk1->zarobki; *wsk2=*wsk1; tokarz=*wsk1;
tablice struktur: przykład: struct pracownik pracownicy[10]; int i; unsigned short int zarobki[]= {2000, 1500, 1200, 1100, 900, 900, 900, 900, 800, 800}; for(i=0; i<10; i++) pracownicy[i].zarobki= zarobki[i]; pracownicy[3]=pracownicy[4];
struktury i dynamiczny przydział pamięci: przykład: struct pracownik *pracownicy; int i; unsigned short int zarobki[]= {2000, 1500, 1200, 1100, 900, 900, 900, 900, 800, 800}; pracownicy=(struct pracownik*)malloc( sizeof *pracownicy*10); for(i=0; i<10; i++) (pracownicy+i)->zarobki= zarobki[i]; pracownicy[3]=*(pracownicy+4);
deklaracja typedef: tworzenie nowych nazw typów danych nie tworzy nowego typu, nadaje tylko istniejącemu typowi nową nazwę dobrym zwyczajem jest nazywać nowe nazwy typów z wielkiej litery przykład: typedef unsigned int Słowo; Słowo bity32; struct struktura{... }; typedef struct struktura nazwa; nazwa zmienna; typedef struct struktura1{... } nazwa1; nazwa1 zmienna1;
unie: zmienna, która może zawierać obiekty różnych typów i rozmiarów przykład: union nazwa{ int Int; double Double; char Char; } zmienna, *wskaźnik; double Double=2.3; int Int=12345; zmienna.double=double; wskaźnik->int=int;
pola bitowe: deklaracja i definicja podobna jak w przypadku struktur pakowanie kilku obiektów (zmiennych) w jedno słowo maszyny oszczędność pamięci przykład: struct polebitowe{ short unsigned int power: 1; short unsigned int volume: 12; short unsigned int cd: 1; short unsigned int radio: 1;}; polebitowe zmienna; zmienna.volume=2000; zmienna.power=1; zmienna.radio=1; zmienna.cd=0;
funkcja printf: int printf(char* format, arg1, arg2,..) wypisuje argumenty arg1, arg2, zgodnie z formatem format na standardowe (ekran) opis formatu format: zwykłe znaki - kopiowane są bezpośrednio specyfikacje przekształcenia - % + modyfikator + znak przekształcenia modyfikatory (postać wyniku): - - dosunięcie przekształconego argumentu do lewego krańca jego pola + - wypisanie liczby zawsze ze znakiem odstęp - poprzedzenie wyniku znakami odstępu 0 - poprzedzenie wyniku zerami
funkcja printf: opis formatu format: modyfikatory: liczba określająca minimalny rozmiar pola kropka oddzielająca rozmiar pola od precyzji liczba określająca precyzję modyfikator długości: h - short lub unsigned short l - long lub unsigned long L - long double
funkcja printf: opis formatu format: znak przekształcenia znak przekształcenia: d, i - liczba dziesiętna ze znakiem o - liczba ósemkowa bez znaku x, X - liczba szesnastkowa bez znaku u - liczba dziesiętna bez znaku c - znak s - wskaźnik do tablicy znaków zakończonych znakiem \0 f - liczba dziesiętna zmiennoprzecinkowa m.d e, E - liczba dziesiętna zmiennoprzecinkowa m.de ±x, m.de ±x g, G - automatyczny wybór znaku przekształcenia znak przekształcenia: f, e lub E p - wskaźnik % - znak %
funkcja printf: przykłady: printf("%d", 20); 20 printf("%d", 3000000000); -1294967296 printf("%u", 3000000000); 3000000000 printf("%5d", 20); 20 printf("% 5d", 20); 20 printf("%07d", 20); 0000020 printf("%-7d", 20); 20
funkcja printf: przykłady: printf("%+d", 20); +20 printf("%+d", -20); -20 printf("%4d", 2000000000); 2000000000 printf("% 8.5f", 2.3); 2.30000 printf("%015.5e", 2.3); 00002.30000e+00 printf("%05.5e", 2.3); 2.30000E+00 printf("%+015.5e", 2.3); +0002.30000E+00
funkcja scanf: int scanf(char* format, arg1, arg2,..) czyta ze standardowego wejścia zgodnie z formatem format i zapamiętuje wyniki w argumentach arg1, arg2 itd. opis formatu format: odstępy i znaki tabulacji są ignorowane zwykłe znaki, których spodziewamy się na wejściu specyfikacje przekształcenia - % + N/h/l/L + znak przekształcenia: N - maksymalny rozmiar pola h, l, L - tak jak poprzednio
funkcja scanf: opis formatu format: znak przekształcenia znak przekształcenia: d - liczba całkowita dziesiętna i - liczba dziesiętna, może wystąpić w postaci szesnastkowej (np. 0xff) lub ósemkowej (np. 077) o - liczba całkowita w postaci ósemkowej x - liczba całkowita w postaci szesnastkowej u - liczba dziesiętna bez znaku c - znak s - ciąg znaków bez cudzysłowów f, e, g - liczba dziesiętna zmiennoprzecinkowa p - wskaźnik % - znak %
funkcja scanf: przykłady: scanf("%d", &a); +20 a=20 scanf("u%d", &a); u-20 a=-20 scanf("%g", &a); 25e10 a=2.5e11 scanf("%i", &a); 017 a=15 scanf("%i", &a); 17 a=17 scanf("%i", &a); 0xff a=255
pliki: dostęp do otwartego pliku poprzez zmienną typu wskaźnik do pliku FILE* otwarcie pliku o nazwie nazwa w trybie tryb: FILE* fopen(char* nazwa, char* tryb) podstawowe tryby otwarcia pliku: r - czytanie w - pisanie a - dopisywanie b - pliki binarne w systemie otwarte są trzy pliki: stdin - klawiatura stdout - ekran stderr - błędów zamykanie pliku: fclose(file* wsk)
pliki: pobranie znaku z pliku: int getc(file *wsk) zapisanie znaku do pliku: int putc(int znak, FILE *wsk) analogia funkcji int printf(char* format,..): int fprintf(file *wsk, char* format,..) analogia funkcji int scanf(char* format,..): int fscanf(file *wsk, char* format,..) makrorozwinięcia: #define getchar() getc(stdin) #define putchar(c) putc((c), stdout) znacznik końca pliku: EOF
pliki: odczyt z pliku skojarzonego ze wskaźnikiem do pliku wskf num obiektów o wielkości size każdy i umieszczenie odczytanych danych pod wskaźnikiem wsk: size t fread(void *wsk, size t size, size t num, FILE* wskf) zapis do pliku skojarzonego ze wskaźnikiem do pliku wskf num obiektów o wielkości size każdy spod adresu umiesczonego we wskaźniku wsk: size t fwrite(const void *wsk, size t size, size t num, FILE* wskf) size t - typ wartości całkowitej bez znaku, np: typedef unsigned int size t
pliki: pozycjonowanie pliku: fseek(file *wsk, long offset, int origin) offset - przesunięcie względem odniesienia origin - odniesienie: SEEK SET - początek pliku SEEK CUR - bieżąca pozycja SEEK END - koniec pliku pobieranie pozycji pliku: long ftell(file *wsk) ustawienie pozycji pliku na początek: void frewind(file *wsk)
operacje na łańcuchach string.h: oznaczenia: char *s, *t; const char *cs, *ct; size t n; char c; char* strstr(cs, ct) zwraca wskaźnik do pierwszego wystąpienia tekstu ct w tekście cs lub NULL jeśli ct nie występuje w cs size t strlen(cs) zwraca długość tekstu cs
operacje na łańcuchach string.h: char* strcpy(s, ct) kopiuje znaki spod adresu ct do adresu s łącznie ze znakiem \0 char* strncpy(s, ct, n) kopiuje spod adresu ct do adresu s co najwyżej n znaków łącznie ze znakiem \0, jeśli ct ma mniej niż n znaków, to s dopełniane jest znakami \0 char* strcat(s, ct) dopisuje znaki spod adresu ct na koniec tekstu spod adresu s łącznie ze znakiem \0 char* strncat(s, ct, n) dopisuje co najwyżej n znaków spod adresu ct na koniec tekstu spod adresu s łącznie ze znakiem \0
operacje na łańcuchach string.h: int strcmp(cs, ct) porównuje teksty zawarte w cs i ct, zwraca wartość mniejszą od zera gdy cs<ct, wartość zero, gdy cs==ct, większą od zera, gdy cs>ct int strncmp(cs, ct, n) porównuje co najwyżej n znaków zawartych w cs i ct, zwraca wartość mniejszą od zera gdy cs<ct, wartość zero, gdy cs==ct, większą od zera, gdy cs>ct char* strchr(cs, c) zwraca wskaźnik do pierwszego wystąpienia znaku c w tekście cs char* strrchr(cs, c) zwraca wskaźnik do ostatniego wystąpienia znaku c w tekście cs
sekwencje specjalne języka C: \a - znak alarmu \b - znak cofania \n - znak nowego wiersza \r - znak powrotu karetki \t - znak tabulacji poziomej \v - znak tabulacji pionowej \\ - znak \ \? - znak zapytania \ - znak apostrofu \" - znak cudzysłowu
wykonanie polecenia systemu operacyjnego system(): system(char*) funkcja exit(): exit(arg) return arg - w przypadku wywołania wewnątrz funkcji main exit(arg) - wychodzi z programu w przypadku wywołania w dowolnym miejscu programu, zwraca arg generowanie liczb losowych rand(): int rand(void) - zwraca pseudolosową liczbę z przedziału [0... RAND MAX]
funkcje matematyczne math.h: sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x) - funkcje trygonometryczne sinh(x), cosh(x), tanh(x) - funkcje hiperboliczne log(x), log10(x), exp(x), pow(x,y), sqrt(x) - funkcje logarytmiczne, wykładnicze i potęgowe fabs(x) - wartość bezwzględna modf(x, double *wsk) - rozdziela x na część całkowitą i ułamkową (obie z tym samym znakiem co x), część całkowitą wstawia do *wsk, zwraca część ułamkową fmod(x,y) - zmiennopozycyjna reszta z dzielenia x/y z tym samym znakiem co x x i y argumenty typu double, funkcje zwracają wartości typu double
badanie klasy znaków i ich przekształcenia ctype.h: isalpha(c) - sprawdza czy c jest literą isupper(c) - sprawdza czy c jest wielką literą islower(c) - sprawdza czy c jest mała literą isdigit(c) - sprawdza czy c jest cyfrą isalnum(c) - sprawdza czy c jest cyfrą lub literą isspace(c) - sprawdza czy c jest odstępem, tabulacją, znakiem nowego wiersza, powrotu karetki, nowej strony lub tabulacji pionowej toupper(c) - zwraca c przekształcony na wielką literę tolower(c) - zwraca c przekształcony na mała literę c - argument całkowity typu int reprezentujący unsigned char
funkcja qsort: porządkuje elementy dowolnego typu, dla których zdefiniowaliśmy funkcję porównującą qsort(void* wskaźnik do elementów, size t liczba elementów, size t wielkość elementu, int (*funkcja porównująca)( const void*, const void*)) właściwości funkcji porównującej: wyznacza kryterium sortowania zwraca zero, gdy oba argumenty są równe, zwraca wartość ujemną, gdy argument drugi następuje po argumencie pierwszym według kolejności sortowania zwraca wartość dodatnią, w przeciwnym wypadku
funkcja qsort, przykład: int a[20]; int i; for(i=0; i<20; i++) a[i]=rand(); int (*cmp)(const void* a, const void* b){ } return *(int*)a-*(int*)b; qsort(a, 20, sizeof *a, cmp);
udoskonalone C C++
dynamiczny przydział pamięci new: short int *data, *data1; struct pracownik *kadra, *kadra1; data1=malloc(sizeof *data1*1000); data=new short int[1000]; kadra=new struct pracownik; kadra1=new struct pracownik[20]; zwalnianie pamięci delete: free(data1); delete kadra; delete[] kadra1; delete[] data;
przeciążanie funkcji: wybór funkcji ze wględu na argumenty wywołania brak możliwości zdefiniowana dwóch funkcji o takiej samej nazwie i rozróżnianiu ich pod względem zwracanego typu void pokaż(void){ } printf("%s", "tu funkcja pokaż"); void pokaż(char *wsk){ } pokaż(); printf(" napisano %s", wsk); pokaż("123"); pokaż();
możliwość definiowania i deklarowania zmiennych w różnych miejscach programu: int main(void){ } int a=10; for(int i=0; i<10; i++) printf("%d", i+a); double b=2.3; struct pracownik szef; char *nazwisko="kowalski"; szef.id->nazwisko= new char[strlen(nazwisko)+1]; strcpy(szef.id->nazwisko, nazwisko); double e;
referencje: synonim zmiennej alternatywa dla wskaźników przykłady: void zamień(int &a, int &b){ int tmp=a; a=b; b=tmp;} int a; int &b=a; for(int i=0; i< 10; b++, i++) printf("%d", a);
definicja klasy: class nazwa{ private: //składowe dostępne tylko dla //funkcji składowych i przyjaciół public: //składowe dostępne //dla wszystkich funkcji protected: //składowe dostępne dla składowych, //przyjaciól i klas pochodnych };
przykład definicji klasy: class prostokąt{ private: int długość, szerokość; protected: double skala; int prepole(void); public: prostokąt(int, int, double); double pole(void); };
przykład definicji klasy: prostokąt::prostokąt(int a, int b, double m){ } długość=a; szerokość=b; skala=m; int prostokąt::prepole(){ } return długość*szerokość; double prostokąt::pole(){ } return (double)prepole()*skala*skala;
wykorzystanie klasy prostokąt: prostokąt figura(20, 30,.5); figura.szerokość=20; //źle int prepole; prepole=figura.prepole(); //źle double pole; pole=figura.pole();//dobrze prostokąt *wsk; wsk=new prostokąt(10, 20, 1.0); pole=wsk->pole(); //dobrze
klasy pochodne: klasa pochodna ma dostęp do składowych public: i protected klasy podstawowej, jak też do wszystkich swoich składowych class pochodna: public podstawowa{ private:... public:... protected:... }; //plus składowe publiczne i //chronione klasy podstawowej
przykład definicji klasy pochodnej: class prostopadłościan:public prostokąt{ } private: int wysokość; protected: int preobjętość(void); public: prostopadłościan(int, int, int, double); prostopadłościan(void); double objętość(void);
przykład definicji klasy pochodnej: int preobjętość(void){ return prepole()*wysokość;} double objętość(void){ return pole()*(double)* wysokość*skala;} prostopadłościan::prostopadłościan(void) :prostokąt(1,1,1){wysokość=1;}; prostopadłościan::prostopadłościan (int a, int b, int c, double m) :prostokąt(a, b, m){wysokość=c;}
wykorzystanie klasy pochodnej: prostopadłościan *wsk=new prostopadlościan[20] (1, 2, 3,.3); prostopadłościan tab[20]; for(int i=0; i<10; i++) printf("%f", (wsk+i)->pole()), printf("%f", tab[i].pole()); delete[] wsk;
wykorzystanie klasy pochodnej: prostopadłościan **wsk; wsk=new prostopadłościan*[10]; for(int i=0; i<10; i++) *(wsk+i)=new prostopadłościan(10,10,10,.1); for(int i=0; i<10; i++) printf("%f", (*(wsk+i))->objętość()); for(int i=0; i<10; i++) delete *(wsk+i); delete[] wsk;
przypisanie (błędnie): class klasa{ char* wsk; int rozm; }; public: klasa(int n){wsk=new char[rozm=n];} ~klasa(){delete[] wsk;} void funkcja(void){ } klasa n1(100); klasa n2(100); n1=n2;
przypisanie (poprawnie): class klasa{ char* wsk; int rozm; public: klasa(int n){wsk=new char[rozm=n];} klasa& operator=(const klasa&); ~klasa(){delete[] wsk;}}; klasa& klasa::operator=(const klasa& n){ } if(this!=&n){ delete[] wsk; wsk=new char[rozm=n.rozm]; strcpy(wsk, n.wsk);} return *this;
inicjacja (błędnie): class klasa{ char* wsk; int rozm; }; public: klasa(int n){wsk=new char[rozm=n];} ~klasa(){delete[] wsk;} klasa& operator=(const klasa&); void funkcja(void){ } klasa n1(100); klasa n2=n1;
inicjacja (poprawnie): class klasa{ char* wsk; int rozm; }; public: klasa(int n){wsk=new char[rozm=n];} klasa(const klasa&); ~klasa(){delete[] wsk;} klasa& operator=(const klasa&); klasa::klasa(const klasa& n){ } wsk=new char[rozm=n.rozm]; strcpy(wsk, n.wsk);
funkcje zaprzyjaźnione: class klasa{ int *data; int rozm; }; public: klasa(int, int*); friend klasa& przyjaciel(int, const klasa&); klasa& przyjaciel(const klasa& n){ } //dostęp do składowych klasy
strumienie iostream.h: ostream& ostream::operator<<(char); ostream& ostream::operator<<(int); ostream& ostream::operator<<(short int); ostream& put(char);... przykład: cerr<<"wystąpił błąd"; int Int=10; double Double=10.2; cout<<"\nint = "<<Int<<" Double = "<<Double;
strumienie iostream.h: istream& istream::operator>>(char *); istream& istream::operator>>(char&); istream& istream::operator>>(int&); istream& get(char); istream& get(char*, int, char= \n ); przykład:... double Double; int Int; cin>>double; cin>>int; char *wsk=new char[20]; cin.get(wsk, 19, e );
strumienie dla typów użytkownika iostream.h: class klasa{ int rozm; int *data;... public: friend ostream& operator<<(ostream&, klasa&);}; ostream& operator<<(ostream& cout_, klasa& klasa_){ for(int i=0; i<klasa_.rozm; i++) cout_<<"\n"<<*(klasa_.data+i); return cout_;}
wzorce: template<class T> class wektor{ T* wsk; int rozm; }; public:... wektor(int r){wsk=new T[rozm=r];} T operator[](int i){return *(wsk+i);}... int main(void){ } wektor<double> a; wektor<int> b; wektor<wektor<int> > c;