dr inż. Paweł Myszkowski Politechnika Białostocka Wydział Elektryczny Elektronika i Telekomunikacja, semestr II, studia stacjonarne I stopnia Rok akademicki 2014/2015 Wykład nr 8 (22.04.2015)
Plan prezentacji: instrukcje wejścia/wyjścia w C/C++ wskaźniki i ich zastosowanie dynamiczny przydział pamięci w C/C++
Instrukcje wejścia/wyjścia w C/C++ standardowe wyjście ekran, okno konsoli standardowe wejście - klawiatura instrukcje wejścia/wyjścia w języku C obsługa znaków obsługa łańcuchów znaków wejście i wyjście sformatowane instrukcje wejścia/wyjścia w języku C++ strumienie wejście, wyjście, błędy
Instrukcje wejścia/wyjścia w języku C obsługa znaków wyjście putchar() funkcja wyprowadzająca pojedynczy znak na standardowe wyjście składnia: int putchar(const char c); przykład: putchar('a'); putchar('\n'); char znak = '!'; putchar(znak);
Instrukcje wejścia/wyjścia w języku C obsługa znaków wejście getchar() funkcja przechwytująca znak podany na standardowe wejście i zwracająca go jako wynik; (analogicznie działa funkcja getch()) składnia: int getchar(void); przykład: char znak_z_klawiatury; znak_z_klawiatury = getchar();
Instrukcje wejścia/wyjścia w języku C obsługa łańcuchów znaków wyjście puts() funkcja wyprowadzająca łańcuch znaków na standardowe wyjście, dołączając po nim znak końca wiersza ('\n') składnia: int puts(const char *s); przykład: puts("oto komunikat jednoliniowy"); char napis[] = "A to inny komunikat"; puts(napis); //poprawna deklaracja
Instrukcje wejścia/wyjścia w języku C obsługa łańcuchów znaków wejście gets() funkcja przechwytująca łańcuch znaków podany na standardowe wejście; po odczytaniu znaku końca wiersza, zamienia go na znak '\0' składnia: char* gets(char *s); przykład: char wczytany_napis[50]; gets(wczytany_napis);
Instrukcje wejścia/wyjścia w języku C wyjście sformatowane printf() funkcja o zmiennej liczbie parametrów, wyświetlająca tekst na ekranie; gdy w łańcuchu sterującym znajduje się sekwencja %znak, w to miejsce trafia wartość kolejnego parametru. składnia: printf("łańcuch sterujący", param1, param2, ); przykłady: printf("oto różne sposoby wywołania funkcji: \n"); printf("średnia = %d \n", suma/n); printf("pierwiastek = %f \n", sqrt(suma));
Instrukcje wejścia/wyjścia w języku C składnia specyfikatora formatu - %znak specyfikator = %[znacznik][szerokość][.precyzja][modyfikator]typ [znacznik] "+" przed liczbą pojawi się jej znak "-" wyrównanie wyświetlanych znaków do lewej strony " " (spacja) przed liczbą pojawią się spacje "0" przed liczbą pojawią się dodatkowe zera "#" przed liczbą ósemkową pojawi się dodatkowe zero (0), a przed szesnastkową " 0x" [szerokość] określa minimalną liczbę wyświetlanych znaków; jeśli znaków jest mniej z lewej strony pojawią się spacje, jeśli więcej ograniczenie szerokości jest ignorowane
Instrukcje wejścia/wyjścia w języku C składnia specyfikatora formatu - %znak [.precyzja] typ określa liczbę cyfr znaczących po kropce dziesiętnej określa rodzaj i typ przekazywanego argumentu d, i liczba całkowita dziesiętna ze znakiem u liczba całkowita dziesiętna bez znaku x, X liczba całkowita szesnastkowa bez znaku o liczba całkowita ósemkowa bez znaku f liczba rzeczywista w postaci [-]ddd.ddd e, E liczba rzeczywista w formacie wykładniczym g liczba rzeczywista (wybór formatu zależy od precyzji) s łańcuch znaków c pojedynczy znak
Instrukcje wejścia/wyjścia w języku C składnia specyfikatora formatu - %znak [modyfikator] modyfikuje podstawowy typ określony przez znak typu h hh l ll L dla specyfikatora całkowitego oznacza short int (%hd) lub unsigned short int (%hu) dla specyfikatora całkowitego oznacza signed char (%hhd) lub unsigned char (%hhu) dla specyfikatora całkowitego oznacza long int (%ld) lub unsigned long int (%lu) dla specyfikatora całkowitego oznacza long long int (%lld) lub unsigned long long int (%llu) oznacza wartość rzeczywistą typu long double
Instrukcje wejścia/wyjścia w języku C wyjście sformatowane printf() uwagi specyfikator wpływa jedynie na wyświetlanie danej wartości, a nie na sposób jej przechowywania w pamięci komputera aby wyświetlić na ekranie znak '%', w łańcuchu sterującym wpisz %% aby wyświetlić na ekranie znak '\', w łańcuchu sterującym wpisz \\ znaki sterujące (przypomnienie): \t tabulator \n przejście do nowego wiersza \r powrót na początek bieżącego wiersza \a alarm (sygnał dźwiękowy)
Instrukcje wejścia/wyjścia w języku C wyjście sformatowane printf() przykłady float pipi = 3.14; printf("%010.1f",pipi); 00000003.1 printf("%+1.6f",pipi); +3.140000 printf("%.4e",pipi); 3.1400e+000 int liczba = 21; printf("%#x",liczba); 0x15 printf("%#o",liczba); 025
Instrukcje wejścia/wyjścia w języku C wejście sformatowane scanf() funkcja o zmiennej liczbie parametrów, pobierająca wartości z klawiatury; każda sekwencja %znak w łańcuchu sterującym oznacza wartość, która zostanie pobrana i trafi do zmiennej, której adres jest kolejnym parametrem. składnia: scanf("łańcuch sterujący", adr_par1, adr_par2, ); przykład: int liczba; char znaki[50]; printf("podaj liczbę całkowitą i łańcuch znaków"); scanf("%d %s", &liczba, znaki);
Instrukcje wejścia/wyjścia w języku C składnia specyfikatora formatu - %znak specyfikator = %[szerokość][modyfikator]typ [szerokość] określa, ile znaków zostanie przeczytanych typ określa rodzaj i typ argumentu d, D liczba całkowita dziesiętna (typ int lub long) o, O liczba całkowita ósemkowa (typ int lub long) x, X liczba całkowita szesnastkowa (typ int lub long) i, I liczba całkowita (różne systemy) (typ int lub long) u, U liczba całkowita dziesiętna bez znaku, typ unsigned (int lub long)
Instrukcje wejścia/wyjścia w języku C składnia specyfikatora formatu - %znak f, e, E liczba rzeczywista, typ float g, G liczba rzeczywista, typ float s łańcuch znaków c pojedynczy znak, typ char [modyfikator] zmienia podstawowy typ, określony przez znak typu l L h zmienia wszystkie typy całkowite na ich długie wersje; zastosowany do znaków typu f, e, E, g,g zmienia typ na double zastosowany do znaków typu f, e, E, g,g zmienia typ na long double zmienia typy całkowite na short
Instrukcje wejścia/wyjścia w języku C wejście sformatowane scanf() uwagi parametry, do których wczytane zostaną wartości, muszą być przekazane w formie adresów dlatego wczytując liczby lub pojedyncze znaki, przed parametrem dodajemy operator pobrania adresu & wczytywanie łańcucha znaków nie wymaga tego operatora, ponieważ nazwa tablicy jest adresem jej pierwszego elementu podczas wczytywania ignorowane są tzw. białe znaki (spacja, tabulator, enter)
Instrukcje wejścia/wyjścia w języku C++ uwagi ogólne operacje wejścia/wyjścia w C++ oparte zostały na strumieniach strumień = transfer danych od źródła do ujścia obsługa strumieni zrealizowana jest na zasadzie klas i zdefiniowana w bibliotece iostream #include <iostream> //bez.h w nazwie strumienie w C++ cout (Console OUTput) związany ze standardowym wyjściem (ekran) cin (Console INput) związany ze standardowym wejściem (klawiatura) cerr (Console ERRor) i clog (Console LOGger) związane ze standardowym wyjściem diagnostycznym niebuforowany i buforowany
Instrukcje wejścia/wyjścia w języku C++ przestrzeń nazw pełna postać odwołania do strumieni wyjścia i wejścia to std::cout i std::cin std:: oznacza, że instrukcje pochodzą z przestrzeni nazw std, zawartej w bibliotece standardowej aby skrócić ścieżkę dostępu, umieszczamy w sekcji nagłówkowej dyrektywę: using namespace std; operatory przekierowania strumieni << - operator wysyłający dane do strumienia >> - operator odbierający dane ze strumienia endl przejście do nowego wiersza, odpowiednik "\n" z języka C
Instrukcje wejścia/wyjścia w języku C++ wyświetlanie danych ogólne zasady liczby całkowite wyświetlane w systemie dziesiętnym zmienne typów char i unsigned char wyświetlane jako pojedyncze znaki liczby zmiennoprzecinkowe wyświetlane z dokładnością do 6 cyfr wskaźniki wyświetlane są w systemie szesnastkowym zmienne typu char* wyświetlane jako łańcuchy znaków wczytywanie danych ogólne zasady białe znaki (spacja, tabulator, enter) są ignorowane liczby wczytywane w systemie dziesiętnym liczby wczytywane są do napotkania nie-cyfry łańcuchy znaków wczytywane są do pierwszego białego znaku
Instrukcje wejścia/wyjścia w języku C++ przykłady int a = 21; float b = 3.14159; char napis[20] = "Wynik"; cout << napis << endl; Na ekranie: Wynik cout << napis << a<< " " << b << endl; Na ekranie: Wynik21 3.14159 cout << napis << ": " << a << "*" << b << "=" << (a*b) << endl; Na ekranie: Wynik: 21*3.14159=65.97339
Instrukcje wejścia/wyjścia w języku C++ przykłady int a, b; float c; char napis[20]; cin >> a; cin >> a >> b; cin >> a >> c; cin >> napis; //wczyta jedną liczbę całkowitą //wczyta dwie liczby całkowite //wczyta liczbę całkowitą i liczbę rzeczywistą //wczyta łańcuch znaków
Instrukcje wejścia/wyjścia w języku C++ manipulatory specjalne wartości, które po umieszczeniu w strumieniu zmieniają sposób formatowania danych działają trwale (oprócz setw), czyli do użycia innego manipulatora zmiana systemu liczbowego przy wyświetlaniu/wczytywaniu hex system szesnastkowy dec system dziesiętny (domyślnie) oct system ósemkowy zmiana notacji fixed notacja dziesiętna scientific notacja wykładnicza (naukowa)
Instrukcje wejścia/wyjścia w języku C++ wyświetlanie kropki dziesiętnej i nieznaczących zer showpoint pokazuje kropkę dziesiętną i nieznaczące zera (domyślnie) noshowpoint nie pokazuje kropki i nieznaczących zer wyświetlanie znaku liczby dodatniej showpos wyświetla znak liczby dodatniej noshowpos nie wyświetla znaku liczby dodatniej wyświetlanie podstawy systemu liczbowego showbase wyświetla 0x na początku liczby szesnastkowej oraz 0 na początku liczby ósemkowej noshowbase nie wyświetla podstawy systemu
Instrukcje wejścia/wyjścia w języku C++ przykłady int x = 10, y = 100; cout << x << " " << hex << x << " " << oct << x << endl; 10 A 12 cout << y << endl; 144 //nadal aktywny format ósemkowy float a = 21; cout << showpoint << a << " " << noshowpoint << a; 21.0000 21 cout << showpos << a << " " << noshowpos << a; +21 21 cout << hex << a << " " << showbase << a; 15 0x15 float a = 314.159; cout << fixed << a << endl; 314.159 cout << scientific << a << endl; 3.14159e+002
Instrukcje wejścia/wyjścia w języku C++ manipulatory z biblioteki <iomanip> setprecision(int) określa precyzję wyświetlania liczb zmiennoprzecinkowych dla fixed ilość miejsc po kropce dla scientific dokładność mantysy setw(int) ustawia szerokość wyświetlania liczb lub wczytywania tekstów (działa tylko w najbliższej instrukcji wejścia/wyjścia) setfill(char) ustawia znak wypełnienia cout << setw(10) << setfill('%') << 121; %%%%%%%121
Wskaźniki i ich zastosowanie W języku C/C++ mogą istnieć zmienne zawierające adres jakiegoś obszaru w pamięci (zmienne wskaźnikowe)
Wskaźniki i ich zastosowanie Cztery domeny zastosowania wskaźników: tworzenie i przetwarzanie dynamicznych struktur danych ulepszone zarządzanie blokami pamięci, łańcuchami i tablicami przekazywanie parametrów do funkcji tak, aby mogły w funkcji ulec zmianie dostęp do specjalnych komórek pamięci
Wskaźniki i ich zastosowanie Deklarowanie zmiennych wskaźnikowych: char *wsk_znak; //wskaźnik na znak int *wsk_lcalk; //wskaźnik na liczbę całkowitą double *wsk_lrzecz; //wskaźnik na liczbę rzeczywistą char *tab_wsk[10]; //10-elem. tablica wskaźników na char char (*wsk_tab)[10]; //wskaźnik na tablicę 10 znaków int **wsk_wsk_lcalk; //wskaźnik na wskaźnik na typ int
Wskaźniki i ich zastosowanie Odwołanie do zmiennych char znak = 'a'; wsk_znak = &znak; int liczba = 89; wsk_lcalk = &liczba; double liczba_rz = 3.14; wsk_lrzecz = &liczba_rz; Na etapie deklaracji: int* wsk = &liczba; *wsk_znak = 'b'; //równoważne znak = 'b'; *wsk_lcalk = 1924; //równoważne liczba = 1924; *wsk_lrzecz = 2.71; //równoważne liczba_rz = 2.71;
Wskaźniki i ich zastosowanie Arytmetyka wskaźników: dodawanie i odejmowanie od nich liczb naturalnych odejmowanie dwóch wskaźników wskazujących na tę samą tablicę porównywanie wskaźników (operatory relacyjne) Obsługa tablic za pomocą wskaźników int tab[20]; tab[9] = 10; *(tab+9) = 10; //deklaracja tablicy //odwołanie za pomocą typowego operatora //równoważne odwołanie za pomocą wskaźnika
Wskaźniki i ich zastosowanie Obsługa tablic wielowymiarowych za pomocą wskaźników int tab[2][4]; //deklaracja tablicy dwuwymiarowej Dostępne są różne sposoby odwołań: tab[1][2] = 100; //odwołanie za pomocą typowych operatorów *(tab+6) = 100; //przesunięcie względem początku tablicy *(*(tab+1)+2) = 100; //przesunięcie względem wskaźnika drugiego wiersza 0,0 0,1 0,2 0,3 1,0 1,1 1,2 1,3 +6 +2 X pamięć operacyjna
Dynamiczny przydział pamięci w C/C++ pamięć w sposób dynamiczny przydzielamy wtedy, gdy rozmiar tablicy nie jest ustalony podczas kompilacji, a dopiero później Pamięć dostępna dla programu obszary: miejsce na kod programu miejsce na dane statyczne (stałe i zmienne globalne) stos (STACK) miejsce na dane automatyczne (zmienne lokalne funkcji) sterta (HEAP) miejsce na dane dynamiczne (pamięć przydzielana i zwalniana przez użytkownika)
Dynamiczny przydział pamięci w C Przydzielanie pamięci: calloc() przydziela pamięć dla tablicy malloc() przydziela pamięć dla zmiennej (ogólnie) Zwalnianie pamięci free() zwalnia blok pamięci przydzielony dynamicznie Zmiana rozmiaru przydzielonej pamięci realloc() zwalnia częściowo przydzieloną wcześniej pamięć i przydziela zmiennej nowy obszar pamięci, o innej długości Pamięć nie jest automatycznie zwalniana w trakcie działania programu, a dopiero po jego zakończeniu!
Dynamiczny przydział pamięci w C Przydzielenie bloku pamięci dla tablicy: void* calloc(int n, int rozmiar); przydziela blok pamięci o rozmiarze n*rozmiar (specjalnie dla n-elementowej tablicy) i zwraca wskaźnik do tego bloku w przypadku błędu zwraca NULL (wskaźnik pusty) przydzielona pamięć jest inicjowana bitowo zerami Przydzielenie bloku pamięci dla zmiennej (ogólnie): void* malloc(int rozmiar); przydziela blok pamięci o rozmiarze określonym parametrem rozmiar i zwraca wskaźnik do tego bloku w przypadku błędu zwraca NULL (wskaźnik pusty) przydzielona pamięć nie jest inicjowana
Dynamiczny przydział pamięci w C Zwolnienie pamięci: void* free(void *wskaznik); zwalnia blok pamięci wskazywany przez wskaznik wartość zmiennej wskaznik musi być wynikiem wcześniejszego użycia funkcji malloc() lub calloc() Zmiana rozmiaru przydzielonej pamięci: void* realloc(void* wskaznik, int nowy_rozmiar); zmienia rozmiar przydzielonego wcześniej bloku pamięci, wskazywanego przez wskaznik, do rozmiaru określonego przez parametr nowy_rozmiar bajty poprzednio zajęte przez zmienną nie ulegają zmianie w przypadku przydziału większego obszaru pamięci
Dynamiczny przydział pamięci w C przykład 1 float *liczba, *tablica; int n; liczba = (float*) malloc(sizeof(float)); //przydział pamięci pojedynczej zmiennej printf("podaj ilość elementów tablicy: \n"); scanf("%d",&n); rzutowanie na odpowiedni typ rzutowanie na odpowiedni typ tablica = (float*) calloc(n,sizeof(float)); //przydział pamięci dla tablicy if ((liczba == NULL) (tablica == NULL)) //kontrola błędów przydziału pamięci { printf("nie przydzielono pamięci!"); exit (-1); }}
Dynamiczny przydział pamięci w C przykład 1 *liczba = 21; //przypisanie wartości z operatorem wyłuskiwania for (i=0; i<n; i++) { printf("podaj %d element tablicy: \n", i+1); scanf("%f",(tab+i)); //nazwa tablicy jest adresem, i jest przesunięciem } free(liczba); free(tablica); //zwolnienie pamięci zmiennej //zwolnienie pamięci tablicy
Dynamiczny przydział pamięci w C przykład 2 Macierz trójkątna o boku 4 const int R=4; int i; int **tab; int* int* int* int int int int int int int int int tab = (int**) calloc(r, sizeof(int*); for (i=0;i<r;i++) tab[i] = (int*) calloc(r-i, sizeof(int); int* int for (i=0;i<r;i++) for (j=0;j<r-i-1;j++) *(*(tab+i)+j) = i+j;
Dynamiczny przydział pamięci w C++ Przydzielanie pamięci: new operator przydziału pamięci <wskaźnik> = new <typ> [parametry]; Zwalnianie pamięci delete operator zwolnienia pamięci delete [parametry]<wskaźnik>; int *wskaznik; wskaznik = new int; *wskaznik = 1294; delete wskaznik; int ile, *tablica; tablica = new int[ile] delete []tablica;
Dziękuję za uwagę. KOLOKWIUM nr 1: 29 kwietnia 2015 AULA 23C, Wydział Informatyki Zapraszam!